@ -658,88 +658,189 @@ type testVal struct {
power int64
}
func TestValSetUpdatesBasicTestsExecute ( t * testing . T ) {
valSetUpdatesBasicTests := [ ] struct {
startVals [ ] testVal
updateVals [ ] testVal
expectedVals [ ] testVal
expError bool
} {
// Operations that should result in error
0 : { // updates leading to overflows
[ ] testVal { { "v1" , 10 } , { "v2" , 10 } } ,
[ ] testVal { { "v1" , math . MaxInt64 } } ,
[ ] testVal { { "v1" , 10 } , { "v2" , 10 } } ,
true } ,
1 : { // duplicate entries in changes
[ ] testVal { { "v1" , 10 } , { "v2" , 10 } } ,
func testValSet ( nVals int , power int64 ) [ ] testVal {
vals := make ( [ ] testVal , nVals )
for i := 0 ; i < nVals ; i ++ {
vals [ i ] = testVal { fmt . Sprintf ( "v%d" , i + 1 ) , power }
}
return vals
}
type valSetErrTestCase struct {
startVals [ ] testVal
updateVals [ ] testVal
}
func executeValSetErrTestCase ( t * testing . T , idx int , tt valSetErrTestCase ) {
// create a new set and apply updates, keeping copies for the checks
valSet := createNewValidatorSet ( tt . startVals )
valSetCopy := valSet . Copy ( )
valList := createNewValidatorList ( tt . updateVals )
valListCopy := validatorListCopy ( valList )
err := valSet . UpdateWithChangeSet ( valList )
// for errors check the validator set has not been changed
assert . Error ( t , err , "test %d" , idx )
assert . Equal ( t , valSet , valSetCopy , "test %v" , idx )
// check the parameter list has not changed
assert . Equal ( t , valList , valListCopy , "test %v" , idx )
}
func TestValSetUpdatesDuplicateEntries ( t * testing . T ) {
testCases := [ ] valSetErrTestCase {
// Duplicate entries in changes
{ // first entry is duplicated change
testValSet ( 2 , 10 ) ,
[ ] testVal { { "v1" , 11 } , { "v1" , 22 } } ,
[ ] testVal { { "v1" , 10 } , { "v2" , 10 } } ,
true } ,
2 : { // duplicate entries in removes
[ ] testVal { { "v1" , 10 } , { "v2" , 10 } } ,
} ,
{ // second entry is duplicated change
testValSet ( 2 , 10 ) ,
[ ] testVal { { "v2" , 11 } , { "v2" , 22 } } ,
} ,
{ // change duplicates are separated by a valid change
testValSet ( 2 , 10 ) ,
[ ] testVal { { "v1" , 11 } , { "v2" , 22 } , { "v1" , 12 } } ,
} ,
{ // change duplicates are separated by a valid change
testValSet ( 3 , 10 ) ,
[ ] testVal { { "v1" , 11 } , { "v3" , 22 } , { "v1" , 12 } } ,
} ,
// Duplicate entries in remove
{ // first entry is duplicated remove
testValSet ( 2 , 10 ) ,
[ ] testVal { { "v1" , 0 } , { "v1" , 0 } } ,
[ ] testVal { { "v1" , 10 } , { "v2" , 10 } } ,
true } ,
3 : { // duplicate entries in removes + changes
[ ] testVal { { "v1" , 10 } , { "v2" , 10 } } ,
} ,
{ // second entry is duplicated remove
testValSet ( 2 , 10 ) ,
[ ] testVal { { "v2" , 0 } , { "v2" , 0 } } ,
} ,
{ // remove duplicates are separated by a valid remove
testValSet ( 2 , 10 ) ,
[ ] testVal { { "v1" , 0 } , { "v2" , 0 } , { "v1" , 0 } } ,
} ,
{ // remove duplicates are separated by a valid remove
testValSet ( 3 , 10 ) ,
[ ] testVal { { "v1" , 0 } , { "v3" , 0 } , { "v1" , 0 } } ,
} ,
{ // remove and update same val
testValSet ( 2 , 10 ) ,
[ ] testVal { { "v1" , 0 } , { "v2" , 20 } , { "v1" , 30 } } ,
} ,
{ // duplicate entries in removes + changes
testValSet ( 2 , 10 ) ,
[ ] testVal { { "v1" , 0 } , { "v2" , 20 } , { "v2" , 30 } , { "v1" , 0 } } ,
[ ] testVal { { "v1" , 10 } , { "v2" , 10 } } ,
true } ,
4 : { // update with negative voting power
[ ] testVal { { "v1" , 10 } , { "v2" , 10 } } ,
} ,
{ // duplicate entries in removes + changes
testValSet ( 3 , 10 ) ,
[ ] testVal { { "v1" , 0 } , { "v3" , 5 } , { "v2" , 20 } , { "v2" , 30 } , { "v1" , 0 } } ,
} ,
}
for i , tt := range testCases {
executeValSetErrTestCase ( t , i , tt )
}
}
func TestValSetUpdatesOverflows ( t * testing . T ) {
maxVP := MaxTotalVotingPower
testCases := [ ] valSetErrTestCase {
{ // single update leading to overflow
testValSet ( 2 , 10 ) ,
[ ] testVal { { "v1" , math . MaxInt64 } } ,
} ,
{ // single update leading to overflow
testValSet ( 2 , 10 ) ,
[ ] testVal { { "v2" , math . MaxInt64 } } ,
} ,
{ // add validator leading to exceed Max
testValSet ( 1 , maxVP - 1 ) ,
[ ] testVal { { "v2" , 5 } } ,
} ,
{ // add validator leading to exceed Max
testValSet ( 2 , maxVP / 3 ) ,
[ ] testVal { { "v3" , maxVP / 2 } } ,
} ,
}
for i , tt := range testCases {
executeValSetErrTestCase ( t , i , tt )
}
}
func TestValSetUpdatesOtherErrors ( t * testing . T ) {
testCases := [ ] valSetErrTestCase {
{ // update with negative voting power
testValSet ( 2 , 10 ) ,
[ ] testVal { { "v1" , - 123 } } ,
[ ] testVal { { "v1" , 10 } , { "v2" , 10 } } ,
true } ,
5 : { // delete non existing validator
[ ] testVal { { "v1" , 10 } , { "v2" , 10 } } ,
} ,
{ // update with negative voting power
testValSet ( 2 , 10 ) ,
[ ] testVal { { "v2" , - 123 } } ,
} ,
{ // remove non-existing validator
testValSet ( 2 , 10 ) ,
[ ] testVal { { "v3" , 0 } } ,
[ ] testVal { { "v1" , 10 } , { "v2" , 10 } } ,
true } ,
} ,
{ // delete all validators
[ ] testVal { { "v1" , 10 } , { "v2" , 20 } , { "v3" , 30 } } ,
[ ] testVal { { "v1" , 0 } , { "v2" , 0 } , { "v3" , 0 } } ,
} ,
}
for i , tt := range testCases {
executeValSetErrTestCase ( t , i , tt )
}
}
// Operations that should be successful
6 : { // no changes
[ ] testVal { { "v1" , 10 } , { "v2" , 10 } } ,
func TestValSetUpdatesBasicTestsExecute ( t * testing . T ) {
valSetUpdatesBasicTests := [ ] struct {
startVals [ ] testVal
updateVals [ ] testVal
expectedVals [ ] testVal
} {
{ // no changes
testValSet ( 2 , 10 ) ,
[ ] testVal { } ,
[ ] testVal { { "v1" , 10 } , { "v2" , 10 } } ,
false } ,
7 : { // voting power changes
[ ] testVal { { "v1" , 10 } , { "v2" , 10 } } ,
testValSet ( 2 , 10 ) ,
} ,
{ // voting power changes
testValSet ( 2 , 10 ) ,
[ ] testVal { { "v1" , 11 } , { "v2" , 22 } } ,
[ ] testVal { { "v1" , 11 } , { "v2" , 22 } } ,
false } ,
8 : { // add new validators
} ,
{ // add new validators
[ ] testVal { { "v1" , 10 } , { "v2" , 20 } } ,
[ ] testVal { { "v3" , 30 } , { "v4" , 40 } } ,
[ ] testVal { { "v1" , 10 } , { "v2" , 20 } , { "v3" , 30 } , { "v4" , 40 } } ,
false } ,
9 : { // delete validators
} ,
{ // add new validator to middle
[ ] testVal { { "v1" , 10 } , { "v3" , 20 } } ,
[ ] testVal { { "v2" , 30 } } ,
[ ] testVal { { "v1" , 10 } , { "v2" , 30 } , { "v3" , 20 } } ,
} ,
{ // add new validator to beginning
[ ] testVal { { "v2" , 10 } , { "v3" , 20 } } ,
[ ] testVal { { "v1" , 30 } } ,
[ ] testVal { { "v1" , 30 } , { "v2" , 10 } , { "v3" , 20 } } ,
} ,
{ // delete validators
[ ] testVal { { "v1" , 10 } , { "v2" , 20 } , { "v3" , 30 } } ,
[ ] testVal { { "v2" , 0 } } ,
[ ] testVal { { "v1" , 10 } , { "v3" , 30 } } ,
false } ,
10 : { // delete all validators
[ ] testVal { { "v1" , 10 } , { "v2" , 20 } , { "v3" , 30 } } ,
[ ] testVal { { "v1" , 0 } , { "v2" , 0 } , { "v3" , 0 } } ,
[ ] testVal { { "v1" , 10 } , { "v2" , 20 } , { "v3" , 30 } } ,
true } ,
} ,
}
for i , tt := range valSetUpdatesBasicTests {
// create a new set and apply updates, keeping copies for the checks
valSet := createNewValidatorSet ( tt . startVals )
valSetCopy := valSet . Copy ( )
valList := createNewValidatorList ( tt . updateVals )
valListCopy := validatorListCopy ( valList )
err := valSet . UpdateWithChangeSet ( valList )
assert . NoError ( t , err , "test %d" , i )
if tt . expError {
// for errors check the validator set has not been changed
assert . Error ( t , err , "test %d" , i )
assert . Equal ( t , valSet , valSetCopy , "test %v" , i )
} else {
assert . NoError ( t , err , "test %d" , i )
}
// check the parameter list has not changed
assert . Equal ( t , valList , valListCopy , "test %v" , i )