-
Notifications
You must be signed in to change notification settings - Fork 32
/
retry_test.go
122 lines (108 loc) · 3.32 KB
/
retry_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
113
114
115
116
117
118
119
120
121
122
package retry_test
import (
"context"
"errors"
"fmt"
"github.com/brianvoe/gofakeit/v6"
. "github.com/stretchr/testify/assert"
"github.com/synapsecns/sanguine/core/retry"
"testing"
"time"
)
// nolint: cyclop
func TestRetryWithBackoff(t *testing.T) {
// Test a function that succeeds on the first attempt.
t.Run("Success", func(t *testing.T) {
err := retry.WithBackoff(context.Background(), func(ctx context.Context) error {
return nil
})
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
})
// Test a function that fails and eventually succeeds.
t.Run("SuccessAfterRetries", func(t *testing.T) {
var i int
err := retry.WithBackoff(context.Background(), func(ctx context.Context) error {
if i < 2 {
i++
return errors.New("simulated error")
}
return nil
}, retry.WithMaxAttempts(3))
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
})
// Test a function that always fails.
t.Run("Failure", func(t *testing.T) {
err := retry.WithBackoff(context.Background(), func(ctx context.Context) error {
return errors.New("simulated error")
}, retry.WithMaxAttempts(3))
if err == nil {
t.Errorf("Expected error, but got nil")
}
})
// Test a function that times out.
t.Run("Timeout", func(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)
defer cancel()
err := retry.WithBackoff(ctx, func(ctx context.Context) error {
return errors.New("simulated error")
})
if err == nil {
t.Errorf("Expected error, but got nil")
}
})
t.Run("WithFactor", func(t *testing.T) {
cfg := retry.DefaultConfig()
factor := gofakeit.Float64Range(1, 10)
newCfg := retry.Configurator(t, cfg, retry.WithFactor(factor))
Equal(t, factor, newCfg.GetFactor())
})
t.Run("WithJitter", func(t *testing.T) {
cfg := retry.DefaultConfig()
jitter := gofakeit.Bool()
newCfg := retry.Configurator(t, cfg, retry.WithJitter(jitter))
Equal(t, jitter, newCfg.GetJitter())
})
t.Run("WithMin", func(t *testing.T) {
cfg := retry.DefaultConfig()
withMin := time.Duration(gofakeit.Uint64())
newCfg := retry.Configurator(t, cfg, retry.WithMin(withMin))
Equal(t, withMin, newCfg.GetMin())
})
t.Run("WithMax", func(t *testing.T) {
cfg := retry.DefaultConfig()
withMax := time.Duration(gofakeit.Uint64())
newCfg := retry.Configurator(t, cfg, retry.WithMax(withMax))
Equal(t, withMax, newCfg.GetMax())
})
t.Run("WithMaxAttemptTime", func(t *testing.T) {
err := retry.WithBackoff(context.Background(), func(ctx context.Context) error {
select {
case <-ctx.Done():
return fmt.Errorf("context canceled: %w", ctx.Err())
case <-time.After(time.Millisecond):
return nil
}
}, retry.WithMaxAttemptTime(1), retry.WithMaxAttempts(3))
NotNil(t, err)
})
t.Run("WithMaxTotalTime", func(t *testing.T) {
startTime := time.Now()
const testDuration = time.Second
err := retry.WithBackoff(context.Background(), func(ctx context.Context) error {
select {
case <-ctx.Done():
return fmt.Errorf("context canceled: %w", ctx.Err())
case <-time.After(time.Millisecond):
return fmt.Errorf("ima fail")
}
}, retry.WithMaxTotalTime(testDuration))
NotNil(t, err)
if time.Since(startTime) < time.Second {
t.Errorf("Expected to run for at least %s second, but ran for %s", testDuration.String(), time.Since(startTime))
}
})
}