github.com/ava-labs/avalanchego@v1.11.11/network/throttling/dial_throttler_test.go (about) 1 // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package throttling 5 6 import ( 7 "context" 8 "testing" 9 "time" 10 11 "github.com/stretchr/testify/require" 12 ) 13 14 // Test that the DialThrottler returned by NewDialThrottler works 15 func TestDialThrottler(t *testing.T) { 16 require := require.New(t) 17 18 startTime := time.Now() 19 // Allows 5 per second 20 throttler := NewDialThrottler(5) 21 // Use all 5 22 for i := 0; i < 5; i++ { 23 acquiredChan := make(chan struct{}, 1) 24 // Should return immediately because < 5 taken this second 25 go func() { 26 require.NoError(throttler.Acquire(context.Background())) 27 acquiredChan <- struct{}{} 28 }() 29 select { 30 case <-time.After(10 * time.Millisecond): 31 require.FailNow("should have acquired immediately") 32 case <-acquiredChan: 33 } 34 close(acquiredChan) 35 } 36 37 acquiredChan := make(chan struct{}, 1) 38 go func() { 39 // Should block because 5 already taken within last second 40 require.NoError(throttler.Acquire(context.Background())) 41 acquiredChan <- struct{}{} 42 }() 43 44 select { 45 case <-time.After(25 * time.Millisecond): 46 case <-acquiredChan: 47 require.FailNow("should not have been able to acquire immediately") 48 } 49 50 // Wait until the 6th Acquire() has returned. The time at which 51 // that returns should be no more than 1s after the time at which 52 // the first Acquire() returned. 53 <-acquiredChan 54 close(acquiredChan) 55 // Use 1.05 seconds instead of 1 second to give some "wiggle room" 56 // so test doesn't flake 57 require.LessOrEqual(time.Since(startTime), 1050*time.Millisecond) 58 } 59 60 // Test that Acquire honors its specification about its context being canceled 61 func TestDialThrottlerCancel(t *testing.T) { 62 require := require.New(t) 63 64 // Allows 5 per second 65 throttler := NewDialThrottler(5) 66 // Use all 5 67 for i := 0; i < 5; i++ { 68 acquiredChan := make(chan struct{}, 1) 69 // Should return immediately because < 5 taken this second 70 go func() { 71 require.NoError(throttler.Acquire(context.Background())) 72 acquiredChan <- struct{}{} 73 }() 74 select { 75 case <-time.After(10 * time.Millisecond): 76 require.FailNow("should have acquired immediately") 77 case <-acquiredChan: 78 } 79 close(acquiredChan) 80 } 81 82 acquiredChan := make(chan struct{}, 1) 83 ctx, cancel := context.WithCancel(context.Background()) 84 go func() { 85 // Should block because 5 already taken within last second 86 err := throttler.Acquire(ctx) 87 // Should error because we call cancel() below 88 require.ErrorIs(err, context.Canceled) 89 acquiredChan <- struct{}{} 90 }() 91 92 // Cancel the 6th acquire 93 cancel() 94 select { 95 case <-acquiredChan: 96 case <-time.After(10 * time.Millisecond): 97 require.FailNow("Acquire should have returned immediately upon context cancellation") 98 } 99 close(acquiredChan) 100 } 101 102 // Test that the Throttler return by NewNoThrottler never blocks on Acquire() 103 func TestNoDialThrottler(t *testing.T) { 104 require := require.New(t) 105 106 throttler := NewNoDialThrottler() 107 for i := 0; i < 250; i++ { 108 startTime := time.Now() 109 require.NoError(throttler.Acquire(context.Background())) // Should always immediately return 110 require.WithinDuration(time.Now(), startTime, 25*time.Millisecond) 111 } 112 }