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
41
42 func TestMonotonicClock(t *testing.T) {
43 start := time.Now()
44 synctest.Run(func() {
45 time.Sleep(time.Until(start.Round(0)))
46 if got, want := time.Now().In(time.UTC), start.In(time.UTC); !got.Equal(want) {
47 t.Fatalf("time.Now() = %v, want %v", got, want)
48 }
49
50 wait := 1 * time.Second
51 time.Sleep(wait)
52 if got := time.Since(start); got != wait {
53 t.Fatalf("time.Since(start) = %v, want %v", got, wait)
54 }
55 if got := time.Now().Sub(start); got != wait {
56 t.Fatalf("time.Now().Sub(start) = %v, want %v", got, wait)
57 }
58 })
59 }
60
61 func TestRunEmpty(t *testing.T) {
62 synctest.Run(func() {
63 })
64 }
65
66 func TestSimpleWait(t *testing.T) {
67 synctest.Run(func() {
68 synctest.Wait()
69 })
70 }
71
72 func TestGoroutineWait(t *testing.T) {
73 synctest.Run(func() {
74 go func() {}()
75 synctest.Wait()
76 })
77 }
78
79
80
81 func TestWait(t *testing.T) {
82 synctest.Run(func() {
83 done := false
84 ch := make(chan int)
85 var f func()
86 f = func() {
87 count := <-ch
88 if count == 0 {
89 done = true
90 } else {
91 go f()
92 ch <- count - 1
93 }
94 }
95 go f()
96 ch <- 100
97 synctest.Wait()
98 if !done {
99 t.Fatalf("done = false, want true")
100 }
101 })
102 }
103
104 func TestMallocs(t *testing.T) {
105 for i := 0; i < 100; i++ {
106 synctest.Run(func() {
107 done := false
108 ch := make(chan []byte)
109 var f func()
110 f = func() {
111 b := <-ch
112 if len(b) == 0 {
113 done = true
114 } else {
115 go f()
116 ch <- make([]byte, len(b)-1)
117 }
118 }
119 go f()
120 ch <- make([]byte, 100)
121 synctest.Wait()
122 if !done {
123 t.Fatalf("done = false, want true")
124 }
125 })
126 }
127 }
128
129 func TestTimerReadBeforeDeadline(t *testing.T) {
130 synctest.Run(func() {
131 start := time.Now()
132 tm := time.NewTimer(5 * time.Second)
133 <-tm.C
134 if got, want := time.Since(start), 5*time.Second; got != want {
135 t.Errorf("after sleep: time.Since(start) = %v, want %v", got, want)
136 }
137 })
138 }
139
140 func TestTimerReadAfterDeadline(t *testing.T) {
141 synctest.Run(func() {
142 delay := 1 * time.Second
143 want := time.Now().Add(delay)
144 tm := time.NewTimer(delay)
145 time.Sleep(2 * delay)
146 got := <-tm.C
147 if got != want {
148 t.Errorf("<-tm.C = %v, want %v", got, want)
149 }
150 })
151 }
152
153 func TestTimerReset(t *testing.T) {
154 synctest.Run(func() {
155 start := time.Now()
156 tm := time.NewTimer(1 * time.Second)
157 if got, want := <-tm.C, start.Add(1*time.Second); got != want {
158 t.Errorf("first sleep: <-tm.C = %v, want %v", got, want)
159 }
160
161 tm.Reset(2 * time.Second)
162 if got, want := <-tm.C, start.Add((1+2)*time.Second); got != want {
163 t.Errorf("second sleep: <-tm.C = %v, want %v", got, want)
164 }
165
166 tm.Reset(3 * time.Second)
167 time.Sleep(1 * time.Second)
168 tm.Reset(3 * time.Second)
169 if got, want := <-tm.C, start.Add((1+2+4)*time.Second); got != want {
170 t.Errorf("third sleep: <-tm.C = %v, want %v", got, want)
171 }
172 })
173 }
174
175 func TestTimeAfter(t *testing.T) {
176 synctest.Run(func() {
177 i := 0
178 time.AfterFunc(1*time.Second, func() {
179
180 i++
181 go func() {
182 time.Sleep(1 * time.Second)
183 i++
184 }()
185 })
186 time.Sleep(3 * time.Second)
187 synctest.Wait()
188 if got, want := i, 2; got != want {
189 t.Errorf("after sleep and wait: i = %v, want %v", got, want)
190 }
191 })
192 }
193
194 func TestTimerFromOutsideBubble(t *testing.T) {
195 tm := time.NewTimer(10 * time.Millisecond)
196 synctest.Run(func() {
197 <-tm.C
198 })
199 if tm.Stop() {
200 t.Errorf("synctest.Run unexpectedly returned before timer fired")
201 }
202 }
203
204 func TestChannelFromOutsideBubble(t *testing.T) {
205 choutside := make(chan struct{})
206 for _, test := range []struct {
207 desc string
208 outside func(ch chan int)
209 inside func(ch chan int)
210 }{{
211 desc: "read closed",
212 outside: func(ch chan int) { close(ch) },
213 inside: func(ch chan int) { <-ch },
214 }, {
215 desc: "read value",
216 outside: func(ch chan int) { ch <- 0 },
217 inside: func(ch chan int) { <-ch },
218 }, {
219 desc: "write value",
220 outside: func(ch chan int) { <-ch },
221 inside: func(ch chan int) { ch <- 0 },
222 }, {
223 desc: "select outside only",
224 outside: func(ch chan int) { close(ch) },
225 inside: func(ch chan int) {
226 select {
227 case <-ch:
228 case <-choutside:
229 }
230 },
231 }, {
232 desc: "select mixed",
233 outside: func(ch chan int) { close(ch) },
234 inside: func(ch chan int) {
235 ch2 := make(chan struct{})
236 select {
237 case <-ch:
238 case <-ch2:
239 }
240 },
241 }} {
242 t.Run(test.desc, func(t *testing.T) {
243 ch := make(chan int)
244 time.AfterFunc(1*time.Millisecond, func() {
245 test.outside(ch)
246 })
247 synctest.Run(func() {
248 test.inside(ch)
249 })
250 })
251 }
252 }
253
254 func TestTimerFromInsideBubble(t *testing.T) {
255 for _, test := range []struct {
256 desc string
257 f func(tm *time.Timer)
258 wantPanic string
259 }{{
260 desc: "read channel",
261 f: func(tm *time.Timer) {
262 <-tm.C
263 },
264 wantPanic: "receive on synctest channel from outside bubble",
265 }, {
266 desc: "Reset",
267 f: func(tm *time.Timer) {
268 tm.Reset(1 * time.Second)
269 },
270 wantPanic: "reset of synctest timer from outside bubble",
271 }, {
272 desc: "Stop",
273 f: func(tm *time.Timer) {
274 tm.Stop()
275 },
276 wantPanic: "stop of synctest timer from outside bubble",
277 }} {
278 t.Run(test.desc, func(t *testing.T) {
279 donec := make(chan struct{})
280 ch := make(chan *time.Timer)
281 go func() {
282 defer close(donec)
283 defer wantPanic(t, test.wantPanic)
284 test.f(<-ch)
285 }()
286 synctest.Run(func() {
287 tm := time.NewTimer(1 * time.Second)
288 ch <- tm
289 })
290 <-donec
291 })
292 }
293 }
294
295 func TestDeadlockRoot(t *testing.T) {
296 defer wantPanic(t, "deadlock: all goroutines in bubble are blocked")
297 synctest.Run(func() {
298 select {}
299 })
300 }
301
302 func TestDeadlockChild(t *testing.T) {
303 defer wantPanic(t, "deadlock: all goroutines in bubble are blocked")
304 synctest.Run(func() {
305 go func() {
306 select {}
307 }()
308 })
309 }
310
311 func TestCond(t *testing.T) {
312 synctest.Run(func() {
313 var mu sync.Mutex
314 cond := sync.NewCond(&mu)
315 start := time.Now()
316 const waitTime = 1 * time.Millisecond
317
318 go func() {
319
320 time.Sleep(waitTime)
321 mu.Lock()
322 cond.Signal()
323 mu.Unlock()
324
325
326 time.Sleep(waitTime)
327 mu.Lock()
328 cond.Broadcast()
329 mu.Unlock()
330 }()
331
332
333 mu.Lock()
334 cond.Wait()
335 mu.Unlock()
336 if got, want := time.Since(start), waitTime; got != want {
337 t.Errorf("after cond.Signal: time elapsed = %v, want %v", got, want)
338 }
339
340
341 waiterDone := false
342 go func() {
343 mu.Lock()
344 cond.Wait()
345 mu.Unlock()
346 waiterDone = true
347 }()
348 mu.Lock()
349 cond.Wait()
350 mu.Unlock()
351 synctest.Wait()
352 if !waiterDone {
353 t.Errorf("after cond.Broadcast: waiter not done")
354 }
355 if got, want := time.Since(start), 2*waitTime; got != want {
356 t.Errorf("after cond.Broadcast: time elapsed = %v, want %v", got, want)
357 }
358 })
359 }
360
361 func TestIteratorPush(t *testing.T) {
362 synctest.Run(func() {
363 seq := func(yield func(time.Time) bool) {
364 for yield(time.Now()) {
365 time.Sleep(1 * time.Second)
366 }
367 }
368 var got []time.Time
369 go func() {
370 for now := range seq {
371 got = append(got, now)
372 if len(got) >= 3 {
373 break
374 }
375 }
376 }()
377 want := []time.Time{
378 time.Now(),
379 time.Now().Add(1 * time.Second),
380 time.Now().Add(2 * time.Second),
381 }
382 time.Sleep(5 * time.Second)
383 synctest.Wait()
384 if !slices.Equal(got, want) {
385 t.Errorf("got: %v; want: %v", got, want)
386 }
387 })
388 }
389
390 func TestIteratorPull(t *testing.T) {
391 synctest.Run(func() {
392 seq := func(yield func(time.Time) bool) {
393 for yield(time.Now()) {
394 time.Sleep(1 * time.Second)
395 }
396 }
397 var got []time.Time
398 go func() {
399 next, stop := iter.Pull(seq)
400 defer stop()
401 for len(got) < 3 {
402 now, _ := next()
403 got = append(got, now)
404 }
405 }()
406 want := []time.Time{
407 time.Now(),
408 time.Now().Add(1 * time.Second),
409 time.Now().Add(2 * time.Second),
410 }
411 time.Sleep(5 * time.Second)
412 synctest.Wait()
413 if !slices.Equal(got, want) {
414 t.Errorf("got: %v; want: %v", got, want)
415 }
416 })
417 }
418
419 func TestReflectFuncOf(t *testing.T) {
420 mkfunc := func(name string, i int) {
421 reflect.FuncOf([]reflect.Type{
422 reflect.StructOf([]reflect.StructField{{
423 Name: name + strconv.Itoa(i),
424 Type: reflect.TypeOf(0),
425 }}),
426 }, nil, false)
427 }
428 go func() {
429 for i := 0; i < 100000; i++ {
430 mkfunc("A", i)
431 }
432 }()
433 synctest.Run(func() {
434 for i := 0; i < 100000; i++ {
435 mkfunc("A", i)
436 }
437 })
438 }
439
440 func TestWaitGroup(t *testing.T) {
441 synctest.Run(func() {
442 var wg sync.WaitGroup
443 wg.Add(1)
444 const delay = 1 * time.Second
445 go func() {
446 time.Sleep(delay)
447 wg.Done()
448 }()
449 start := time.Now()
450 wg.Wait()
451 if got := time.Since(start); got != delay {
452 t.Fatalf("WaitGroup.Wait() took %v, want %v", got, delay)
453 }
454 })
455 }
456
457 func TestHappensBefore(t *testing.T) {
458
459
460 var v1 int
461 var v2 int
462 synctest.Run(func() {
463 v1++
464 v2++
465
466
467 go func() {
468 v1++
469 }()
470 go func() {
471 v2++
472 }()
473 synctest.Wait()
474
475 v1++
476 v2++
477
478
479 ch1 := make(chan struct{})
480 go func() {
481 v1++
482 <-ch1
483 }()
484 go func() {
485 v2++
486 <-ch1
487 }()
488 synctest.Wait()
489
490 v1++
491 v2++
492 close(ch1)
493
494
495 time.AfterFunc(0, func() {
496 v1++
497 })
498 time.AfterFunc(0, func() {
499 v2++
500 })
501 synctest.Wait()
502
503 v1++
504 v2++
505
506
507 ch2 := make(chan struct{})
508 time.AfterFunc(0, func() {
509 v1++
510 <-ch2
511 })
512 time.AfterFunc(0, func() {
513 v2++
514 <-ch2
515 })
516 synctest.Wait()
517
518 v1++
519 v2++
520 close(ch2)
521 })
522
523 synctest.Run(func() {
524 go func() {
525 go func() {
526 v1++
527 }()
528 }()
529 go func() {
530 go func() {
531 v2++
532 }()
533 }()
534 })
535
536 if got, want := v1, 10; got != want {
537 t.Errorf("v1 = %v, want %v", got, want)
538 }
539 if got, want := v2, 10; got != want {
540 t.Errorf("v2 = %v, want %v", got, want)
541 }
542 }
543
544 func wantPanic(t *testing.T, want string) {
545 if e := recover(); e != nil {
546 if got := fmt.Sprint(e); got != want {
547 t.Errorf("got panic message %q, want %q", got, want)
548 }
549 } else {
550 t.Errorf("got no panic, want one")
551 }
552 }
553
View as plain text