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  }