github.com/koko1123/flow-go-1@v0.29.6/module/forest/leveled_forrest_test.go (about) 1 package forest 2 3 import ( 4 "strconv" 5 "testing" 6 7 "github.com/stretchr/testify/assert" 8 9 "github.com/koko1123/flow-go-1/model/flow" 10 "github.com/koko1123/flow-go-1/module/forest/mock" 11 ) 12 13 // ~~~~~~~~~~~~~~~~~~~~~ Mock implementation for Vertex ~~~~~~~~~~~~~~~~~~~~~ // 14 type VertexMock struct { 15 id flow.Identifier 16 level uint64 17 18 parentId flow.Identifier 19 parentLevel uint64 20 } 21 22 func (v *VertexMock) VertexID() flow.Identifier { return v.id } 23 func (v *VertexMock) Level() uint64 { return v.level } 24 func (v *VertexMock) Parent() (flow.Identifier, uint64) { return v.parentId, v.parentLevel } 25 26 func NewVertexMock(vertexId string, vertexLevel uint64, parentId string, parentLevel uint64) *mock.Vertex { 27 v := &mock.Vertex{} 28 v.On("VertexID").Return(string2Identifyer(vertexId)) 29 v.On("Level").Return(vertexLevel) 30 v.On("Parent").Return(string2Identifyer(parentId), parentLevel) 31 return v 32 } 33 34 var TestVertices = map[string]*mock.Vertex{ 35 "A": NewVertexMock("A", 3, "Genesis", 0), 36 "B": NewVertexMock("B", 1, "Genesis", 0), 37 "C": NewVertexMock("C", 2, "B", 1), 38 "D": NewVertexMock("D", 3, "C", 2), 39 "W": NewVertexMock("W", 4, "Missing1", 3), 40 "X": NewVertexMock("X", 5, "Missing2", 4), 41 "Y": NewVertexMock("Y", 6, "X", 5), 42 "Z": NewVertexMock("Z", 6, "X", 5), 43 } 44 45 // ~~~~~~~~~~~~~~~~~~~~~~~~ Tests for VertexIterator ~~~~~~~~~~~~~~~~~~~~~~~~ // 46 47 // TestVertexIterator tests VertexIterator on non-empty list 48 func TestVertexIterator(t *testing.T) { 49 var vl VertexList 50 for i := 1; i <= 10; i++ { 51 b := VertexMock{level: uint64(i)} 52 c := vertexContainer{vertex: &b} 53 vl = append(vl, &c) 54 } 55 56 i := 0 57 for I := newVertexIterator(vl); I.HasNext(); { 58 assert.Equal(t, vl[i].vertex, I.NextVertex()) 59 i++ 60 } 61 } 62 63 // TestVertexIteratorOnEmpty tests VertexIterator on non-empty and nil lists 64 func TestVertexIteratorOnEmpty(t *testing.T) { 65 I := newVertexIterator(nil) 66 assert.False(t, I.HasNext()) 67 assert.True(t, I.NextVertex() == nil) 68 69 I = newVertexIterator(VertexList{}) 70 assert.False(t, I.HasNext()) 71 assert.True(t, I.NextVertex() == nil) 72 } 73 74 // ~~~~~~~~~~~~~~~~~~~~~~~~ Tests for LevelledForest ~~~~~~~~~~~~~~~~~~~~~~~~ // 75 76 // TestLevelledForest_AddVertex tests that Vertex can be added twice without problems 77 func TestLevelledForest_AddVertex(t *testing.T) { 78 F := NewLevelledForest(0) 79 v := NewVertexMock("A", 3, "Genesis", 0) 80 if err := F.VerifyVertex(v); err != nil { 81 assert.Fail(t, err.Error()) 82 } 83 F.AddVertex(v) 84 assert.True(t, F.HasVertex(string2Identifyer("A"))) 85 86 // Adding Vertex twice should be fine 87 v = NewVertexMock("A", 3, "Genesis", 0) 88 if err := F.VerifyVertex(v); err != nil { 89 assert.Fail(t, err.Error()) 90 } 91 F.AddVertex(v) 92 assert.True(t, F.HasVertex(string2Identifyer("A"))) 93 } 94 95 // TestLevelledForest_AcceptingGenesis checks that Levelled Forest accepts vertices 96 // whose level are at LevelledForest.LowestLevel without requiring the parent. 97 // we test this by having the mock.vertex.Parent() panic 98 func TestLevelledForest_AcceptingGenesis(t *testing.T) { 99 // LevelledForest.LowestLevel on initial conditions 100 F := populateNewForest(t) 101 v1 := &mock.Vertex{} 102 v1.On("VertexID").Return(string2Identifyer("Root-Vertex-A_@Level0")) 103 v1.On("Level").Return(uint64(0)) 104 v1.On("Parent").Return(func() (flow.Identifier, uint64) { panic("Parent() should not have been called") }) 105 assert.NotPanics(t, func() { F.AddVertex(v1) }) 106 107 v2 := &mock.Vertex{} 108 v2.On("VertexID").Return(string2Identifyer("Root-Vertex-B_@Level0")) 109 v2.On("Level").Return(uint64(0)) 110 v2.On("Parent").Return(func() (flow.Identifier, uint64) { panic("Parent() should not have been called") }) 111 assert.NotPanics(t, func() { F.AddVertex(v2) }) 112 assert.NotPanics(t, func() { F.AddVertex(v2) }) 113 114 F = populateNewForest(t) 115 err := F.PruneUpToLevel(8) // LevelledForest.LowestLevel on initial conditions 116 assert.True(t, err == nil) 117 v3 := &mock.Vertex{} 118 v3.On("VertexID").Return(string2Identifyer("Root-Vertex-A_@Level8")) 119 v3.On("Level").Return(uint64(8)) 120 v3.On("Parent").Return(func() (flow.Identifier, uint64) { panic("Parent() should not have been called") }) 121 assert.NotPanics(t, func() { F.AddVertex(v3) }) 122 123 v4 := &mock.Vertex{} 124 v4.On("VertexID").Return(string2Identifyer("Root-Vertex-B_@Level8")) 125 v4.On("Level").Return(uint64(8)) 126 v4.On("Parent").Return(func() (flow.Identifier, uint64) { panic("Parent() should not have been called") }) 127 assert.NotPanics(t, func() { F.AddVertex(v4) }) 128 assert.NotPanics(t, func() { F.AddVertex(v4) }) 129 } 130 131 // TestLevelledForest_VerifyVertex checks that invalid Vertices are detected. 132 // with an ID identical to a known reference BUT whose level is not consistent with the reference 133 func TestLevelledForest_VerifyVertex(t *testing.T) { 134 F := populateNewForest(t) 135 136 // KNOWN vertex but with wrong level number 137 err := F.VerifyVertex(NewVertexMock("D", 10, "C", 2)) 138 assert.True(t, err != nil, err.Error()) 139 140 // KNOWN vertex whose PARENT references a known vertex but with mismatching level 141 err = F.VerifyVertex(NewVertexMock("D", 10, "C", 10)) 142 assert.True(t, err != nil, err.Error()) 143 144 // adding unknown vertex whose PARENT references a known vertex but with mismatching level 145 err = F.VerifyVertex(NewVertexMock("F", 4, "Genesis", 10)) 146 assert.True(t, err != nil, err.Error()) 147 } 148 149 // TestLevelledForest_HasVertex test that vertices as correctly reported as contained in Forest 150 // NOTE: We consider a vertex added only if it has been directly added through the AddVertex method. 151 // Vertices that references bvy known vertices but have not themselves are considered to be not in the tree. 152 func TestLevelledForest_HasVertex(t *testing.T) { 153 F := populateNewForest(t) 154 assert.True(t, F.HasVertex(string2Identifyer("A"))) 155 assert.True(t, F.HasVertex(string2Identifyer("B"))) 156 assert.True(t, F.HasVertex(string2Identifyer("X"))) 157 158 assert.False(t, F.HasVertex(string2Identifyer("Genesis"))) // Genesis block never directly added (only referenced) => unknown 159 assert.False(t, F.HasVertex(string2Identifyer("NotYetAdded"))) // Block never mentioned before 160 } 161 162 // TestLevelledForest_GetChildren tests that children are returned properly 163 func TestLevelledForest_GetChildren(t *testing.T) { 164 F := populateNewForest(t) 165 166 // testing children for Block that is contained in Tree 167 it := F.GetChildren(string2Identifyer("X")) 168 expectedChildren := []*mock.Vertex{ 169 TestVertices["Y"], 170 TestVertices["Z"], 171 } 172 assert.ElementsMatch(t, expectedChildren, children2List(&it)) 173 174 // testing children for referenced Block that is NOT contained in Tree 175 it = F.GetChildren(string2Identifyer("Genesis")) 176 expectedChildren = []*mock.Vertex{ 177 TestVertices["A"], 178 TestVertices["B"], 179 } 180 assert.ElementsMatch(t, expectedChildren, children2List(&it)) 181 182 // testing children for Block that is contained in Tree but no children are known 183 it = F.GetChildren(string2Identifyer("D")) 184 assert.False(t, it.HasNext()) 185 } 186 187 // TestLevelledForest_GetNumberOfChildren tests that children are returned properly 188 func TestLevelledForest_GetNumberOfChildren(t *testing.T) { 189 F := populateNewForest(t) 190 191 // testing children for Block that is contained in Tree 192 assert.Equal(t, 2, F.GetNumberOfChildren(string2Identifyer("X"))) 193 194 // testing children for referenced Block that is NOT contained in Tree 195 assert.Equal(t, 2, F.GetNumberOfChildren(string2Identifyer("Genesis"))) 196 197 // testing children for Block that is contained in Tree but no children are known 198 assert.Equal(t, 0, F.GetNumberOfChildren(string2Identifyer("D"))) 199 } 200 201 // TestLevelledForest_GetVerticesAtLevel tests that Vertex blob is returned properly 202 func TestLevelledForest_GetVerticesAtLevel(t *testing.T) { 203 F := populateNewForest(t) 204 205 // testing vertices for level that are contained in Tree 206 it := F.GetVerticesAtLevel(6) 207 expectedChildren := []*mock.Vertex{ 208 TestVertices["Y"], 209 TestVertices["Z"], 210 } 211 assert.ElementsMatch(t, expectedChildren, children2List(&it)) 212 213 // testing vertices for level that are not in Tree but referenced by vertices in the Tree 214 it = F.GetVerticesAtLevel(0) 215 assert.ElementsMatch(t, []*mock.Vertex{}, children2List(&it)) 216 217 // testing vertices for level with a mixture of referenced but unknown vertices and known vertices 218 it = F.GetVerticesAtLevel(4) 219 expectedChildren = []*mock.Vertex{ 220 TestVertices["W"], 221 } 222 assert.ElementsMatch(t, expectedChildren, children2List(&it)) 223 224 // testing vertices for level that are neither in Tree nor referenced by vertices in the Tree 225 it = F.GetVerticesAtLevel(100000) 226 assert.ElementsMatch(t, []*mock.Vertex{}, children2List(&it)) 227 } 228 229 // TestLevelledForest_GetNumberOfVerticesAtLevel tests that the number of vertices at a specified level is reported correctly. 230 func TestLevelledForest_GetNumberOfVerticesAtLevel(t *testing.T) { 231 F := populateNewForest(t) 232 233 // testing vertices for level that are contained in Tree 234 assert.Equal(t, 2, F.GetNumberOfVerticesAtLevel(6)) 235 236 // testing vertices for level that are not in Tree but referenced by vertices in the Tree 237 assert.Equal(t, 0, F.GetNumberOfVerticesAtLevel(0)) 238 239 // testing vertices for level with a mixture of referenced but unknown vertices and known vertices 240 assert.Equal(t, 1, F.GetNumberOfVerticesAtLevel(4)) 241 242 // testing vertices for level that are neither in Tree nor referenced by vertices in the Tree 243 assert.Equal(t, 0, F.GetNumberOfVerticesAtLevel(100000)) 244 } 245 246 // TestLevelledForest_GetVertex tests that Vertex blob is returned properly 247 func TestLevelledForest_GetVertex(t *testing.T) { 248 F := populateNewForest(t) 249 v, exists := F.GetVertex(string2Identifyer("D")) 250 assert.Equal(t, TestVertices["D"], v) 251 assert.True(t, exists) 252 253 v, exists = F.GetVertex(string2Identifyer("X")) 254 assert.Equal(t, TestVertices["X"], v) 255 assert.True(t, exists) 256 257 v, exists = F.GetVertex(string2Identifyer("Genesis")) 258 assert.Equal(t, (Vertex)(nil), v) 259 assert.False(t, exists) 260 } 261 262 // TestLevelledForest_GetSize tests that GetSize returns valid size when adding and pruning vertices 263 func TestLevelledForest_GetSize(t *testing.T) { 264 F := NewLevelledForest(0) 265 numberOfNodes := uint64(10) 266 parentLevel := uint64(0) 267 for i := uint64(1); i <= numberOfNodes; i++ { 268 vertexId := strconv.FormatUint(i, 10) 269 parentId := strconv.FormatUint(parentLevel, 10) 270 F.AddVertex(NewVertexMock(vertexId, i, parentId, parentLevel)) 271 parentLevel = i 272 } 273 assert.Equal(t, numberOfNodes, F.GetSize()) 274 assert.NoError(t, F.PruneUpToLevel(numberOfNodes/2)) 275 // pruning removes element till some level but not including, that's why if we prune 276 // to numberOfNodes/2 then we actually expect elements with level >= numberOfNodes/2 277 assert.Equal(t, numberOfNodes/2+1, F.GetSize()) 278 assert.NoError(t, F.PruneUpToLevel(numberOfNodes+1)) 279 assert.Equal(t, uint64(0), F.GetSize()) 280 } 281 282 // TestLevelledForest_GetSize_PruningTwice tests that GetSize returns same size when pruned twice to same height 283 func TestLevelledForest_GetSize_PruningTwice(t *testing.T) { 284 F := NewLevelledForest(0) 285 numberOfNodes := uint64(10) 286 parentLevel := uint64(0) 287 for i := uint64(1); i <= numberOfNodes; i++ { 288 vertexId := strconv.FormatUint(i, 10) 289 parentId := strconv.FormatUint(parentLevel, 10) 290 F.AddVertex(NewVertexMock(vertexId, i, parentId, parentLevel)) 291 parentLevel = i 292 } 293 assert.NoError(t, F.PruneUpToLevel(numberOfNodes/2)) 294 size := F.GetSize() 295 296 assert.NoError(t, F.PruneUpToLevel(numberOfNodes/2)) 297 // pruning again with the same level should not change size 298 assert.Equal(t, size, F.GetSize()) 299 } 300 301 // TestLevelledForest_GetSize_DuplicatedNodes tests that GetSize returns valid size when adding duplicated nodes 302 func TestLevelledForest_GetSize_DuplicatedNodes(t *testing.T) { 303 F := NewLevelledForest(0) 304 for _, vertex := range TestVertices { 305 F.AddVertex(vertex) 306 } 307 size := F.GetSize() 308 for _, vertex := range TestVertices { 309 F.AddVertex(vertex) 310 } 311 assert.Equal(t, size, F.GetSize()) 312 } 313 314 // TestLevelledForest_GetVertex tests that Vertex blob is returned properly 315 func TestLevelledForest_PruneAtLevel(t *testing.T) { 316 F := populateNewForest(t) 317 err := F.PruneUpToLevel(1) 318 assert.False(t, err != nil) 319 assert.False(t, F.HasVertex(string2Identifyer("Genesis"))) 320 assert.True(t, F.HasVertex(string2Identifyer("A"))) 321 assert.True(t, F.HasVertex(string2Identifyer("B"))) 322 assert.True(t, F.HasVertex(string2Identifyer("C"))) 323 assert.True(t, F.HasVertex(string2Identifyer("D"))) 324 assert.True(t, F.HasVertex(string2Identifyer("X"))) 325 assert.True(t, F.HasVertex(string2Identifyer("Y"))) 326 assert.True(t, F.HasVertex(string2Identifyer("Z"))) 327 328 err = F.PruneUpToLevel(3) 329 assert.False(t, err != nil) 330 assert.False(t, F.HasVertex(string2Identifyer("Genesis"))) 331 assert.True(t, F.HasVertex(string2Identifyer("A"))) 332 assert.False(t, F.HasVertex(string2Identifyer("B"))) 333 assert.False(t, F.HasVertex(string2Identifyer("C"))) 334 assert.True(t, F.HasVertex(string2Identifyer("D"))) 335 assert.True(t, F.HasVertex(string2Identifyer("X"))) 336 assert.True(t, F.HasVertex(string2Identifyer("Y"))) 337 assert.True(t, F.HasVertex(string2Identifyer("Z"))) 338 339 err = F.PruneUpToLevel(6) 340 assert.False(t, err != nil) 341 assert.False(t, F.HasVertex(string2Identifyer("Genesis"))) 342 assert.False(t, F.HasVertex(string2Identifyer("A"))) 343 assert.False(t, F.HasVertex(string2Identifyer("B"))) 344 assert.False(t, F.HasVertex(string2Identifyer("C"))) 345 assert.False(t, F.HasVertex(string2Identifyer("D"))) 346 assert.False(t, F.HasVertex(string2Identifyer("X"))) 347 assert.True(t, F.HasVertex(string2Identifyer("Y"))) 348 assert.True(t, F.HasVertex(string2Identifyer("Z"))) 349 350 // pruning at same level repeatedly should be fine 351 err = F.PruneUpToLevel(6) 352 assert.False(t, err != nil) 353 assert.True(t, F.HasVertex(string2Identifyer("Y"))) 354 assert.True(t, F.HasVertex(string2Identifyer("Z"))) 355 356 // checking that pruning at lower level than what is already pruned results in error 357 err = F.PruneUpToLevel(5) 358 assert.True(t, err != nil) 359 } 360 361 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ Helper Functions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // 362 363 func populateNewForest(t *testing.T) *LevelledForest { 364 F := NewLevelledForest(0) 365 for _, v := range TestVertices { 366 if err := F.VerifyVertex(v); err != nil { 367 assert.Fail(t, err.Error()) 368 } 369 F.AddVertex(v) 370 } 371 return F 372 } 373 374 func children2List(it *VertexIterator) []*mock.Vertex { 375 l := []*mock.Vertex{} 376 for it.HasNext() { 377 // Vertex interface is implemented by mock.Vertex POINTER! 378 // Hence, the concrete type is *mock.Vertex 379 v := it.NextVertex().(*mock.Vertex) 380 l = append(l, v) 381 } 382 return l 383 } 384 385 func string2Identifyer(s string) flow.Identifier { 386 var identifier flow.Identifier 387 copy(identifier[:], []byte(s)) 388 return identifier 389 }