1package backoff
2
3import (
4	"reflect"
5	"sync"
6	"testing"
7	"time"
8)
9
10func Test1(t *testing.T) {
11
12	b := &Backoff{
13		Min:    100 * time.Millisecond,
14		Max:    10 * time.Second,
15		Factor: 2,
16	}
17
18	equals(t, b.Duration(), 100*time.Millisecond)
19	equals(t, b.Duration(), 200*time.Millisecond)
20	equals(t, b.Duration(), 400*time.Millisecond)
21	b.Reset()
22	equals(t, b.Duration(), 100*time.Millisecond)
23}
24
25func TestForAttempt(t *testing.T) {
26
27	b := &Backoff{
28		Min:    100 * time.Millisecond,
29		Max:    10 * time.Second,
30		Factor: 2,
31	}
32
33	equals(t, b.ForAttempt(0), 100*time.Millisecond)
34	equals(t, b.ForAttempt(1), 200*time.Millisecond)
35	equals(t, b.ForAttempt(2), 400*time.Millisecond)
36	b.Reset()
37	equals(t, b.ForAttempt(0), 100*time.Millisecond)
38}
39
40func Test2(t *testing.T) {
41
42	b := &Backoff{
43		Min:    100 * time.Millisecond,
44		Max:    10 * time.Second,
45		Factor: 1.5,
46	}
47
48	equals(t, b.Duration(), 100*time.Millisecond)
49	equals(t, b.Duration(), 150*time.Millisecond)
50	equals(t, b.Duration(), 225*time.Millisecond)
51	b.Reset()
52	equals(t, b.Duration(), 100*time.Millisecond)
53}
54
55func Test3(t *testing.T) {
56
57	b := &Backoff{
58		Min:    100 * time.Nanosecond,
59		Max:    10 * time.Second,
60		Factor: 1.75,
61	}
62
63	equals(t, b.Duration(), 100*time.Nanosecond)
64	equals(t, b.Duration(), 175*time.Nanosecond)
65	equals(t, b.Duration(), 306*time.Nanosecond)
66	b.Reset()
67	equals(t, b.Duration(), 100*time.Nanosecond)
68}
69
70func Test4(t *testing.T) {
71	b := &Backoff{
72		Min:    500 * time.Second,
73		Max:    100 * time.Second,
74		Factor: 1,
75	}
76
77	equals(t, b.Duration(), b.Max)
78}
79
80func TestGetAttempt(t *testing.T) {
81	b := &Backoff{
82		Min:    100 * time.Millisecond,
83		Max:    10 * time.Second,
84		Factor: 2,
85	}
86	equals(t, b.Attempt(), float64(0))
87	equals(t, b.Duration(), 100*time.Millisecond)
88	equals(t, b.Attempt(), float64(1))
89	equals(t, b.Duration(), 200*time.Millisecond)
90	equals(t, b.Attempt(), float64(2))
91	equals(t, b.Duration(), 400*time.Millisecond)
92	equals(t, b.Attempt(), float64(3))
93	b.Reset()
94	equals(t, b.Attempt(), float64(0))
95	equals(t, b.Duration(), 100*time.Millisecond)
96	equals(t, b.Attempt(), float64(1))
97}
98
99func TestJitter(t *testing.T) {
100	b := &Backoff{
101		Min:    100 * time.Millisecond,
102		Max:    10 * time.Second,
103		Factor: 2,
104		Jitter: true,
105	}
106
107	equals(t, b.Duration(), 100*time.Millisecond)
108	between(t, b.Duration(), 100*time.Millisecond, 200*time.Millisecond)
109	between(t, b.Duration(), 100*time.Millisecond, 400*time.Millisecond)
110	b.Reset()
111	equals(t, b.Duration(), 100*time.Millisecond)
112}
113
114func TestCopy(t *testing.T) {
115	b := &Backoff{
116		Min:    100 * time.Millisecond,
117		Max:    10 * time.Second,
118		Factor: 2,
119	}
120	b2 := b.Copy()
121	equals(t, b, b2)
122}
123
124func TestConcurrent(t *testing.T) {
125	b := &Backoff{
126		Min:    100 * time.Millisecond,
127		Max:    10 * time.Second,
128		Factor: 2,
129	}
130
131	wg := &sync.WaitGroup{}
132
133	test := func() {
134		time.Sleep(b.Duration())
135		wg.Done()
136	}
137
138	wg.Add(2)
139	go test()
140	go test()
141	wg.Wait()
142}
143
144func between(t *testing.T, actual, low, high time.Duration) {
145	t.Helper()
146	if actual < low {
147		t.Fatalf("Got %s, Expecting >= %s", actual, low)
148	}
149	if actual > high {
150		t.Fatalf("Got %s, Expecting <= %s", actual, high)
151	}
152}
153
154func equals(t *testing.T, v1, v2 interface{}) {
155	t.Helper()
156	if !reflect.DeepEqual(v1, v2) {
157		t.Fatalf("Got %v, Expecting %v", v1, v2)
158	}
159}
160