github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/network/cache/rcvcache_test.go (about)

     1  package netcache_test
     2  
     3  import (
     4  	"fmt"
     5  	"sync"
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/onflow/flow-go/network/message"
    10  
    11  	"github.com/stretchr/testify/assert"
    12  	"github.com/stretchr/testify/require"
    13  	"github.com/stretchr/testify/suite"
    14  
    15  	"github.com/onflow/flow-go/network/channels"
    16  
    17  	"github.com/onflow/crypto/hash"
    18  
    19  	"github.com/onflow/flow-go/module/metrics"
    20  	netcache "github.com/onflow/flow-go/network/cache"
    21  	"github.com/onflow/flow-go/utils/unittest"
    22  )
    23  
    24  type ReceiveCacheTestSuite struct {
    25  	suite.Suite
    26  	c    *netcache.ReceiveCache
    27  	size int
    28  }
    29  
    30  func TestReceiveCacheTestSuite(t *testing.T) {
    31  	suite.Run(t, new(ReceiveCacheTestSuite))
    32  }
    33  
    34  // SetupTest creates a new cache
    35  func (r *ReceiveCacheTestSuite) SetupTest() {
    36  	const size = 10
    37  
    38  	c := netcache.NewHeroReceiveCache(size, unittest.Logger(), metrics.NewNoopCollector())
    39  
    40  	r.c = c
    41  	r.size = size
    42  }
    43  
    44  // TestSingleElementAdd adds a single element to the cache and verifies its existence.
    45  func (r *ReceiveCacheTestSuite) TestSingleElementAdd() {
    46  	eventID, err := message.EventId(channels.Channel("0"), []byte("event-1"))
    47  	require.NoError(r.T(), err)
    48  
    49  	assert.True(r.Suite.T(), r.c.Add(eventID))
    50  	assert.False(r.Suite.T(), r.c.Add(eventID))
    51  
    52  	// same channel but different event should be treated as unseen
    53  	eventID2, err := message.EventId(channels.Channel("0"), []byte("event-2"))
    54  	require.NoError(r.T(), err)
    55  	assert.True(r.Suite.T(), r.c.Add(eventID2))
    56  	assert.False(r.Suite.T(), r.c.Add(eventID2))
    57  
    58  	// same event but different channels should be treated as unseen
    59  	eventID3, err := message.EventId(channels.Channel("1"), []byte("event-2"))
    60  	require.NoError(r.T(), err)
    61  	assert.True(r.Suite.T(), r.c.Add(eventID3))
    62  	assert.False(r.Suite.T(), r.c.Add(eventID3))
    63  }
    64  
    65  // TestNoneExistence evaluates the correctness of cache operation against non-existing element
    66  func (r *ReceiveCacheTestSuite) TestNoneExistence() {
    67  	eventID, err := message.EventId(channels.Channel("1"), []byte("non-existing event"))
    68  	require.NoError(r.T(), err)
    69  
    70  	// adding new event to cache should return true
    71  	assert.True(r.Suite.T(), r.c.Add(eventID))
    72  }
    73  
    74  // TestMultipleElementAdd adds several eventIDs to th cache and evaluates their existence
    75  func (r *ReceiveCacheTestSuite) TestMultipleElementAdd() {
    76  	// creates and populates slice of 10 events
    77  	eventIDs := make([]hash.Hash, 0)
    78  	for i := 0; i < r.size; i++ {
    79  		eventID, err := message.EventId(channels.Channel("1"), []byte(fmt.Sprintf("event-%d", i)))
    80  		require.NoError(r.T(), err)
    81  
    82  		eventIDs = append(eventIDs, eventID)
    83  	}
    84  
    85  	// adding non-existing even id must return true
    86  	wg := sync.WaitGroup{}
    87  	wg.Add(r.size)
    88  	for i := 0; i < r.size; i++ {
    89  		go func(i int) {
    90  			assert.True(r.Suite.T(), r.c.Add(eventIDs[i]))
    91  
    92  			wg.Done()
    93  		}(i)
    94  
    95  	}
    96  
    97  	unittest.RequireReturnsBefore(r.T(), wg.Wait, 100*time.Millisecond, "cannot add events to cache on time")
    98  
    99  	// adding duplicate event id must return false.
   100  	wg.Add(r.size)
   101  	for i := 0; i < r.size; i++ {
   102  		go func(i int) {
   103  			assert.False(r.Suite.T(), r.c.Add(eventIDs[i]))
   104  
   105  			wg.Done()
   106  		}(i)
   107  	}
   108  
   109  	unittest.RequireReturnsBefore(r.T(), wg.Wait, 100*time.Millisecond, "cannot add duplicate events to cache on time")
   110  }
   111  
   112  // TestLRU makes sure that received cache is configured in LRU mode.
   113  func (r *ReceiveCacheTestSuite) TestLRU() {
   114  	eventIDs := make([]hash.Hash, 0)
   115  	total := r.size + 1
   116  	for i := 0; i < total; i++ {
   117  		eventID, err := message.EventId(channels.Channel("1"), []byte(fmt.Sprintf("event-%d", i)))
   118  		require.NoError(r.T(), err)
   119  
   120  		eventIDs = append(eventIDs, eventID)
   121  	}
   122  
   123  	// adding non-existing even id must return true
   124  	for i := 0; i < total; i++ {
   125  		assert.True(r.Suite.T(), r.c.Add(eventIDs[i]))
   126  	}
   127  
   128  	// when adding 11th element, cache goes beyond its size,
   129  	// and 1st element (i.e., index 0) is ejected.
   130  	// Now when trying to add 1st element again, it seems
   131  	// new to cache and replaces 2nd element (at index 1) with it.
   132  	require.True(r.T(), r.c.Add(eventIDs[0]))
   133  
   134  }