1package backoff 2 3import ( 4 "fmt" 5 "math" 6 "testing" 7 "time" 8) 9 10// If given New with 0's and no jitter, ensure that certain invariants are met: 11// 12// - the default max duration and interval should be used 13// - noJitter should be true 14// - the RNG should not be initialised 15// - the first duration should be equal to the default interval 16func TestDefaults(t *testing.T) { 17 b := NewWithoutJitter(0, 0) 18 19 if b.maxDuration != DefaultMaxDuration { 20 t.Fatalf("expected new backoff to use the default max duration (%s), but have %s", DefaultMaxDuration, b.maxDuration) 21 } 22 23 if b.interval != DefaultInterval { 24 t.Fatalf("exepcted new backoff to use the default interval (%s), but have %s", DefaultInterval, b.interval) 25 } 26 27 if b.noJitter != true { 28 t.Fatal("backoff should have been initialised without jitter") 29 } 30 31 dur := b.Duration() 32 if dur != DefaultInterval { 33 t.Fatalf("expected first duration to be %s, have %s", DefaultInterval, dur) 34 } 35} 36 37// Given a zero-value initialised Backoff, it should be transparently 38// setup. 39func TestSetup(t *testing.T) { 40 b := new(Backoff) 41 dur := b.Duration() 42 if dur < 0 || dur > (5*time.Minute) { 43 t.Fatalf("want duration between 0 and 5 minutes, have %s", dur) 44 } 45} 46 47// Ensure that tries incremenets as expected. 48func TestTries(t *testing.T) { 49 b := NewWithoutJitter(5, 1) 50 51 for i := uint64(0); i < 3; i++ { 52 if b.n != i { 53 t.Fatalf("want tries=%d, have tries=%d", i, b.n) 54 } 55 56 pow := 1 << i 57 expected := time.Duration(pow) 58 dur := b.Duration() 59 if dur != expected { 60 t.Fatalf("want duration=%d, have duration=%d at i=%d", expected, dur, i) 61 } 62 } 63 64 for i := uint(3); i < 5; i++ { 65 dur := b.Duration() 66 if dur != 5 { 67 t.Fatalf("want duration=5, have %d at i=%d", dur, i) 68 } 69 } 70} 71 72// Ensure that a call to Reset will actually reset the Backoff. 73func TestReset(t *testing.T) { 74 const iter = 10 75 b := New(1000, 1) 76 for i := 0; i < iter; i++ { 77 _ = b.Duration() 78 } 79 80 if b.n != iter { 81 t.Fatalf("expected tries=%d, have tries=%d", iter, b.n) 82 } 83 84 b.Reset() 85 if b.n != 0 { 86 t.Fatalf("expected tries=0 after reset, have tries=%d", b.n) 87 } 88} 89 90const decay = 5 * time.Millisecond 91const max = 10 * time.Millisecond 92const interval = time.Millisecond 93 94func TestDecay(t *testing.T) { 95 const iter = 10 96 97 b := NewWithoutJitter(max, 1) 98 b.SetDecay(decay) 99 100 var backoff time.Duration 101 for i := 0; i < iter; i++ { 102 backoff = b.Duration() 103 } 104 105 if b.n != iter { 106 t.Fatalf("expected tries=%d, have tries=%d", iter, b.n) 107 } 108 109 // Don't decay below backoff 110 b.lastTry = time.Now().Add(-backoff + 1) 111 backoff = b.Duration() 112 if b.n != iter+1 { 113 t.Fatalf("expected tries=%d, have tries=%d", iter+1, b.n) 114 } 115 116 // Reset after backoff + decay 117 b.lastTry = time.Now().Add(-backoff - decay) 118 b.Duration() 119 if b.n != 1 { 120 t.Fatalf("expected tries=%d, have tries=%d", 1, b.n) 121 } 122} 123 124// Ensure that decay works even if the retry counter is saturated. 125func TestDecaySaturation(t *testing.T) { 126 b := NewWithoutJitter(1<<2, 1) 127 b.SetDecay(decay) 128 129 var duration time.Duration 130 for i := 0; i <= 2; i++ { 131 duration = b.Duration() 132 } 133 134 if duration != 1<<2 { 135 t.Fatalf("expected duration=%v, have duration=%v", 1<<2, duration) 136 } 137 138 b.lastTry = time.Now().Add(-duration - decay) 139 b.n = math.MaxUint64 140 141 duration = b.Duration() 142 if duration != 1 { 143 t.Errorf("expected duration=%v, have duration=%v", 1, duration) 144 } 145} 146 147func ExampleBackoff_SetDecay() { 148 b := NewWithoutJitter(max, interval) 149 b.SetDecay(decay) 150 151 // try 0 152 fmt.Println(b.Duration()) 153 154 // try 1 155 fmt.Println(b.Duration()) 156 157 // try 2 158 duration := b.Duration() 159 fmt.Println(duration) 160 161 // try 3, below decay 162 time.Sleep(duration) 163 duration = b.Duration() 164 fmt.Println(duration) 165 166 // try 4, resets 167 time.Sleep(duration + decay) 168 fmt.Println(b.Duration()) 169 170 // Output: 1ms 171 // 2ms 172 // 4ms 173 // 8ms 174 // 1ms 175} 176