github.com/MetalBlockchain/metalgo@v1.11.9/utils/timer/adaptive_timeout_manager_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 timer 5 6 import ( 7 "sync" 8 "testing" 9 "time" 10 11 "github.com/prometheus/client_golang/prometheus" 12 "github.com/stretchr/testify/require" 13 14 "github.com/MetalBlockchain/metalgo/ids" 15 ) 16 17 // Test that Initialize works 18 func TestAdaptiveTimeoutManagerInit(t *testing.T) { 19 type test struct { 20 config AdaptiveTimeoutConfig 21 expectedErr error 22 } 23 24 tests := []*test{ 25 { 26 config: AdaptiveTimeoutConfig{ 27 InitialTimeout: time.Second, 28 MinimumTimeout: 2 * time.Second, 29 MaximumTimeout: 3 * time.Second, 30 TimeoutCoefficient: 2, 31 TimeoutHalflife: 5 * time.Minute, 32 }, 33 expectedErr: errInitialTimeoutBelowMinimum, 34 }, 35 { 36 config: AdaptiveTimeoutConfig{ 37 InitialTimeout: 5 * time.Second, 38 MinimumTimeout: 2 * time.Second, 39 MaximumTimeout: 3 * time.Second, 40 TimeoutCoefficient: 2, 41 TimeoutHalflife: 5 * time.Minute, 42 }, 43 expectedErr: errInitialTimeoutAboveMaximum, 44 }, 45 { 46 config: AdaptiveTimeoutConfig{ 47 InitialTimeout: 2 * time.Second, 48 MinimumTimeout: 2 * time.Second, 49 MaximumTimeout: 3 * time.Second, 50 TimeoutCoefficient: 0.9, 51 TimeoutHalflife: 5 * time.Minute, 52 }, 53 expectedErr: errTooSmallTimeoutCoefficient, 54 }, 55 { 56 config: AdaptiveTimeoutConfig{ 57 InitialTimeout: 2 * time.Second, 58 MinimumTimeout: 2 * time.Second, 59 MaximumTimeout: 3 * time.Second, 60 TimeoutCoefficient: 1, 61 }, 62 expectedErr: errNonPositiveHalflife, 63 }, 64 { 65 config: AdaptiveTimeoutConfig{ 66 InitialTimeout: 2 * time.Second, 67 MinimumTimeout: 2 * time.Second, 68 MaximumTimeout: 3 * time.Second, 69 TimeoutCoefficient: 1, 70 TimeoutHalflife: -1 * time.Second, 71 }, 72 expectedErr: errNonPositiveHalflife, 73 }, 74 { 75 config: AdaptiveTimeoutConfig{ 76 InitialTimeout: 2 * time.Second, 77 MinimumTimeout: 2 * time.Second, 78 MaximumTimeout: 3 * time.Second, 79 TimeoutCoefficient: 1, 80 TimeoutHalflife: 5 * time.Minute, 81 }, 82 }, 83 } 84 85 for _, test := range tests { 86 _, err := NewAdaptiveTimeoutManager(&test.config, prometheus.NewRegistry()) 87 require.ErrorIs(t, err, test.expectedErr) 88 } 89 } 90 91 func TestAdaptiveTimeoutManager(t *testing.T) { 92 tm, err := NewAdaptiveTimeoutManager( 93 &AdaptiveTimeoutConfig{ 94 InitialTimeout: time.Millisecond, 95 MinimumTimeout: time.Millisecond, 96 MaximumTimeout: time.Hour, 97 TimeoutHalflife: 5 * time.Minute, 98 TimeoutCoefficient: 1.25, 99 }, 100 prometheus.NewRegistry(), 101 ) 102 require.NoError(t, err) 103 go tm.Dispatch() 104 105 var lock sync.Mutex 106 107 numSuccessful := 5 108 109 wg := sync.WaitGroup{} 110 wg.Add(numSuccessful) 111 112 callback := new(func()) 113 *callback = func() { 114 lock.Lock() 115 defer lock.Unlock() 116 117 numSuccessful-- 118 if numSuccessful > 0 { 119 tm.Put(ids.RequestID{Op: byte(numSuccessful)}, true, *callback) 120 } 121 if numSuccessful >= 0 { 122 wg.Done() 123 } 124 if numSuccessful%2 == 0 { 125 tm.Remove(ids.RequestID{Op: byte(numSuccessful)}) 126 tm.Put(ids.RequestID{Op: byte(numSuccessful)}, true, *callback) 127 } 128 } 129 (*callback)() 130 (*callback)() 131 132 wg.Wait() 133 }