github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/network/p2p/inspector/internal/cache/tracker_test.go (about) 1 package cache 2 3 import ( 4 "sync" 5 "testing" 6 "time" 7 8 "github.com/rs/zerolog" 9 "github.com/stretchr/testify/require" 10 11 "github.com/onflow/flow-go/model/flow" 12 "github.com/onflow/flow-go/module/metrics" 13 "github.com/onflow/flow-go/utils/unittest" 14 ) 15 16 // TestClusterPrefixedMessagesReceivedTracker_Inc ensures cluster prefixed received tracker increments a cluster prefixed control messages received gauge value correctly. 17 func TestClusterPrefixedMessagesReceivedTracker_Inc(t *testing.T) { 18 tracker := mockTracker(t) 19 id := unittest.PeerIdFixture(t) 20 n := float64(5) 21 prevGuage := 0.0 22 for i := float64(1); i <= n; i++ { 23 guage, err := tracker.Inc(id) 24 require.NoError(t, err) 25 // on each increment the current gauge value should 26 // always be greater than the previous gauge value but 27 // slightly less than i due to the decay. 28 require.LessOrEqual(t, guage, i) 29 require.Greater(t, guage, prevGuage) 30 } 31 } 32 33 // TestClusterPrefixedMessagesReceivedTracker_IncConcurrent ensures cluster prefixed received tracker increments a cluster prefixed control messages received gauge value correctly concurrently. 34 func TestClusterPrefixedMessagesReceivedTracker_IncConcurrent(t *testing.T) { 35 tracker := mockTracker(t) 36 n := float64(5) 37 id := unittest.PeerIdFixture(t) 38 var wg sync.WaitGroup 39 wg.Add(5) 40 for i := float64(0); i < n; i++ { 41 go func() { 42 defer wg.Done() 43 _, err := tracker.Inc(id) 44 require.NoError(t, err) 45 }() 46 } 47 unittest.RequireReturnsBefore(t, wg.Wait, 100*time.Millisecond, "timed out waiting for goroutines to finish") 48 // after each decay is applied the gauge value result should be slightly less than n 49 gaugeVal, err := tracker.Load(id) 50 require.NoError(t, err) 51 require.InDelta(t, n, gaugeVal, .2) 52 } 53 54 // TestClusterPrefixedMessagesReceivedTracker_ConcurrentIncAndLoad ensures cluster prefixed received tracker increments/loads the cluster prefixed control messages received gauge value correctly concurrently. 55 func TestClusterPrefixedMessagesReceivedTracker_ConcurrentIncAndLoad(t *testing.T) { 56 tracker := mockTracker(t) 57 n := float64(5) 58 id := unittest.PeerIdFixture(t) 59 var wg sync.WaitGroup 60 wg.Add(10) 61 62 go func() { 63 for i := float64(0); i < n; i++ { 64 go func() { 65 defer wg.Done() 66 _, err := tracker.Inc(id) 67 require.NoError(t, err) 68 }() 69 } 70 }() 71 72 // slight sleep so that each goroutine does not start at the same exact time 73 time.Sleep(500 * time.Millisecond) 74 go func() { 75 for i := float64(0); i < n; i++ { 76 go func() { 77 defer wg.Done() 78 gaugeVal, err := tracker.Load(id) 79 require.NoError(t, err) 80 require.Greater(t, gaugeVal, float64(0)) 81 require.LessOrEqual(t, gaugeVal, n) 82 }() 83 } 84 }() 85 unittest.RequireReturnsBefore(t, wg.Wait, 100*time.Millisecond, "timed out waiting for goroutines to finish") 86 gaugeVal, err := tracker.Load(id) 87 require.NoError(t, err) 88 // after each decay is applied the gauge value result should be slightly less than n 89 require.InDelta(t, n, gaugeVal, .2) 90 } 91 92 func TestClusterPrefixedMessagesReceivedTracker_StoreAndGetActiveClusterIds(t *testing.T) { 93 tracker := mockTracker(t) 94 activeClusterIds := []flow.ChainIDList{chainIDListFixture(), chainIDListFixture(), chainIDListFixture()} 95 for _, chainIDList := range activeClusterIds { 96 tracker.StoreActiveClusterIds(chainIDList) 97 actualChainIdList := tracker.GetActiveClusterIds() 98 require.Equal(t, chainIDList, actualChainIdList) 99 } 100 } 101 102 func TestClusterPrefixedMessagesReceivedTracker_StoreAndGetActiveClusterIdsConcurrent(t *testing.T) { 103 tracker := mockTracker(t) 104 activeClusterIds := []flow.ChainIDList{chainIDListFixture(), chainIDListFixture(), chainIDListFixture()} 105 expectedLen := len(activeClusterIds[0]) 106 var wg sync.WaitGroup 107 wg.Add(len(activeClusterIds)) 108 for _, chainIDList := range activeClusterIds { 109 go func(ids flow.ChainIDList) { 110 defer wg.Done() 111 tracker.StoreActiveClusterIds(ids) 112 actualChainIdList := tracker.GetActiveClusterIds() 113 require.NotNil(t, actualChainIdList) 114 require.Equal(t, expectedLen, len(actualChainIdList)) // each fixture is of the same len 115 }(chainIDList) 116 } 117 118 unittest.RequireReturnsBefore(t, wg.Wait, 100*time.Millisecond, "timed out waiting for goroutines to finish") 119 120 actualChainIdList := tracker.GetActiveClusterIds() 121 require.NotNil(t, actualChainIdList) 122 require.Equal(t, expectedLen, len(actualChainIdList)) // each fixture is of the same len 123 } 124 125 func mockTracker(t *testing.T) *ClusterPrefixedMessagesReceivedTracker { 126 logger := zerolog.Nop() 127 sizeLimit := uint32(100) 128 collector := metrics.NewNoopCollector() 129 decay := defaultDecay 130 tracker, err := NewClusterPrefixedMessagesReceivedTracker(logger, sizeLimit, collector, decay) 131 require.NoError(t, err) 132 return tracker 133 } 134 135 func chainIDListFixture() flow.ChainIDList { 136 return flow.ChainIDList{ 137 flow.ChainID(unittest.IdentifierFixture().String()), 138 flow.ChainID(unittest.IdentifierFixture().String()), 139 flow.ChainID(unittest.IdentifierFixture().String()), 140 flow.ChainID(unittest.IdentifierFixture().String()), 141 } 142 }