github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/network/p2p/scoring/internal/appSpecificScoreCache_test.go (about)

     1  package internal_test
     2  
     3  import (
     4  	"sync"
     5  	"testing"
     6  	"time"
     7  
     8  	"github.com/stretchr/testify/require"
     9  
    10  	"github.com/onflow/flow-go/module/metrics"
    11  	"github.com/onflow/flow-go/network/p2p/scoring/internal"
    12  	"github.com/onflow/flow-go/utils/unittest"
    13  )
    14  
    15  // TestAppSpecificScoreCache tests the functionality of AppSpecificScoreCache;
    16  // specifically, it tests the Add and Get methods.
    17  // It does not test the eviction policy of the cache.
    18  func TestAppSpecificScoreCache(t *testing.T) {
    19  	cache := internal.NewAppSpecificScoreCache(10, unittest.Logger(), metrics.NewNoopCollector())
    20  	require.NotNil(t, cache, "failed to create AppSpecificScoreCache")
    21  
    22  	peerID := unittest.PeerIdFixture(t)
    23  	score := 5.0
    24  	updateTime := time.Now()
    25  
    26  	err := cache.AdjustWithInit(peerID, score, updateTime)
    27  	require.Nil(t, err, "failed to add score to cache")
    28  
    29  	// retrieve score from cache
    30  	retrievedScore, lastUpdated, found := cache.Get(peerID)
    31  	require.True(t, found, "failed to find score in cache")
    32  	require.Equal(t, score, retrievedScore, "retrieved score does not match expected")
    33  	require.Equal(t, updateTime, lastUpdated, "retrieved update time does not match expected")
    34  
    35  	// test cache update
    36  	newScore := 10.0
    37  	err = cache.AdjustWithInit(peerID, newScore, updateTime.Add(time.Minute))
    38  	require.Nil(t, err, "Failed to update score in cache")
    39  
    40  	// retrieve updated score
    41  	updatedScore, updatedTime, found := cache.Get(peerID)
    42  	require.True(t, found, "failed to find updated score in cache")
    43  	require.Equal(t, newScore, updatedScore, "updated score does not match expected")
    44  	require.Equal(t, updateTime.Add(time.Minute), updatedTime, "updated time does not match expected")
    45  }
    46  
    47  // TestAppSpecificScoreCache_Concurrent_Add_Get_Update tests the concurrent functionality of AppSpecificScoreCache;
    48  // specifically, it tests the Add and Get methods under concurrent access.
    49  func TestAppSpecificScoreCache_Concurrent_Add_Get_Update(t *testing.T) {
    50  	cache := internal.NewAppSpecificScoreCache(10, unittest.Logger(), metrics.NewNoopCollector())
    51  	require.NotNil(t, cache, "failed to create AppSpecificScoreCache")
    52  
    53  	peerId1 := unittest.PeerIdFixture(t)
    54  	score1 := 5.0
    55  	lastUpdated1 := time.Now()
    56  
    57  	peerId2 := unittest.PeerIdFixture(t)
    58  	score2 := 10.0
    59  	lastUpdated2 := time.Now().Add(time.Minute)
    60  
    61  	wg := sync.WaitGroup{}
    62  	wg.Add(2)
    63  	go func() {
    64  		defer wg.Done()
    65  		err := cache.AdjustWithInit(peerId1, score1, lastUpdated1)
    66  		require.Nil(t, err, "failed to add score1 to cache")
    67  	}()
    68  
    69  	go func() {
    70  		defer wg.Done()
    71  		err := cache.AdjustWithInit(peerId2, score2, lastUpdated2)
    72  		require.Nil(t, err, "failed to add score2 to cache")
    73  	}()
    74  
    75  	unittest.RequireReturnsBefore(t, wg.Wait, 100*time.Millisecond, "failed to add scores to cache")
    76  
    77  	// retrieve scores concurrently
    78  	wg.Add(2)
    79  	go func() {
    80  		defer wg.Done()
    81  		retrievedScore, lastUpdated, found := cache.Get(peerId1)
    82  		require.True(t, found, "failed to find score1 in cache")
    83  		require.Equal(t, score1, retrievedScore, "retrieved score1 does not match expected")
    84  		require.Equal(t, lastUpdated1, lastUpdated, "retrieved update time1 does not match expected")
    85  	}()
    86  
    87  	go func() {
    88  		defer wg.Done()
    89  		retrievedScore, lastUpdated, found := cache.Get(peerId2)
    90  		require.True(t, found, "failed to find score2 in cache")
    91  		require.Equal(t, score2, retrievedScore, "retrieved score2 does not match expected")
    92  		require.Equal(t, lastUpdated2, lastUpdated, "retrieved update time2 does not match expected")
    93  	}()
    94  
    95  	unittest.RequireReturnsBefore(t, wg.Wait, 100*time.Millisecond, "failed to retrieve scores from cache")
    96  
    97  	// test cache update
    98  	newScore1 := 15.0
    99  	newScore2 := 20.0
   100  	lastUpdated1 = time.Now().Add(time.Minute)
   101  	lastUpdated2 = time.Now().Add(time.Minute)
   102  
   103  	wg.Add(2)
   104  	go func() {
   105  		defer wg.Done()
   106  		err := cache.AdjustWithInit(peerId1, newScore1, lastUpdated1)
   107  		require.Nil(t, err, "failed to update score1 in cache")
   108  	}()
   109  
   110  	go func() {
   111  		defer wg.Done()
   112  		err := cache.AdjustWithInit(peerId2, newScore2, lastUpdated2)
   113  		require.Nil(t, err, "failed to update score2 in cache")
   114  	}()
   115  
   116  	unittest.RequireReturnsBefore(t, wg.Wait, 100*time.Millisecond, "failed to update scores in cache")
   117  
   118  	// retrieve updated scores concurrently
   119  	wg.Add(2)
   120  
   121  	go func() {
   122  		defer wg.Done()
   123  		updatedScore, updatedTime, found := cache.Get(peerId1)
   124  		require.True(t, found, "failed to find updated score1 in cache")
   125  		require.Equal(t, newScore1, updatedScore, "updated score1 does not match expected")
   126  		require.Equal(t, lastUpdated1, updatedTime, "updated time1 does not match expected")
   127  	}()
   128  
   129  	go func() {
   130  		defer wg.Done()
   131  		updatedScore, updatedTime, found := cache.Get(peerId2)
   132  		require.True(t, found, "failed to find updated score2 in cache")
   133  		require.Equal(t, newScore2, updatedScore, "updated score2 does not match expected")
   134  		require.Equal(t, lastUpdated2, updatedTime, "updated time2 does not match expected")
   135  	}()
   136  
   137  	unittest.RequireReturnsBefore(t, wg.Wait, 100*time.Millisecond, "failed to retrieve updated scores from cache")
   138  }
   139  
   140  // TestAppSpecificScoreCache_Eviction tests the eviction policy of AppSpecificScoreCache;
   141  // specifically, it tests that the cache evicts the least recently used record when the cache is full.
   142  func TestAppSpecificScoreCache_Eviction(t *testing.T) {
   143  	cache := internal.NewAppSpecificScoreCache(10, unittest.Logger(), metrics.NewNoopCollector())
   144  	require.NotNil(t, cache, "failed to create AppSpecificScoreCache")
   145  
   146  	peerIds := unittest.PeerIdFixtures(t, 11)
   147  	scores := []float64{5.0, 10.0, 15.0, 20.0, 25.0, 30.0, 35.0, -1, -2, -3, -4}
   148  	require.Equal(t, len(peerIds), len(scores), "peer ids and scores must have the same length")
   149  
   150  	// add scores to cache
   151  	for i := 0; i < len(peerIds); i++ {
   152  		err := cache.AdjustWithInit(peerIds[i], scores[i], time.Now())
   153  		require.Nil(t, err, "failed to add score to cache")
   154  	}
   155  
   156  	// retrieve scores from cache; the first score should have been evicted
   157  	for i := 1; i < len(peerIds); i++ {
   158  		retrievedScore, _, found := cache.Get(peerIds[i])
   159  		require.True(t, found, "failed to find score in cache")
   160  		require.Equal(t, scores[i], retrievedScore, "retrieved score does not match expected")
   161  	}
   162  
   163  	// the first score should not be in the cache
   164  	_, _, found := cache.Get(peerIds[0])
   165  	require.False(t, found, "score should not be in cache")
   166  }