github.com/koko1123/flow-go-1@v0.29.6/module/buffer/backend_test.go (about)

     1  package buffer
     2  
     3  import (
     4  	"math/rand"
     5  	"testing"
     6  
     7  	"github.com/stretchr/testify/suite"
     8  
     9  	"github.com/koko1123/flow-go-1/model/flow"
    10  	"github.com/koko1123/flow-go-1/utils/unittest"
    11  )
    12  
    13  type BackendSuite struct {
    14  	suite.Suite
    15  	backend *backend
    16  }
    17  
    18  func TestBackendSuite(t *testing.T) {
    19  	suite.Run(t, new(BackendSuite))
    20  }
    21  
    22  func (suite *BackendSuite) SetupTest() {
    23  	suite.backend = newBackend()
    24  }
    25  
    26  func (suite *BackendSuite) Item() *item {
    27  	parent := unittest.BlockHeaderFixture()
    28  	return suite.ItemWithParent(parent)
    29  }
    30  
    31  func (suite *BackendSuite) ItemWithParent(parent *flow.Header) *item {
    32  	header := unittest.BlockHeaderWithParentFixture(parent)
    33  	return &item{
    34  		header:   header,
    35  		payload:  unittest.IdentifierFixture(),
    36  		originID: unittest.IdentifierFixture(),
    37  	}
    38  }
    39  
    40  func (suite *BackendSuite) Add(item *item) {
    41  	suite.backend.add(item.originID, item.header, item.payload)
    42  }
    43  
    44  func (suite *BackendSuite) TestAdd() {
    45  	expected := suite.Item()
    46  	suite.backend.add(expected.originID, expected.header, expected.payload)
    47  
    48  	actual, ok := suite.backend.byID(expected.header.ID())
    49  	suite.Assert().True(ok)
    50  	suite.Assert().Equal(expected, actual)
    51  
    52  	byParent, ok := suite.backend.byParentID(expected.header.ParentID)
    53  	suite.Assert().True(ok)
    54  	suite.Assert().Len(byParent, 1)
    55  	suite.Assert().Equal(expected, byParent[0])
    56  }
    57  
    58  func (suite *BackendSuite) TestChildIndexing() {
    59  
    60  	parent := suite.Item()
    61  	child1 := suite.ItemWithParent(parent.header)
    62  	child2 := suite.ItemWithParent(parent.header)
    63  	grandchild := suite.ItemWithParent(child1.header)
    64  	unrelated := suite.Item()
    65  
    66  	suite.Add(child1)
    67  	suite.Add(child2)
    68  	suite.Add(grandchild)
    69  	suite.Add(unrelated)
    70  
    71  	suite.Run("retrieve by parent ID", func() {
    72  		byParent, ok := suite.backend.byParentID(parent.header.ID())
    73  		suite.Assert().True(ok)
    74  		// should only include direct children
    75  		suite.Assert().Len(byParent, 2)
    76  		suite.Assert().Contains(byParent, child1)
    77  		suite.Assert().Contains(byParent, child2)
    78  	})
    79  
    80  	suite.Run("drop for parent ID", func() {
    81  		suite.backend.dropForParent(parent.header.ID())
    82  
    83  		// should only drop direct children
    84  		_, exists := suite.backend.byID(child1.header.ID())
    85  		suite.Assert().False(exists)
    86  		_, exists = suite.backend.byID(child2.header.ID())
    87  		suite.Assert().False(exists)
    88  
    89  		// grandchildren should be unaffected
    90  		_, exists = suite.backend.byParentID(child1.header.ID())
    91  		suite.Assert().True(exists)
    92  		_, exists = suite.backend.byID(grandchild.header.ID())
    93  		suite.Assert().True(exists)
    94  
    95  		// nothing else should be affected
    96  		_, exists = suite.backend.byID(unrelated.header.ID())
    97  		suite.Assert().True(exists)
    98  	})
    99  }
   100  
   101  func (suite *BackendSuite) TestPruneByView() {
   102  
   103  	const N = 100 // number of items we're testing with
   104  	items := make([]*item, 0, N)
   105  
   106  	// build a pending buffer
   107  	for i := 0; i < N; i++ {
   108  
   109  		// 10% of the time, add a new unrelated pending block
   110  		if i%10 == 0 {
   111  			item := suite.Item()
   112  			suite.Add(item)
   113  			items = append(items, item)
   114  			continue
   115  		}
   116  
   117  		// 90% of the time, build on an existing block
   118  		if i%2 == 1 {
   119  			parent := items[rand.Intn(len(items))]
   120  			item := suite.ItemWithParent(parent.header)
   121  			suite.Add(item)
   122  			items = append(items, item)
   123  		}
   124  	}
   125  
   126  	// pick a height to prune that's guaranteed to prune at least one item
   127  	pruneAt := items[rand.Intn(len(items))].header.View
   128  	suite.backend.pruneByView(pruneAt)
   129  
   130  	for _, item := range items {
   131  		view := item.header.View
   132  		id := item.header.ID()
   133  		parentID := item.header.ParentID
   134  
   135  		// check that items below the prune view were removed
   136  		if view <= pruneAt {
   137  			_, exists := suite.backend.byID(id)
   138  			suite.Assert().False(exists)
   139  			_, exists = suite.backend.byParentID(parentID)
   140  			suite.Assert().False(exists)
   141  		}
   142  
   143  		// check that other items were not removed
   144  		if view > item.header.View {
   145  			_, exists := suite.backend.byID(id)
   146  			suite.Assert().True(exists)
   147  			_, exists = suite.backend.byParentID(parentID)
   148  			suite.Assert().True(exists)
   149  		}
   150  	}
   151  }