Source file
src/context/context_test.go
1
2
3
4
5 package context
6
7
8
9
10
11
12 import (
13 "time"
14 )
15
16 type testingT interface {
17 Deadline() (time.Time, bool)
18 Error(args ...any)
19 Errorf(format string, args ...any)
20 Fail()
21 FailNow()
22 Failed() bool
23 Fatal(args ...any)
24 Fatalf(format string, args ...any)
25 Helper()
26 Log(args ...any)
27 Logf(format string, args ...any)
28 Name() string
29 Parallel()
30 Skip(args ...any)
31 SkipNow()
32 Skipf(format string, args ...any)
33 Skipped() bool
34 }
35
36 const veryLongDuration = 1000 * time.Hour
37
38 func contains(m map[canceler]struct{}, key canceler) bool {
39 _, ret := m[key]
40 return ret
41 }
42
43 func XTestParentFinishesChild(t testingT) {
44
45
46
47
48 parent, cancel := WithCancel(Background())
49 cancelChild, stop := WithCancel(parent)
50 defer stop()
51 valueChild := WithValue(parent, "key", "value")
52 timerChild, stop := WithTimeout(valueChild, veryLongDuration)
53 defer stop()
54 afterStop := AfterFunc(parent, func() {})
55 defer afterStop()
56
57 select {
58 case x := <-parent.Done():
59 t.Errorf("<-parent.Done() == %v want nothing (it should block)", x)
60 case x := <-cancelChild.Done():
61 t.Errorf("<-cancelChild.Done() == %v want nothing (it should block)", x)
62 case x := <-timerChild.Done():
63 t.Errorf("<-timerChild.Done() == %v want nothing (it should block)", x)
64 case x := <-valueChild.Done():
65 t.Errorf("<-valueChild.Done() == %v want nothing (it should block)", x)
66 default:
67 }
68
69
70 pc := parent.(*cancelCtx)
71 cc := cancelChild.(*cancelCtx)
72 tc := timerChild.(*timerCtx)
73 pc.mu.Lock()
74 var ac *afterFuncCtx
75 for c := range pc.children {
76 if a, ok := c.(*afterFuncCtx); ok {
77 ac = a
78 break
79 }
80 }
81 if len(pc.children) != 3 || !contains(pc.children, cc) || !contains(pc.children, tc) || ac == nil {
82 t.Errorf("bad linkage: pc.children = %v, want %v, %v, and an afterFunc",
83 pc.children, cc, tc)
84 }
85 pc.mu.Unlock()
86
87 if p, ok := parentCancelCtx(cc.Context); !ok || p != pc {
88 t.Errorf("bad linkage: parentCancelCtx(cancelChild.Context) = %v, %v want %v, true", p, ok, pc)
89 }
90 if p, ok := parentCancelCtx(tc.Context); !ok || p != pc {
91 t.Errorf("bad linkage: parentCancelCtx(timerChild.Context) = %v, %v want %v, true", p, ok, pc)
92 }
93 if p, ok := parentCancelCtx(ac.Context); !ok || p != pc {
94 t.Errorf("bad linkage: parentCancelCtx(afterChild.Context) = %v, %v want %v, true", p, ok, pc)
95 }
96
97 cancel()
98
99 pc.mu.Lock()
100 if len(pc.children) != 0 {
101 t.Errorf("pc.cancel didn't clear pc.children = %v", pc.children)
102 }
103 pc.mu.Unlock()
104
105
106 check := func(ctx Context, name string) {
107 select {
108 case <-ctx.Done():
109 default:
110 t.Errorf("<-%s.Done() blocked, but shouldn't have", name)
111 }
112 if e := ctx.Err(); e != Canceled {
113 t.Errorf("%s.Err() == %v want %v", name, e, Canceled)
114 }
115 }
116 check(parent, "parent")
117 check(cancelChild, "cancelChild")
118 check(valueChild, "valueChild")
119 check(timerChild, "timerChild")
120
121
122 precanceledChild := WithValue(parent, "key", "value")
123 select {
124 case <-precanceledChild.Done():
125 default:
126 t.Errorf("<-precanceledChild.Done() blocked, but shouldn't have")
127 }
128 if e := precanceledChild.Err(); e != Canceled {
129 t.Errorf("precanceledChild.Err() == %v want %v", e, Canceled)
130 }
131 }
132
133 func XTestChildFinishesFirst(t testingT) {
134 cancelable, stop := WithCancel(Background())
135 defer stop()
136 for _, parent := range []Context{Background(), cancelable} {
137 child, cancel := WithCancel(parent)
138
139 select {
140 case x := <-parent.Done():
141 t.Errorf("<-parent.Done() == %v want nothing (it should block)", x)
142 case x := <-child.Done():
143 t.Errorf("<-child.Done() == %v want nothing (it should block)", x)
144 default:
145 }
146
147 cc := child.(*cancelCtx)
148 pc, pcok := parent.(*cancelCtx)
149 if p, ok := parentCancelCtx(cc.Context); ok != pcok || (ok && pc != p) {
150 t.Errorf("bad linkage: parentCancelCtx(cc.Context) = %v, %v want %v, %v", p, ok, pc, pcok)
151 }
152
153 if pcok {
154 pc.mu.Lock()
155 if len(pc.children) != 1 || !contains(pc.children, cc) {
156 t.Errorf("bad linkage: pc.children = %v, cc = %v", pc.children, cc)
157 }
158 pc.mu.Unlock()
159 }
160
161 cancel()
162
163 if pcok {
164 pc.mu.Lock()
165 if len(pc.children) != 0 {
166 t.Errorf("child's cancel didn't remove self from pc.children = %v", pc.children)
167 }
168 pc.mu.Unlock()
169 }
170
171
172 select {
173 case <-child.Done():
174 default:
175 t.Errorf("<-child.Done() blocked, but shouldn't have")
176 }
177 if e := child.Err(); e != Canceled {
178 t.Errorf("child.Err() == %v want %v", e, Canceled)
179 }
180
181
182 select {
183 case x := <-parent.Done():
184 t.Errorf("<-parent.Done() == %v want nothing (it should block)", x)
185 default:
186 }
187 if e := parent.Err(); e != nil {
188 t.Errorf("parent.Err() == %v want nil", e)
189 }
190 }
191 }
192
193 func XTestCancelRemoves(t testingT) {
194 checkChildren := func(when string, ctx Context, want int) {
195 if got := len(ctx.(*cancelCtx).children); got != want {
196 t.Errorf("%s: context has %d children, want %d", when, got, want)
197 }
198 }
199
200 ctx, _ := WithCancel(Background())
201 checkChildren("after creation", ctx, 0)
202 _, cancel := WithCancel(ctx)
203 checkChildren("with WithCancel child ", ctx, 1)
204 cancel()
205 checkChildren("after canceling WithCancel child", ctx, 0)
206
207 ctx, _ = WithCancel(Background())
208 checkChildren("after creation", ctx, 0)
209 _, cancel = WithTimeout(ctx, 60*time.Minute)
210 checkChildren("with WithTimeout child ", ctx, 1)
211 cancel()
212 checkChildren("after canceling WithTimeout child", ctx, 0)
213
214 ctx, _ = WithCancel(Background())
215 checkChildren("after creation", ctx, 0)
216 stop := AfterFunc(ctx, func() {})
217 checkChildren("with AfterFunc child ", ctx, 1)
218 stop()
219 checkChildren("after stopping AfterFunc child ", ctx, 0)
220 }
221
222 type myCtx struct {
223 Context
224 }
225
226 type myDoneCtx struct {
227 Context
228 }
229
230 func (d *myDoneCtx) Done() <-chan struct{} {
231 c := make(chan struct{})
232 return c
233 }
234 func XTestCustomContextGoroutines(t testingT) {
235 g := goroutines.Load()
236 checkNoGoroutine := func() {
237 t.Helper()
238 now := goroutines.Load()
239 if now != g {
240 t.Fatalf("%d goroutines created", now-g)
241 }
242 }
243 checkCreatedGoroutine := func() {
244 t.Helper()
245 now := goroutines.Load()
246 if now != g+1 {
247 t.Fatalf("%d goroutines created, want 1", now-g)
248 }
249 g = now
250 }
251
252 _, cancel0 := WithCancel(&myDoneCtx{Background()})
253 cancel0()
254 checkCreatedGoroutine()
255
256 _, cancel0 = WithTimeout(&myDoneCtx{Background()}, veryLongDuration)
257 cancel0()
258 checkCreatedGoroutine()
259
260 checkNoGoroutine()
261 defer checkNoGoroutine()
262
263 ctx1, cancel1 := WithCancel(Background())
264 defer cancel1()
265 checkNoGoroutine()
266
267 ctx2 := &myCtx{ctx1}
268 ctx3, cancel3 := WithCancel(ctx2)
269 defer cancel3()
270 checkNoGoroutine()
271
272 _, cancel3b := WithCancel(&myDoneCtx{ctx2})
273 defer cancel3b()
274 checkCreatedGoroutine()
275
276 ctx4, cancel4 := WithTimeout(ctx3, veryLongDuration)
277 defer cancel4()
278 checkNoGoroutine()
279
280 ctx5, cancel5 := WithCancel(ctx4)
281 defer cancel5()
282 checkNoGoroutine()
283
284 cancel5()
285 checkNoGoroutine()
286
287 _, cancel6 := WithTimeout(ctx5, veryLongDuration)
288 defer cancel6()
289 checkNoGoroutine()
290
291
292 cancel6()
293 cancel1()
294 _, cancel7 := WithCancel(ctx5)
295 defer cancel7()
296 checkNoGoroutine()
297 }
298
View as plain text