...
1
3 package poll
4
5 import (
6 "fmt"
7 "strings"
8 "time"
9
10 "gotest.tools/v3/assert/cmp"
11 "gotest.tools/v3/internal/assert"
12 "gotest.tools/v3/internal/format"
13 )
14
15
16 type TestingT interface {
17 LogT
18 Fatalf(format string, args ...interface{})
19 }
20
21
22 type LogT interface {
23 Log(args ...interface{})
24 Logf(format string, args ...interface{})
25 }
26
27 type helperT interface {
28 Helper()
29 }
30
31
32 type Settings struct {
33
34 Timeout time.Duration
35
36
37 Delay time.Duration
38 }
39
40 func defaultConfig() *Settings {
41 return &Settings{Timeout: 10 * time.Second, Delay: 100 * time.Millisecond}
42 }
43
44
45 type SettingOp func(config *Settings)
46
47
48 func WithDelay(delay time.Duration) SettingOp {
49 return func(config *Settings) {
50 config.Delay = delay
51 }
52 }
53
54
55 func WithTimeout(timeout time.Duration) SettingOp {
56 return func(config *Settings) {
57 config.Timeout = timeout
58 }
59 }
60
61
62 type Result interface {
63
64
65 Error() error
66
67 Done() bool
68
69 Message() string
70 }
71
72 type result struct {
73 done bool
74 message string
75 err error
76 }
77
78 func (r result) Done() bool {
79 return r.done
80 }
81
82 func (r result) Message() string {
83 return r.message
84 }
85
86 func (r result) Error() error {
87 return r.err
88 }
89
90
91
92
93 func Continue(message string, args ...interface{}) Result {
94 return result{message: format.Message(append([]interface{}{message}, args...)...)}
95 }
96
97
98
99 func Success() Result {
100 return result{done: true}
101 }
102
103
104
105 func Error(err error) Result {
106 return result{err: err}
107 }
108
109
110
111
112 func WaitOn(t TestingT, check Check, pollOps ...SettingOp) {
113 if ht, ok := t.(helperT); ok {
114 ht.Helper()
115 }
116 config := defaultConfig()
117 for _, pollOp := range pollOps {
118 pollOp(config)
119 }
120
121 var lastMessage string
122 after := time.After(config.Timeout)
123 chResult := make(chan Result)
124 for {
125 go func() {
126 chResult <- check(t)
127 }()
128 select {
129 case <-after:
130 if lastMessage == "" {
131 lastMessage = "first check never completed"
132 }
133 t.Fatalf("timeout hit after %s: %s", config.Timeout, lastMessage)
134 case result := <-chResult:
135 switch {
136 case result.Error() != nil:
137 t.Fatalf("polling check failed: %s", result.Error())
138 case result.Done():
139 return
140 }
141 time.Sleep(config.Delay)
142 lastMessage = result.Message()
143 }
144 }
145 }
146
147
148
149
150 func Compare(compare cmp.Comparison) Result {
151 buf := new(logBuffer)
152 if assert.RunComparison(buf, assert.ArgsAtZeroIndex, compare) {
153 return Success()
154 }
155 return Continue("%v", buf.String())
156 }
157
158 type logBuffer struct {
159 log [][]interface{}
160 }
161
162 func (c *logBuffer) Log(args ...interface{}) {
163 c.log = append(c.log, args)
164 }
165
166 func (c *logBuffer) String() string {
167 b := new(strings.Builder)
168 for _, item := range c.log {
169 b.WriteString(fmt.Sprint(item...) + " ")
170 }
171 return b.String()
172 }
173
View as plain text