Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
aos
GitHub Repository: aos/grafana-agent
Path: blob/main/pkg/util/eventually.go
4094 views
1
package util
2
3
import (
4
"context"
5
"time"
6
7
"github.com/grafana/dskit/backoff"
8
"github.com/stretchr/testify/require"
9
)
10
11
var backoffRetry = backoff.Config{
12
MinBackoff: 10 * time.Millisecond,
13
MaxBackoff: 1 * time.Second,
14
MaxRetries: 10,
15
}
16
17
// Eventually calls the check function several times until it doesn't report an
18
// error. Failing the test in the t provided to check does not fail the test
19
// until the provided backoff.Config is out of retries.
20
func Eventually(t require.TestingT, check func(t require.TestingT)) {
21
EventuallyWithBackoff(t, check, backoffRetry)
22
}
23
24
func EventuallyWithBackoff(t require.TestingT, check func(t require.TestingT), bc backoff.Config) {
25
bo := backoff.New(context.Background(), bc)
26
27
var (
28
lastErrors []testError
29
shouldAbort bool
30
)
31
32
for bo.Ongoing() {
33
ev := invokeCheck(check)
34
35
lastErrors = ev.errors
36
shouldAbort = ev.aborted
37
38
if len(ev.errors) == 0 {
39
break
40
}
41
42
bo.Wait()
43
}
44
45
if bo.Err() != nil {
46
// Forward the last set of received errors back to our real test.
47
for _, err := range lastErrors {
48
t.Errorf(err.format, err.args...)
49
}
50
51
if shouldAbort {
52
t.FailNow()
53
}
54
}
55
}
56
57
func invokeCheck(check func(t require.TestingT)) (result eventuallyT) {
58
defer func() {
59
if err := recover(); err != nil {
60
if _, ok := err.(testAbort); ok {
61
return
62
}
63
// Unexpected panic; raise it back.
64
panic(err)
65
}
66
}()
67
68
check(&result)
69
return
70
}
71
72
type eventuallyT struct {
73
// Populated by calls to Errorf.
74
errors []testError
75
aborted bool
76
}
77
78
// Helper types for eventuallyT,.
79
type (
80
testError struct {
81
format string
82
args []interface{}
83
}
84
85
// testAbort is sent when FailNow is called.
86
testAbort struct{}
87
)
88
89
var _ require.TestingT = (*eventuallyT)(nil)
90
91
func (et *eventuallyT) Errorf(format string, args ...interface{}) {
92
et.errors = append(et.errors, testError{
93
format: format,
94
args: args,
95
})
96
}
97
98
func (et *eventuallyT) FailNow() {
99
et.aborted = true
100
panic(testAbort{})
101
}
102
103