github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/engine/collection/ingest/rate_limiter_test.go (about)

     1  package ingest_test
     2  
     3  import (
     4  	"fmt"
     5  	"sync"
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/stretchr/testify/require"
    10  	"go.uber.org/atomic"
    11  	"golang.org/x/time/rate"
    12  
    13  	"github.com/onflow/flow-go/access"
    14  	"github.com/onflow/flow-go/engine/collection/ingest"
    15  	"github.com/onflow/flow-go/model/flow"
    16  	"github.com/onflow/flow-go/utils/unittest"
    17  )
    18  
    19  var _ access.RateLimiter = (*ingest.AddressRateLimiter)(nil)
    20  
    21  func TestLimiterAddRemoveAddress(t *testing.T) {
    22  	t.Parallel()
    23  
    24  	good1 := unittest.RandomAddressFixture()
    25  	limited1 := unittest.RandomAddressFixture()
    26  	limited2 := unittest.RandomAddressFixture()
    27  
    28  	numPerSec := rate.Limit(1)
    29  	burst := 1
    30  	l := ingest.NewAddressRateLimiter(numPerSec, burst)
    31  
    32  	require.False(t, l.IsRateLimited(good1))
    33  	require.False(t, l.IsRateLimited(good1)) // address are not limited
    34  
    35  	l.AddAddress(limited1)
    36  	require.Equal(t, []flow.Address{limited1}, l.GetAddresses())
    37  
    38  	require.False(t, l.IsRateLimited(limited1)) // address 1 is not limited on the first call
    39  	require.True(t, l.IsRateLimited(limited1))  // limited on the second call immediately
    40  	require.True(t, l.IsRateLimited(limited1))  // limited on the second call immediately
    41  
    42  	require.False(t, l.IsRateLimited(good1))
    43  	require.False(t, l.IsRateLimited(good1)) // address are not limited
    44  
    45  	l.AddAddress(limited2)
    46  	list := l.GetAddresses()
    47  	require.Len(t, list, 2)
    48  	require.Contains(t, list, limited1, limited2)
    49  
    50  	require.False(t, l.IsRateLimited(limited2)) // address 2 is not limited on the first call
    51  	require.True(t, l.IsRateLimited(limited2))  // limited on the second call immediately
    52  	require.True(t, l.IsRateLimited(limited2))  // limited on the second call immediately
    53  
    54  	l.RemoveAddress(limited1) // after remove the limit, it no longer limited
    55  	require.False(t, l.IsRateLimited(limited1))
    56  	require.False(t, l.IsRateLimited(limited1))
    57  
    58  	// but limit2 is still limited
    59  	require.True(t, l.IsRateLimited(limited2))
    60  }
    61  
    62  func TestLimiterBurst(t *testing.T) {
    63  	t.Parallel()
    64  
    65  	limited1 := unittest.RandomAddressFixture()
    66  
    67  	numPerSec := rate.Limit(1)
    68  	burst := 3
    69  	l := ingest.NewAddressRateLimiter(numPerSec, burst)
    70  
    71  	l.AddAddress(limited1)
    72  	for i := 0; i < burst; i++ {
    73  		require.False(t, l.IsRateLimited(limited1), fmt.Sprintf("%v-nth call", i))
    74  	}
    75  
    76  	require.True(t, l.IsRateLimited(limited1)) // limited
    77  	require.True(t, l.IsRateLimited(limited1)) // limited
    78  }
    79  
    80  // verify that if wait long enough after rate limited
    81  func TestLimiterWaitLongEnough(t *testing.T) {
    82  	t.Parallel()
    83  
    84  	addr1 := unittest.RandomAddressFixture()
    85  
    86  	// with limit set to 10, it means we allow 10 messages per second,
    87  	// and with burst set to 1, it means we only allow 1 message at a time,
    88  	// so the limit is 1 message per 100 milliseconds.
    89  	// Note rate.Limit(0.1) is not to set 1 message per 100 milliseconds, but
    90  	// 1 message per 10 seconds.
    91  	numPerSec := rate.Limit(10)
    92  	burst := 1
    93  	l := ingest.NewAddressRateLimiter(numPerSec, burst)
    94  
    95  	l.AddAddress(addr1)
    96  	require.False(t, l.IsRateLimited(addr1))
    97  	require.True(t, l.IsRateLimited(addr1))
    98  
    99  	// check every 10 Millisecond then after 100 Millisecond it should be allowed
   100  	require.Eventually(t, func() bool {
   101  		return l.Allow(addr1)
   102  	}, 110*time.Millisecond, 10*time.Millisecond)
   103  
   104  	// block again until another 100 ms
   105  	require.True(t, l.IsRateLimited(addr1))
   106  
   107  	// block until another 100 ms
   108  	require.Eventually(t, func() bool {
   109  		return l.Allow(addr1)
   110  	}, 110*time.Millisecond, 10*time.Millisecond)
   111  }
   112  
   113  func TestLimiterConcurrentSafe(t *testing.T) {
   114  	t.Parallel()
   115  	good1 := unittest.RandomAddressFixture()
   116  	limited1 := unittest.RandomAddressFixture()
   117  
   118  	numPerSec := rate.Limit(1)
   119  	burst := 1
   120  	l := ingest.NewAddressRateLimiter(numPerSec, burst)
   121  
   122  	l.AddAddress(limited1)
   123  
   124  	wg := sync.WaitGroup{}
   125  	wg.Add(2)
   126  
   127  	succeed := atomic.NewUint64(0)
   128  	go func(wg *sync.WaitGroup) {
   129  		defer wg.Done()
   130  		ok := l.IsRateLimited(limited1)
   131  		if ok {
   132  			succeed.Add(1)
   133  		}
   134  		require.False(t, l.IsRateLimited(good1)) // never limited
   135  	}(&wg)
   136  
   137  	go func(wg *sync.WaitGroup) {
   138  		defer wg.Done()
   139  		ok := l.IsRateLimited(limited1)
   140  		if ok {
   141  			succeed.Add(1)
   142  		}
   143  		require.False(t, l.IsRateLimited(good1)) // never limited
   144  	}(&wg)
   145  
   146  	wg.Wait()
   147  	require.Equal(t, uint64(1), succeed.Load()) // should only succeed once
   148  }
   149  
   150  func TestLimiterGetSetConfig(t *testing.T) {
   151  	t.Parallel()
   152  
   153  	addr1 := unittest.RandomAddressFixture()
   154  
   155  	// with limit set to 10, it means we allow 10 messages per second,
   156  	// and with burst set to 1, it means we only allow 1 message at a time,
   157  	// so the limit is 1 message per 100 milliseconds.
   158  	// Note rate.Limit(0.1) is not to set 1 message per 100 milliseconds, but
   159  	// 1 message per 10 seconds.
   160  	numPerSec := rate.Limit(10)
   161  	burst := 1
   162  	l := ingest.NewAddressRateLimiter(numPerSec, burst)
   163  
   164  	l.AddAddress(addr1)
   165  	require.False(t, l.IsRateLimited(addr1))
   166  	require.True(t, l.IsRateLimited(addr1))
   167  
   168  	limitConfig, burstConfig := l.GetLimitConfig()
   169  	require.Equal(t, numPerSec, limitConfig)
   170  	require.Equal(t, burst, burstConfig)
   171  
   172  	// change from 1 message per 100 ms to 4 messages per 200 ms
   173  	l.SetLimitConfig(rate.Limit(20), 4)
   174  
   175  	// verify the quota is reset, and the new limit is applied
   176  	for i := 0; i < 4; i++ {
   177  		require.False(t, l.IsRateLimited(addr1), fmt.Sprintf("fail at %v-th call", i))
   178  	}
   179  	require.True(t, l.IsRateLimited(addr1))
   180  
   181  	// check every 10 Millisecond then after 100 Millisecond it should be allowed
   182  	require.Eventually(t, func() bool {
   183  		return l.Allow(addr1)
   184  	}, 210*time.Millisecond, 10*time.Millisecond)
   185  }