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 }