-
Notifications
You must be signed in to change notification settings - Fork 1
/
retrier_test.go
112 lines (93 loc) · 2.16 KB
/
retrier_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
package retry
import (
"context"
"math"
"testing"
"time"
)
func TestContextCancel(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
cancel()
r := New(time.Hour, time.Hour)
for r.Wait(ctx) {
t.Fatalf("attempt allowed even though context cancelled")
}
}
func TestFirstTryImmediately(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
r := New(time.Hour, time.Hour)
tt := time.Now()
if !r.Wait(ctx) {
t.Fatalf("attempt not allowed")
}
if time.Since(tt) > time.Second {
t.Fatalf("attempt took too long")
}
}
func TestScalesExponentially(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
r := New(time.Second, time.Second*10)
r.Rate = 2
start := time.Now()
for i := 0; i < 3; i++ {
t.Logf("delay: %v", r.Delay)
r.Wait(ctx)
t.Logf("sinceStart: %v", time.Since(start).Round(time.Second))
}
sinceStart := time.Since(start).Round(time.Second)
if sinceStart != time.Second*6 {
t.Fatalf("did not scale correctly: %v", sinceStart)
}
}
func TestReset(t *testing.T) {
r := New(time.Hour, time.Hour)
// Should be immediate
ctx := context.Background()
r.Wait(ctx)
r.Reset()
r.Wait(ctx)
}
func TestJitter_Normal(t *testing.T) {
t.Parallel()
r := New(time.Millisecond, time.Millisecond)
r.Jitter = 0.5
var (
sum time.Duration
waits []float64
ctx = context.Background()
)
for i := 0; i < 1000; i++ {
start := time.Now()
r.Wait(ctx)
took := time.Since(start)
waits = append(waits, (took.Seconds() * 1000))
sum += took
}
avg := float64(sum) / float64(len(waits))
std := stdDev(waits)
if std > avg*0.1 {
t.Fatalf("standard deviation too high: %v", std)
}
t.Logf("average: %v", time.Duration(avg))
t.Logf("std dev: %v", std)
t.Logf("sample: %v", waits[len(waits)-10:])
}
// stdDev returns the standard deviation of the sample.
func stdDev(sample []float64) float64 {
if len(sample) == 0 {
return 0
}
mean := 0.0
for _, v := range sample {
mean += v
}
mean /= float64(len(sample))
variance := 0.0
for _, v := range sample {
variance += math.Pow(v-mean, 2)
}
variance /= float64(len(sample))
return math.Sqrt(variance)
}