1
2
3
4
5 package synctest_test
6
7 import (
8 "fmt"
9 "internal/synctest"
10 "iter"
11 "reflect"
12 "slices"
13 "strconv"
14 "sync"
15 "testing"
16 "time"
17 )
18
19 func TestNow(t *testing.T) {
20 start := time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC).In(time.Local)
21 synctest.Run(func() {
22
23 if got, want := time.Now(), start; !got.Equal(want) {
24 t.Errorf("at start: time.Now = %v, want %v", got, want)
25 }
26 go func() {
27
28 if got, want := time.Now(), start; !got.Equal(want) {
29 t.Errorf("time.Now = %v, want %v", got, want)
30 }
31 }()
32
33 time.Sleep(1 * time.Second)
34 if got, want := time.Now(), start.Add(1*time.Second); !got.Equal(want) {
35 t.Errorf("after sleep: time.Now = %v, want %v", got, want)
36 }
37 })
38 }
39
40 func TestRunEmpty(t *testing.T) {
41 synctest.Run(func() {
42 })
43 }
44
45 func TestSimpleWait(t *testing.T) {
46 synctest.Run(func() {
47 synctest.Wait()
48 })
49 }
50
51 func TestGoroutineWait(t *testing.T) {
52 synctest.Run(func() {
53 go func() {}()
54 synctest.Wait()
55 })
56 }
57
58
59
60 func TestWait(t *testing.T) {
61 synctest.Run(func() {
62 done := false
63 ch := make(chan int)
64 var f func()
65 f = func() {
66 count := <-ch
67 if count == 0 {
68 done = true
69 } else {
70 go f()
71 ch <- count - 1
72 }
73 }
74 go f()
75 ch <- 100
76 synctest.Wait()
77 if !done {
78 t.Fatalf("done = false, want true")
79 }
80 })
81 }
82
83 func TestMallocs(t *testing.T) {
84 for i := 0; i < 100; i++ {
85 synctest.Run(func() {
86 done := false
87 ch := make(chan []byte)
88 var f func()
89 f = func() {
90 b := <-ch
91 if len(b) == 0 {
92 done = true
93 } else {
94 go f()
95 ch <- make([]byte, len(b)-1)
96 }
97 }
98 go f()
99 ch <- make([]byte, 100)
100 synctest.Wait()
101 if !done {
102 t.Fatalf("done = false, want true")
103 }
104 })
105 }
106 }
107
108 func TestTimerReadBeforeDeadline(t *testing.T) {
109 synctest.Run(func() {
110 start := time.Now()
111 tm := time.NewTimer(5 * time.Second)
112 <-tm.C
113 if got, want := time.Since(start), 5*time.Second; got != want {
114 t.Errorf("after sleep: time.Since(start) = %v, want %v", got, want)
115 }
116 })
117 }
118
119 func TestTimerReadAfterDeadline(t *testing.T) {
120 synctest.Run(func() {
121 delay := 1 * time.Second
122 want := time.Now().Add(delay)
123 tm := time.NewTimer(delay)
124 time.Sleep(2 * delay)
125 got := <-tm.C
126 if got != want {
127 t.Errorf("<-tm.C = %v, want %v", got, want)
128 }
129 })
130 }
131
132 func TestTimerReset(t *testing.T) {
133 synctest.Run(func() {
134 start := time.Now()
135 tm := time.NewTimer(1 * time.Second)
136 if got, want := <-tm.C, start.Add(1*time.Second); got != want {
137 t.Errorf("first sleep: <-tm.C = %v, want %v", got, want)
138 }
139
140 tm.Reset(2 * time.Second)
141 if got, want := <-tm.C, start.Add((1+2)*time.Second); got != want {
142 t.Errorf("second sleep: <-tm.C = %v, want %v", got, want)
143 }
144
145 tm.Reset(3 * time.Second)
146 time.Sleep(1 * time.Second)
147 tm.Reset(3 * time.Second)
148 if got, want := <-tm.C, start.Add((1+2+4)*time.Second); got != want {
149 t.Errorf("third sleep: <-tm.C = %v, want %v", got, want)
150 }
151 })
152 }
153
154 func TestTimeAfter(t *testing.T) {
155 synctest.Run(func() {
156 i := 0
157 time.AfterFunc(1*time.Second, func() {
158
159 i++
160 go func() {
161 time.Sleep(1 * time.Second)
162 i++
163 }()
164 })
165 time.Sleep(3 * time.Second)
166 synctest.Wait()
167 if got, want := i, 2; got != want {
168 t.Errorf("after sleep and wait: i = %v, want %v", got, want)
169 }
170 })
171 }
172
173 func TestTimerFromOutsideBubble(t *testing.T) {
174 tm := time.NewTimer(10 * time.Millisecond)
175 synctest.Run(func() {
176 <-tm.C
177 })
178 if tm.Stop() {
179 t.Errorf("synctest.Run unexpectedly returned before timer fired")
180 }
181 }
182
183 func TestChannelFromOutsideBubble(t *testing.T) {
184 choutside := make(chan struct{})
185 for _, test := range []struct {
186 desc string
187 outside func(ch chan int)
188 inside func(ch chan int)
189 }{{
190 desc: "read closed",
191 outside: func(ch chan int) { close(ch) },
192 inside: func(ch chan int) { <-ch },
193 }, {
194 desc: "read value",
195 outside: func(ch chan int) { ch <- 0 },
196 inside: func(ch chan int) { <-ch },
197 }, {
198 desc: "write value",
199 outside: func(ch chan int) { <-ch },
200 inside: func(ch chan int) { ch <- 0 },
201 }, {
202 desc: "select outside only",
203 outside: func(ch chan int) { close(ch) },
204 inside: func(ch chan int) {
205 select {
206 case <-ch:
207 case <-choutside:
208 }
209 },
210 }, {
211 desc: "select mixed",
212 outside: func(ch chan int) { close(ch) },
213 inside: func(ch chan int) {
214 ch2 := make(chan struct{})
215 select {
216 case <-ch:
217 case <-ch2:
218 }
219 },
220 }} {
221 t.Run(test.desc, func(t *testing.T) {
222 ch := make(chan int)
223 time.AfterFunc(1*time.Millisecond, func() {
224 test.outside(ch)
225 })
226 synctest.Run(func() {
227 test.inside(ch)
228 })
229 })
230 }
231 }
232
233 func TestTimerFromInsideBubble(t *testing.T) {
234 for _, test := range []struct {
235 desc string
236 f func(tm *time.Timer)
237 wantPanic string
238 }{{
239 desc: "read channel",
240 f: func(tm *time.Timer) {
241 <-tm.C
242 },
243 wantPanic: "receive on synctest channel from outside bubble",
244 }, {
245 desc: "Reset",
246 f: func(tm *time.Timer) {
247 tm.Reset(1 * time.Second)
248 },
249 wantPanic: "reset of synctest timer from outside bubble",
250 }, {
251 desc: "Stop",
252 f: func(tm *time.Timer) {
253 tm.Stop()
254 },
255 wantPanic: "stop of synctest timer from outside bubble",
256 }} {
257 t.Run(test.desc, func(t *testing.T) {
258 donec := make(chan struct{})
259 ch := make(chan *time.Timer)
260 go func() {
261 defer close(donec)
262 defer wantPanic(t, test.wantPanic)
263 test.f(<-ch)
264 }()
265 synctest.Run(func() {
266 tm := time.NewTimer(1 * time.Second)
267 ch <- tm
268 })
269 <-donec
270 })
271 }
272 }
273
274 func TestDeadlockRoot(t *testing.T) {
275 defer wantPanic(t, "deadlock: all goroutines in bubble are blocked")
276 synctest.Run(func() {
277 select {}
278 })
279 }
280
281 func TestDeadlockChild(t *testing.T) {
282 defer wantPanic(t, "deadlock: all goroutines in bubble are blocked")
283 synctest.Run(func() {
284 go func() {
285 select {}
286 }()
287 })
288 }
289
290 func TestCond(t *testing.T) {
291 synctest.Run(func() {
292 var mu sync.Mutex
293 cond := sync.NewCond(&mu)
294 start := time.Now()
295 const waitTime = 1 * time.Millisecond
296
297 go func() {
298
299 time.Sleep(waitTime)
300 mu.Lock()
301 cond.Signal()
302 mu.Unlock()
303
304
305 time.Sleep(waitTime)
306 mu.Lock()
307 cond.Broadcast()
308 mu.Unlock()
309 }()
310
311
312 mu.Lock()
313 cond.Wait()
314 mu.Unlock()
315 if got, want := time.Since(start), waitTime; got != want {
316 t.Errorf("after cond.Signal: time elapsed = %v, want %v", got, want)
317 }
318
319
320 waiterDone := false
321 go func() {
322 mu.Lock()
323 cond.Wait()
324 mu.Unlock()
325 waiterDone = true
326 }()
327 mu.Lock()
328 cond.Wait()
329 mu.Unlock()
330 synctest.Wait()
331 if !waiterDone {
332 t.Errorf("after cond.Broadcast: waiter not done")
333 }
334 if got, want := time.Since(start), 2*waitTime; got != want {
335 t.Errorf("after cond.Broadcast: time elapsed = %v, want %v", got, want)
336 }
337 })
338 }
339
340 func TestIteratorPush(t *testing.T) {
341 synctest.Run(func() {
342 seq := func(yield func(time.Time) bool) {
343 for yield(time.Now()) {
344 time.Sleep(1 * time.Second)
345 }
346 }
347 var got []time.Time
348 go func() {
349 for now := range seq {
350 got = append(got, now)
351 if len(got) >= 3 {
352 break
353 }
354 }
355 }()
356 want := []time.Time{
357 time.Now(),
358 time.Now().Add(1 * time.Second),
359 time.Now().Add(2 * time.Second),
360 }
361 time.Sleep(5 * time.Second)
362 synctest.Wait()
363 if !slices.Equal(got, want) {
364 t.Errorf("got: %v; want: %v", got, want)
365 }
366 })
367 }
368
369 func TestIteratorPull(t *testing.T) {
370 synctest.Run(func() {
371 seq := func(yield func(time.Time) bool) {
372 for yield(time.Now()) {
373 time.Sleep(1 * time.Second)
374 }
375 }
376 var got []time.Time
377 go func() {
378 next, stop := iter.Pull(seq)
379 defer stop()
380 for len(got) < 3 {
381 now, _ := next()
382 got = append(got, now)
383 }
384 }()
385 want := []time.Time{
386 time.Now(),
387 time.Now().Add(1 * time.Second),
388 time.Now().Add(2 * time.Second),
389 }
390 time.Sleep(5 * time.Second)
391 synctest.Wait()
392 if !slices.Equal(got, want) {
393 t.Errorf("got: %v; want: %v", got, want)
394 }
395 })
396 }
397
398 func TestReflectFuncOf(t *testing.T) {
399 mkfunc := func(name string, i int) {
400 reflect.FuncOf([]reflect.Type{
401 reflect.StructOf([]reflect.StructField{{
402 Name: name + strconv.Itoa(i),
403 Type: reflect.TypeOf(0),
404 }}),
405 }, nil, false)
406 }
407 go func() {
408 for i := 0; i < 100000; i++ {
409 mkfunc("A", i)
410 }
411 }()
412 synctest.Run(func() {
413 for i := 0; i < 100000; i++ {
414 mkfunc("A", i)
415 }
416 })
417 }
418
419 func TestWaitGroup(t *testing.T) {
420 synctest.Run(func() {
421 var wg sync.WaitGroup
422 wg.Add(1)
423 const delay = 1 * time.Second
424 go func() {
425 time.Sleep(delay)
426 wg.Done()
427 }()
428 start := time.Now()
429 wg.Wait()
430 if got := time.Since(start); got != delay {
431 t.Fatalf("WaitGroup.Wait() took %v, want %v", got, delay)
432 }
433 })
434 }
435
436 func wantPanic(t *testing.T, want string) {
437 if e := recover(); e != nil {
438 if got := fmt.Sprint(e); got != want {
439 t.Errorf("got panic message %q, want %q", got, want)
440 }
441 } else {
442 t.Errorf("got no panic, want one")
443 }
444 }
445
View as plain text