1
15 package syncutil
16
17 import (
18 "context"
19 "errors"
20 "io"
21 "reflect"
22 "strconv"
23 "sync"
24 "testing"
25 "time"
26 )
27
28 func TestOnce_Do(t *testing.T) {
29 var f []func() (interface{}, error)
30 for i := 0; i < 100; i++ {
31 f = append(f, func(i int) func() (interface{}, error) {
32 return func() (interface{}, error) {
33 return i + 1, errors.New(strconv.Itoa(i))
34 }
35 }(i))
36 }
37
38 once := NewOnce()
39 first := make([]bool, len(f))
40 result := make([]interface{}, len(f))
41 err := make([]error, len(f))
42 var wg sync.WaitGroup
43 for i := 0; i < len(f); i++ {
44 wg.Add(1)
45 go func(i int) {
46 defer wg.Done()
47 ctx := context.Background()
48 first[i], result[i], err[i] = once.Do(ctx, f[i])
49 }(i)
50 }
51 wg.Wait()
52
53 target := 0
54 for i := 0; i < len(f); i++ {
55 if first[i] {
56 target = i
57 break
58 }
59 }
60 targetErr := err[target]
61 if targetErr == nil || targetErr.Error() != strconv.Itoa(target) {
62 t.Errorf("Once.Do(%d) error = %v, wantErr %v", target, targetErr, strconv.Itoa(target))
63 }
64
65 wantResult := target + 1
66 wantErr := targetErr
67 for i := 0; i < len(f); i++ {
68 wantFirst := false
69 if i == target {
70 wantFirst = true
71 }
72 if first[i] != wantFirst {
73 t.Errorf("Once.Do(%d) first = %v, want %v", i, first[i], wantFirst)
74 }
75 if err[i] != wantErr {
76 t.Errorf("Once.Do(%d) error = %v, wantErr %v", i, err[i], wantErr)
77 }
78 if !reflect.DeepEqual(result[i], wantResult) {
79 t.Errorf("Once.Do(%d) result = %v, want %v", i, result[i], wantResult)
80 }
81 }
82 }
83
84 func TestOnce_Do_Cancel_Context(t *testing.T) {
85 once := NewOnce()
86
87 var wg sync.WaitGroup
88 var (
89 first bool
90 result interface{}
91 err error
92 )
93 wg.Add(1)
94 go func() {
95 defer wg.Done()
96 ctx := context.Background()
97 first, result, err = once.Do(ctx, func() (interface{}, error) {
98 time.Sleep(200 * time.Millisecond)
99 return "foo", io.EOF
100 })
101 }()
102 time.Sleep(100 * time.Millisecond)
103 ctx := context.Background()
104 ctx, cancel := context.WithCancel(ctx)
105 cancel()
106 first2, result2, err2 := once.Do(ctx, func() (interface{}, error) {
107 return "bar", nil
108 })
109 wg.Wait()
110
111 if wantFirst := true; first != wantFirst {
112 t.Fatalf("Once.Do() first = %v, want %v", first, wantFirst)
113 }
114 if wantErr := io.EOF; err != wantErr {
115 t.Fatalf("Once.Do() error = %v, wantErr %v", err, wantErr)
116 }
117 if wantResult := "foo"; !reflect.DeepEqual(result, wantResult) {
118 t.Fatalf("Once.Do() result = %v, want %v", result, wantResult)
119 }
120
121 if wantFirst := false; first2 != wantFirst {
122 t.Fatalf("Once.Do() first = %v, want %v", first2, wantFirst)
123 }
124 if wantErr := context.Canceled; err2 != wantErr {
125 t.Fatalf("Once.Do() error = %v, wantErr %v", err2, wantErr)
126 }
127 if wantResult := interface{}(nil); !reflect.DeepEqual(result2, wantResult) {
128 t.Fatalf("Once.Do() result = %v, want %v", result2, wantResult)
129 }
130 }
131
132 func TestOnce_Do_Cancel_Function(t *testing.T) {
133 ctx := context.Background()
134 once := NewOnce()
135
136 first, result, err := once.Do(ctx, func() (interface{}, error) {
137 return "foo", context.Canceled
138 })
139 if wantFirst := false; first != wantFirst {
140 t.Fatalf("Once.Do() first = %v, want %v", first, wantFirst)
141 }
142 if wantErr := context.Canceled; err != wantErr {
143 t.Fatalf("Once.Do() error = %v, wantErr %v", err, wantErr)
144 }
145 if wantResult := interface{}(nil); !reflect.DeepEqual(result, wantResult) {
146 t.Fatalf("Once.Do() result = %v, want %v", result, wantResult)
147 }
148
149 first, result, err = once.Do(ctx, func() (interface{}, error) {
150 return "bar", io.EOF
151 })
152 if wantFirst := true; first != wantFirst {
153 t.Fatalf("Once.Do() first = %v, want %v", first, wantFirst)
154 }
155 if wantErr := io.EOF; err != wantErr {
156 t.Fatalf("Once.Do() error = %v, wantErr %v", err, wantErr)
157 }
158 if wantResult := "bar"; !reflect.DeepEqual(result, wantResult) {
159 t.Fatalf("Once.Do() result = %v, want %v", result, wantResult)
160 }
161 }
162
163 func TestOnce_Do_Cancel_Panic(t *testing.T) {
164 ctx := context.Background()
165 once := NewOnce()
166
167 func() {
168 defer func() {
169 got := recover()
170 want := "foo"
171 if got != want {
172 t.Fatalf("Once.Do() panic = %v, want %v", got, want)
173 }
174 }()
175 once.Do(ctx, func() (interface{}, error) {
176 panic("foo")
177 })
178 }()
179
180 first, result, err := once.Do(ctx, func() (interface{}, error) {
181 return "bar", io.EOF
182 })
183 if wantFirst := true; first != wantFirst {
184 t.Fatalf("Once.Do() first = %v, want %v", first, wantFirst)
185 }
186 if wantErr := io.EOF; err != wantErr {
187 t.Fatalf("Once.Do() error = %v, wantErr %v", err, wantErr)
188 }
189 if wantResult := "bar"; !reflect.DeepEqual(result, wantResult) {
190 t.Fatalf("Once.Do() result = %v, want %v", result, wantResult)
191 }
192 }
193
View as plain text