github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/model/flow/factory/cluster_list_test.go (about) 1 package factory_test 2 3 import ( 4 "testing" 5 6 "github.com/stretchr/testify/require" 7 8 "github.com/onflow/flow-go/model/flow" 9 "github.com/onflow/flow-go/model/flow/factory" 10 "github.com/onflow/flow-go/utils/unittest" 11 ) 12 13 // TestNewClusterList ensures that implementation enforces the following protocol rules in case they are violated: 14 // 15 // (a) input `collectors` only contains collector nodes with positive weight 16 // (b) collectors have unique node IDs 17 // (c) each collector is assigned exactly to one cluster and is only listed once within that cluster 18 // (d) cluster contains at least one collector (i.e. is not empty) 19 // (e) cluster is composed of known nodes, i.e. for each nodeID in `assignments` an IdentitySkeleton is given in `collectors` 20 // (f) cluster assignment lists the nodes in canonical ordering 21 func TestNewClusterList(t *testing.T) { 22 identities := unittest.IdentityListFixture(100, unittest.WithRole(flow.RoleCollection)) 23 24 t.Run("valid inputs", func(t *testing.T) { 25 assignments := unittest.ClusterAssignment(10, identities.ToSkeleton()) 26 _, err := factory.NewClusterList(assignments, identities.ToSkeleton()) 27 require.NoError(t, err) 28 }) 29 t.Run("(a) input `collectors` only contains collector nodes with positive weight", func(t *testing.T) { 30 identities := identities.Copy() 31 identities[0].InitialWeight = 0 32 assignments := unittest.ClusterAssignment(10, identities.ToSkeleton()) 33 _, err := factory.NewClusterList(assignments, identities.ToSkeleton()) 34 require.Error(t, err) 35 }) 36 t.Run("(b) collectors have unique node IDs", func(t *testing.T) { 37 identities := identities.Copy() 38 identities[0].NodeID = identities[1].NodeID 39 assignments := unittest.ClusterAssignment(10, identities.ToSkeleton()) 40 _, err := factory.NewClusterList(assignments, identities.ToSkeleton()) 41 require.Error(t, err) 42 }) 43 t.Run("(c) each collector is assigned exactly to one cluster", func(t *testing.T) { 44 assignments := unittest.ClusterAssignment(10, identities.ToSkeleton()) 45 assignments[1][0] = assignments[0][0] 46 _, err := factory.NewClusterList(assignments, identities.ToSkeleton()) 47 require.Error(t, err) 48 }) 49 t.Run("(c) each collector is only listed once within that cluster", func(t *testing.T) { 50 assignments := unittest.ClusterAssignment(10, identities.ToSkeleton()) 51 assignments[0][0] = assignments[0][1] 52 _, err := factory.NewClusterList(assignments, identities.ToSkeleton()) 53 require.Error(t, err) 54 }) 55 t.Run("(d) cluster contains at least one collector (i.e. is not empty)", func(t *testing.T) { 56 assignments := unittest.ClusterAssignment(10, identities.ToSkeleton()) 57 assignments[0] = flow.IdentifierList{} 58 _, err := factory.NewClusterList(assignments, identities.ToSkeleton()) 59 require.Error(t, err) 60 }) 61 t.Run("(e) cluster is composed of known nodes, i.e. for each nodeID in `assignments` an IdentitySkeleton is given in `collectors` ", func(t *testing.T) { 62 assignments := unittest.ClusterAssignment(10, identities.ToSkeleton()) 63 assignments[0][0] = unittest.IdentifierFixture() 64 _, err := factory.NewClusterList(assignments, identities.ToSkeleton()) 65 require.Error(t, err) 66 }) 67 t.Run("(f) cluster assignment lists the nodes in canonical ordering", func(t *testing.T) { 68 assignments := unittest.ClusterAssignment(10, identities.ToSkeleton()) 69 // sort in non-canonical order 70 assignments[0] = assignments[0].Sort(func(lhs flow.Identifier, rhs flow.Identifier) int { 71 return -flow.IdentifierCanonical(lhs, rhs) 72 }) 73 _, err := factory.NewClusterList(assignments, identities.ToSkeleton()) 74 require.Error(t, err) 75 }) 76 }