blob: 7a6bc92a5b91c630d4f58bd75ee9840e46c99fd2 [file] [log] [blame]
Tilak Sharma6d7c39c2014-06-27 10:05:37 -07001package sync
2
3import (
4 "testing"
5 "veyron/lib/testutil"
6)
7
8// TestRandom tests Wait after a random sequence of TryAdd's and Done's that
9// leaves the counter at 0.
10func TestRandom(t *testing.T) {
11 var w WaitGroup
12 N := 100
13
14 count := 0
15 for n := 0; n < N; n++ {
16 if count == 0 || testutil.Rand.Intn(2) == 0 {
17 if !w.TryAdd() {
18 t.Fatal("TryAdd failed")
19 }
20 count++
21 continue
22 }
23 w.Done()
24 count--
25 }
26 for d := 0; d < count; d++ {
27 w.Done()
28 }
29
30 w.Wait()
31}
32
33func TestConcurrentWait(t *testing.T) {
34 for r := 0; r < 100; r++ {
35 var w WaitGroup
36
37 done := make(chan struct{}, 1)
38
39 if !w.TryAdd() {
40 t.Fatal("TryAdd failed")
41 }
42
43 go func() {
44 w.Wait()
45 // w.Wait() should not return before w.Done() sets the counter
46 // to 0.
47 // This test is not deterministic as we cannot infer the order
48 // in which Wait() and the last Done() return. Hopefully, bugs
49 // will revealed by repeating the test.
50 select {
51 case <-done:
52 default:
53 t.Fatal("Wait returned before Done.")
54 }
55 }()
56
57 for w.TryAdd() {
58 w.Done()
59 }
60 close(done)
61 w.Done()
62 }
63}
64
65func TestTryAddFailsAfterWait(t *testing.T) {
66 var w WaitGroup
67
68 if !w.TryAdd() {
69 t.Fatal("TryAdd failed")
70 }
71
72 go w.Wait()
73
74 // At some point, another goroutine will be in w.Wait() and w.TryAdd()
75 // should fail. If this doesn't happen, the test will never terminate.
76 for w.TryAdd() {
77 w.Done()
78 }
79 w.Done()
80}
81
82func TestIdempotentWait(t *testing.T) {
83 var w WaitGroup
84
85 done := make(chan struct{}, 1)
86
87 if !w.TryAdd() {
88 t.Fatal("TryAdd failed")
89 }
90
91 // w.Wait() should be idempotent.
92 for i := 0; i < 2; i++ {
93 go func() {
94 w.Wait()
95 select {
96 case <-done:
97 default:
98 t.Fatal("Wait returned before Done.")
99 }
100 }()
101 }
102
103 for w.TryAdd() {
104 w.Done()
105 }
106 close(done)
107 w.Done()
108}
109
110func TestDoneFailsBeforeAdd(t *testing.T) {
111 var w WaitGroup
112 defer func() {
113 if r := recover(); r == nil {
114 t.Fatal("Done succeeded before Add.")
115 }
116 }()
117 w.Done()
118}