@@ -4,16 +4,27 @@ import (
4
4
"context"
5
5
"testing"
6
6
"time"
7
+
8
+ "github.com/stretchr/testify/assert"
7
9
)
8
10
9
- // Eventually is like require.Eventually except it takes a context.
10
- // If ctx times out, the test will fail.
11
- // ctx must have a deadline set or this will panic.
12
- func Eventually (ctx context.Context , t testing.TB , condition func () bool , tick time.Duration ) bool {
11
+ // Eventually is like require.Eventually except it allows passing
12
+ // a context into the condition. It is safe to use with `require.*`.
13
+ //
14
+ // If ctx times out, the test will fail, but not immediately.
15
+ // It is the caller's responsibility to exit early if required.
16
+ //
17
+ // It is the caller's responsibility to ensure that ctx has a
18
+ // deadline or timeout set. Eventually will panic if this is not
19
+ // the case in order to avoid potentially waiting forever.
20
+ //
21
+ // condition is not run in a goroutine; use the provided
22
+ // context argument for cancellation if required.
23
+ func Eventually (ctx context.Context , t testing.TB , condition func (context.Context ) bool , tick time.Duration ) bool {
13
24
t .Helper ()
14
25
15
26
if _ , ok := ctx .Deadline (); ! ok {
16
- panic ("developer error: must set deadline on ctx" )
27
+ panic ("developer error: must set deadline or timeout on ctx" )
17
28
}
18
29
19
30
ch := make (chan bool , 1 )
@@ -22,13 +33,14 @@ func Eventually(ctx context.Context, t testing.TB, condition func() bool, tick t
22
33
for tick := ticker .C ; ; {
23
34
select {
24
35
case <- ctx .Done ():
25
- t . Errorf ( "Await timed out" )
36
+ assert . NoError ( t , ctx . Err (), "Eventually timed out" )
26
37
return false
27
38
case <- tick :
28
39
tick = nil
29
- go func () { ch <- condition () }( )
40
+ ch <- condition (ctx )
30
41
case v := <- ch :
31
42
if v {
43
+ close (ch )
32
44
return true
33
45
}
34
46
tick = ticker .C
@@ -38,23 +50,23 @@ func Eventually(ctx context.Context, t testing.TB, condition func() bool, tick t
38
50
39
51
// EventuallyShort is a convenience function that runs Eventually with
40
52
// IntervalFast and times out after WaitShort.
41
- func EventuallyShort (t testing.TB , condition func () bool ) bool {
53
+ func EventuallyShort (t testing.TB , condition func (context. Context ) bool ) bool {
42
54
ctx , cancel := context .WithTimeout (context .Background (), WaitShort )
43
55
defer cancel ()
44
56
return Eventually (ctx , t , condition , IntervalFast )
45
57
}
46
58
47
59
// EventuallyMedium is a convenience function that runs Eventually with
48
60
// IntervalMedium and times out after WaitMedium.
49
- func EventuallyMedium (t testing.TB , condition func () bool ) bool {
61
+ func EventuallyMedium (t testing.TB , condition func (context. Context ) bool ) bool {
50
62
ctx , cancel := context .WithTimeout (context .Background (), WaitMedium )
51
63
defer cancel ()
52
64
return Eventually (ctx , t , condition , IntervalMedium )
53
65
}
54
66
55
67
// EventuallyLong is a convenience function that runs Eventually with
56
68
// IntervalSlow and times out after WaitLong.
57
- func EventuallyLong (t testing.TB , condition func () bool ) bool {
69
+ func EventuallyLong (t testing.TB , condition func (context. Context ) bool ) bool {
58
70
ctx , cancel := context .WithTimeout (context .Background (), WaitLong )
59
71
defer cancel ()
60
72
return Eventually (ctx , t , condition , IntervalSlow )
0 commit comments