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  }