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 TestTimer(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 TestTimeAfter(t *testing.T) {
120 synctest.Run(func() {
121 i := 0
122 time.AfterFunc(1*time.Second, func() {
123
124 i++
125 go func() {
126 time.Sleep(1 * time.Second)
127 i++
128 }()
129 })
130 time.Sleep(3 * time.Second)
131 synctest.Wait()
132 if got, want := i, 2; got != want {
133 t.Errorf("after sleep and wait: i = %v, want %v", got, want)
134 }
135 })
136 }
137
138 func TestTimerFromOutsideBubble(t *testing.T) {
139 tm := time.NewTimer(10 * time.Millisecond)
140 synctest.Run(func() {
141 defer wantPanic(t, "timer moved between synctest groups")
142 <-tm.C
143 })
144 }
145
146 func TestChannelFromOutsideBubble(t *testing.T) {
147 choutside := make(chan struct{})
148 for _, test := range []struct {
149 desc string
150 outside func(ch chan int)
151 inside func(ch chan int)
152 }{{
153 desc: "read closed",
154 outside: func(ch chan int) { close(ch) },
155 inside: func(ch chan int) { <-ch },
156 }, {
157 desc: "read value",
158 outside: func(ch chan int) { ch <- 0 },
159 inside: func(ch chan int) { <-ch },
160 }, {
161 desc: "write value",
162 outside: func(ch chan int) { <-ch },
163 inside: func(ch chan int) { ch <- 0 },
164 }, {
165 desc: "select outside only",
166 outside: func(ch chan int) { close(ch) },
167 inside: func(ch chan int) {
168 select {
169 case <-ch:
170 case <-choutside:
171 }
172 },
173 }, {
174 desc: "select mixed",
175 outside: func(ch chan int) { close(ch) },
176 inside: func(ch chan int) {
177 ch2 := make(chan struct{})
178 select {
179 case <-ch:
180 case <-ch2:
181 }
182 },
183 }} {
184 t.Run(test.desc, func(t *testing.T) {
185 ch := make(chan int)
186 time.AfterFunc(1*time.Millisecond, func() {
187 test.outside(ch)
188 })
189 synctest.Run(func() {
190 test.inside(ch)
191 })
192 })
193 }
194 }
195
196 func TestTimerFromInsideBubble(t *testing.T) {
197 for _, test := range []struct {
198 desc string
199 f func(tm *time.Timer)
200 wantPanic string
201 }{{
202 desc: "read channel",
203 f: func(tm *time.Timer) {
204 <-tm.C
205 },
206 wantPanic: "receive on synctest channel from outside bubble",
207 }, {
208 desc: "Reset",
209 f: func(tm *time.Timer) {
210 tm.Reset(1 * time.Second)
211 },
212 wantPanic: "reset of synctest timer from outside bubble",
213 }, {
214 desc: "Stop",
215 f: func(tm *time.Timer) {
216 tm.Stop()
217 },
218 wantPanic: "stop of synctest timer from outside bubble",
219 }} {
220 t.Run(test.desc, func(t *testing.T) {
221 donec := make(chan struct{})
222 ch := make(chan *time.Timer)
223 go func() {
224 defer close(donec)
225 defer wantPanic(t, test.wantPanic)
226 test.f(<-ch)
227 }()
228 synctest.Run(func() {
229 tm := time.NewTimer(1 * time.Second)
230 ch <- tm
231 })
232 <-donec
233 })
234 }
235 }
236
237 func TestDeadlockRoot(t *testing.T) {
238 defer wantPanic(t, "deadlock: all goroutines in bubble are blocked")
239 synctest.Run(func() {
240 select {}
241 })
242 }
243
244 func TestDeadlockChild(t *testing.T) {
245 defer wantPanic(t, "deadlock: all goroutines in bubble are blocked")
246 synctest.Run(func() {
247 go func() {
248 select {}
249 }()
250 })
251 }
252
253 func TestCond(t *testing.T) {
254 synctest.Run(func() {
255 var mu sync.Mutex
256 cond := sync.NewCond(&mu)
257 start := time.Now()
258 const waitTime = 1 * time.Millisecond
259
260 go func() {
261
262 time.Sleep(waitTime)
263 mu.Lock()
264 cond.Signal()
265 mu.Unlock()
266
267
268 time.Sleep(waitTime)
269 mu.Lock()
270 cond.Broadcast()
271 mu.Unlock()
272 }()
273
274
275 mu.Lock()
276 cond.Wait()
277 mu.Unlock()
278 if got, want := time.Since(start), waitTime; got != want {
279 t.Errorf("after cond.Signal: time elapsed = %v, want %v", got, want)
280 }
281
282
283 waiterDone := false
284 go func() {
285 mu.Lock()
286 cond.Wait()
287 mu.Unlock()
288 waiterDone = true
289 }()
290 mu.Lock()
291 cond.Wait()
292 mu.Unlock()
293 synctest.Wait()
294 if !waiterDone {
295 t.Errorf("after cond.Broadcast: waiter not done")
296 }
297 if got, want := time.Since(start), 2*waitTime; got != want {
298 t.Errorf("after cond.Broadcast: time elapsed = %v, want %v", got, want)
299 }
300 })
301 }
302
303 func TestIteratorPush(t *testing.T) {
304 synctest.Run(func() {
305 seq := func(yield func(time.Time) bool) {
306 for yield(time.Now()) {
307 time.Sleep(1 * time.Second)
308 }
309 }
310 var got []time.Time
311 go func() {
312 for now := range seq {
313 got = append(got, now)
314 if len(got) >= 3 {
315 break
316 }
317 }
318 }()
319 want := []time.Time{
320 time.Now(),
321 time.Now().Add(1 * time.Second),
322 time.Now().Add(2 * time.Second),
323 }
324 time.Sleep(5 * time.Second)
325 synctest.Wait()
326 if !slices.Equal(got, want) {
327 t.Errorf("got: %v; want: %v", got, want)
328 }
329 })
330 }
331
332 func TestIteratorPull(t *testing.T) {
333 synctest.Run(func() {
334 seq := func(yield func(time.Time) bool) {
335 for yield(time.Now()) {
336 time.Sleep(1 * time.Second)
337 }
338 }
339 var got []time.Time
340 go func() {
341 next, stop := iter.Pull(seq)
342 defer stop()
343 for len(got) < 3 {
344 now, _ := next()
345 got = append(got, now)
346 }
347 }()
348 want := []time.Time{
349 time.Now(),
350 time.Now().Add(1 * time.Second),
351 time.Now().Add(2 * time.Second),
352 }
353 time.Sleep(5 * time.Second)
354 synctest.Wait()
355 if !slices.Equal(got, want) {
356 t.Errorf("got: %v; want: %v", got, want)
357 }
358 })
359 }
360
361 func TestReflectFuncOf(t *testing.T) {
362 mkfunc := func(name string, i int) {
363 reflect.FuncOf([]reflect.Type{
364 reflect.StructOf([]reflect.StructField{{
365 Name: name + strconv.Itoa(i),
366 Type: reflect.TypeOf(0),
367 }}),
368 }, nil, false)
369 }
370 go func() {
371 for i := 0; i < 100000; i++ {
372 mkfunc("A", i)
373 }
374 }()
375 synctest.Run(func() {
376 for i := 0; i < 100000; i++ {
377 mkfunc("A", i)
378 }
379 })
380 }
381
382 func TestWaitGroup(t *testing.T) {
383 synctest.Run(func() {
384 var wg sync.WaitGroup
385 wg.Add(1)
386 const delay = 1 * time.Second
387 go func() {
388 time.Sleep(delay)
389 wg.Done()
390 }()
391 start := time.Now()
392 wg.Wait()
393 if got := time.Since(start); got != delay {
394 t.Fatalf("WaitGroup.Wait() took %v, want %v", got, delay)
395 }
396 })
397 }
398
399 func wantPanic(t *testing.T, want string) {
400 if e := recover(); e != nil {
401 if got := fmt.Sprint(e); got != want {
402 t.Errorf("got panic message %q, want %q", got, want)
403 }
404 } else {
405 t.Errorf("got no panic, want one")
406 }
407 }
408
View as plain text