blob: 9554dcf712362d40cb360f09e5ebf5ec54e2c7bc [file] [log] [blame]
Sameer Ajmanif5729742014-05-16 16:11:29 -04001// Copyright 2014 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
Brad Fitzpatrickafc22ee2016-03-08 00:20:11 +00005// +build !go1.7
6
Sameer Ajmanif5729742014-05-16 16:11:29 -04007package context
8
9import (
10 "fmt"
Sameer Ajmania1f36092014-07-29 14:21:02 -040011 "math/rand"
Sameer Ajmanif5729742014-05-16 16:11:29 -040012 "runtime"
Sameer Ajmani9c40a722014-08-01 09:28:31 -040013 "strings"
Sameer Ajmanif5729742014-05-16 16:11:29 -040014 "sync"
15 "testing"
16 "time"
17)
18
Sameer Ajmania67aa992014-07-30 12:14:59 -040019// otherContext is a Context that's not one of the types defined in context.go.
20// This lets us test code paths that differ based on the underlying type of the
21// Context.
Sameer Ajmanif5729742014-05-16 16:11:29 -040022type otherContext struct {
23 Context
24}
25
26func TestBackground(t *testing.T) {
27 c := Background()
28 if c == nil {
29 t.Fatalf("Background returned nil")
30 }
31 select {
32 case x := <-c.Done():
33 t.Errorf("<-c.Done() == %v want nothing (it should block)", x)
34 default:
35 }
Sameer Ajmani9c40a722014-08-01 09:28:31 -040036 if got, want := fmt.Sprint(c), "context.Background"; got != want {
37 t.Errorf("Background().String() = %q want %q", got, want)
Sameer Ajmania1f36092014-07-29 14:21:02 -040038 }
39}
40
41func TestTODO(t *testing.T) {
42 c := TODO()
43 if c == nil {
44 t.Fatalf("TODO returned nil")
45 }
46 select {
47 case x := <-c.Done():
48 t.Errorf("<-c.Done() == %v want nothing (it should block)", x)
49 default:
50 }
Sameer Ajmani9c40a722014-08-01 09:28:31 -040051 if got, want := fmt.Sprint(c), "context.TODO"; got != want {
52 t.Errorf("TODO().String() = %q want %q", got, want)
Sameer Ajmania1f36092014-07-29 14:21:02 -040053 }
Sameer Ajmanif5729742014-05-16 16:11:29 -040054}
55
56func TestWithCancel(t *testing.T) {
57 c1, cancel := WithCancel(Background())
Sameer Ajmani9c40a722014-08-01 09:28:31 -040058
59 if got, want := fmt.Sprint(c1), "context.Background.WithCancel"; got != want {
60 t.Errorf("c1.String() = %q want %q", got, want)
61 }
62
Sameer Ajmanif5729742014-05-16 16:11:29 -040063 o := otherContext{c1}
Sameer Ajmania67aa992014-07-30 12:14:59 -040064 c2, _ := WithCancel(o)
Sameer Ajmanif5729742014-05-16 16:11:29 -040065 contexts := []Context{c1, o, c2}
66
67 for i, c := range contexts {
68 if d := c.Done(); d == nil {
69 t.Errorf("c[%d].Done() == %v want non-nil", i, d)
70 }
71 if e := c.Err(); e != nil {
72 t.Errorf("c[%d].Err() == %v want nil", i, e)
73 }
74
75 select {
76 case x := <-c.Done():
77 t.Errorf("<-c.Done() == %v want nothing (it should block)", x)
78 default:
79 }
80 }
81
82 cancel()
Sameer Ajmani9c40a722014-08-01 09:28:31 -040083 time.Sleep(100 * time.Millisecond) // let cancelation propagate
Sameer Ajmanif5729742014-05-16 16:11:29 -040084
85 for i, c := range contexts {
86 select {
87 case <-c.Done():
88 default:
89 t.Errorf("<-c[%d].Done() blocked, but shouldn't have", i)
90 }
91 if e := c.Err(); e != Canceled {
92 t.Errorf("c[%d].Err() == %v want %v", i, e, Canceled)
93 }
94 }
95}
96
97func TestParentFinishesChild(t *testing.T) {
Sameer Ajmania67aa992014-07-30 12:14:59 -040098 // Context tree:
99 // parent -> cancelChild
100 // parent -> valueChild -> timerChild
Sameer Ajmanif5729742014-05-16 16:11:29 -0400101 parent, cancel := WithCancel(Background())
Sameer Ajmania67aa992014-07-30 12:14:59 -0400102 cancelChild, stop := WithCancel(parent)
103 defer stop()
104 valueChild := WithValue(parent, "key", "value")
105 timerChild, stop := WithTimeout(valueChild, 10000*time.Hour)
106 defer stop()
Sameer Ajmanif5729742014-05-16 16:11:29 -0400107
108 select {
109 case x := <-parent.Done():
110 t.Errorf("<-parent.Done() == %v want nothing (it should block)", x)
Sameer Ajmania67aa992014-07-30 12:14:59 -0400111 case x := <-cancelChild.Done():
112 t.Errorf("<-cancelChild.Done() == %v want nothing (it should block)", x)
113 case x := <-timerChild.Done():
114 t.Errorf("<-timerChild.Done() == %v want nothing (it should block)", x)
115 case x := <-valueChild.Done():
116 t.Errorf("<-valueChild.Done() == %v want nothing (it should block)", x)
Sameer Ajmanif5729742014-05-16 16:11:29 -0400117 default:
118 }
119
Sameer Ajmania67aa992014-07-30 12:14:59 -0400120 // The parent's children should contain the two cancelable children.
121 pc := parent.(*cancelCtx)
122 cc := cancelChild.(*cancelCtx)
123 tc := timerChild.(*timerCtx)
124 pc.mu.Lock()
125 if len(pc.children) != 2 || !pc.children[cc] || !pc.children[tc] {
126 t.Errorf("bad linkage: pc.children = %v, want %v and %v",
127 pc.children, cc, tc)
Sameer Ajmanif5729742014-05-16 16:11:29 -0400128 }
Sameer Ajmania67aa992014-07-30 12:14:59 -0400129 pc.mu.Unlock()
130
131 if p, ok := parentCancelCtx(cc.Context); !ok || p != pc {
132 t.Errorf("bad linkage: parentCancelCtx(cancelChild.Context) = %v, %v want %v, true", p, ok, pc)
133 }
134 if p, ok := parentCancelCtx(tc.Context); !ok || p != pc {
135 t.Errorf("bad linkage: parentCancelCtx(timerChild.Context) = %v, %v want %v, true", p, ok, pc)
136 }
Sameer Ajmanif5729742014-05-16 16:11:29 -0400137
138 cancel()
139
Sameer Ajmania67aa992014-07-30 12:14:59 -0400140 pc.mu.Lock()
141 if len(pc.children) != 0 {
142 t.Errorf("pc.cancel didn't clear pc.children = %v", pc.children)
Sameer Ajmanif5729742014-05-16 16:11:29 -0400143 }
Sameer Ajmania67aa992014-07-30 12:14:59 -0400144 pc.mu.Unlock()
Sameer Ajmanif5729742014-05-16 16:11:29 -0400145
146 // parent and children should all be finished.
Sameer Ajmania67aa992014-07-30 12:14:59 -0400147 check := func(ctx Context, name string) {
148 select {
149 case <-ctx.Done():
150 default:
151 t.Errorf("<-%s.Done() blocked, but shouldn't have", name)
152 }
153 if e := ctx.Err(); e != Canceled {
154 t.Errorf("%s.Err() == %v want %v", name, e, Canceled)
155 }
Sameer Ajmanif5729742014-05-16 16:11:29 -0400156 }
Sameer Ajmania67aa992014-07-30 12:14:59 -0400157 check(parent, "parent")
158 check(cancelChild, "cancelChild")
159 check(valueChild, "valueChild")
160 check(timerChild, "timerChild")
Sameer Ajmanif5729742014-05-16 16:11:29 -0400161
Sameer Ajmania67aa992014-07-30 12:14:59 -0400162 // WithCancel should return a canceled context on a canceled parent.
163 precanceledChild := WithValue(parent, "key", "value")
Sameer Ajmanif5729742014-05-16 16:11:29 -0400164 select {
Sameer Ajmania67aa992014-07-30 12:14:59 -0400165 case <-precanceledChild.Done():
Sameer Ajmanif5729742014-05-16 16:11:29 -0400166 default:
Sameer Ajmania67aa992014-07-30 12:14:59 -0400167 t.Errorf("<-precanceledChild.Done() blocked, but shouldn't have")
Sameer Ajmanif5729742014-05-16 16:11:29 -0400168 }
Sameer Ajmania67aa992014-07-30 12:14:59 -0400169 if e := precanceledChild.Err(); e != Canceled {
170 t.Errorf("precanceledChild.Err() == %v want %v", e, Canceled)
Sameer Ajmanif5729742014-05-16 16:11:29 -0400171 }
172}
173
174func TestChildFinishesFirst(t *testing.T) {
Sameer Ajmania67aa992014-07-30 12:14:59 -0400175 cancelable, stop := WithCancel(Background())
176 defer stop()
177 for _, parent := range []Context{Background(), cancelable} {
Sameer Ajmanif5729742014-05-16 16:11:29 -0400178 child, cancel := WithCancel(parent)
Sameer Ajmanif5729742014-05-16 16:11:29 -0400179
180 select {
181 case x := <-parent.Done():
182 t.Errorf("<-parent.Done() == %v want nothing (it should block)", x)
183 case x := <-child.Done():
184 t.Errorf("<-child.Done() == %v want nothing (it should block)", x)
185 default:
186 }
187
Sameer Ajmania67aa992014-07-30 12:14:59 -0400188 cc := child.(*cancelCtx)
189 pc, pcok := parent.(*cancelCtx) // pcok == false when parent == Background()
190 if p, ok := parentCancelCtx(cc.Context); ok != pcok || (ok && pc != p) {
191 t.Errorf("bad linkage: parentCancelCtx(cc.Context) = %v, %v want %v, %v", p, ok, pc, pcok)
Sameer Ajmanif5729742014-05-16 16:11:29 -0400192 }
193
Sameer Ajmania67aa992014-07-30 12:14:59 -0400194 if pcok {
195 pc.mu.Lock()
196 if len(pc.children) != 1 || !pc.children[cc] {
197 t.Errorf("bad linkage: pc.children = %v, cc = %v", pc.children, cc)
Sameer Ajmanif5729742014-05-16 16:11:29 -0400198 }
Sameer Ajmania67aa992014-07-30 12:14:59 -0400199 pc.mu.Unlock()
Sameer Ajmanif5729742014-05-16 16:11:29 -0400200 }
201
202 cancel()
203
Sameer Ajmania67aa992014-07-30 12:14:59 -0400204 if pcok {
205 pc.mu.Lock()
206 if len(pc.children) != 0 {
207 t.Errorf("child's cancel didn't remove self from pc.children = %v", pc.children)
208 }
209 pc.mu.Unlock()
Sameer Ajmanif5729742014-05-16 16:11:29 -0400210 }
Sameer Ajmanif5729742014-05-16 16:11:29 -0400211
212 // child should be finished.
213 select {
214 case <-child.Done():
215 default:
216 t.Errorf("<-child.Done() blocked, but shouldn't have")
217 }
218 if e := child.Err(); e != Canceled {
219 t.Errorf("child.Err() == %v want %v", e, Canceled)
220 }
221
222 // parent should not be finished.
223 select {
224 case x := <-parent.Done():
225 t.Errorf("<-parent.Done() == %v want nothing (it should block)", x)
226 default:
227 }
228 if e := parent.Err(); e != nil {
229 t.Errorf("parent.Err() == %v want nil", e)
230 }
231 }
232}
233
234func testDeadline(c Context, wait time.Duration, t *testing.T) {
235 select {
236 case <-time.After(wait):
237 t.Fatalf("context should have timed out")
238 case <-c.Done():
239 }
240 if e := c.Err(); e != DeadlineExceeded {
241 t.Errorf("c.Err() == %v want %v", e, DeadlineExceeded)
242 }
243}
244
245func TestDeadline(t *testing.T) {
Sameer Ajmania67aa992014-07-30 12:14:59 -0400246 c, _ := WithDeadline(Background(), time.Now().Add(100*time.Millisecond))
Sameer Ajmani9c40a722014-08-01 09:28:31 -0400247 if got, prefix := fmt.Sprint(c), "context.Background.WithDeadline("; !strings.HasPrefix(got, prefix) {
248 t.Errorf("c.String() = %q want prefix %q", got, prefix)
249 }
Sameer Ajmanif5729742014-05-16 16:11:29 -0400250 testDeadline(c, 200*time.Millisecond, t)
251
Sameer Ajmania67aa992014-07-30 12:14:59 -0400252 c, _ = WithDeadline(Background(), time.Now().Add(100*time.Millisecond))
Sameer Ajmanif5729742014-05-16 16:11:29 -0400253 o := otherContext{c}
254 testDeadline(o, 200*time.Millisecond, t)
255
Sameer Ajmania67aa992014-07-30 12:14:59 -0400256 c, _ = WithDeadline(Background(), time.Now().Add(100*time.Millisecond))
Sameer Ajmanif5729742014-05-16 16:11:29 -0400257 o = otherContext{c}
258 c, _ = WithDeadline(o, time.Now().Add(300*time.Millisecond))
259 testDeadline(c, 200*time.Millisecond, t)
260}
261
262func TestTimeout(t *testing.T) {
Sameer Ajmania67aa992014-07-30 12:14:59 -0400263 c, _ := WithTimeout(Background(), 100*time.Millisecond)
Sameer Ajmani9c40a722014-08-01 09:28:31 -0400264 if got, prefix := fmt.Sprint(c), "context.Background.WithDeadline("; !strings.HasPrefix(got, prefix) {
265 t.Errorf("c.String() = %q want prefix %q", got, prefix)
266 }
Sameer Ajmanif5729742014-05-16 16:11:29 -0400267 testDeadline(c, 200*time.Millisecond, t)
268
Sameer Ajmania67aa992014-07-30 12:14:59 -0400269 c, _ = WithTimeout(Background(), 100*time.Millisecond)
Sameer Ajmanif5729742014-05-16 16:11:29 -0400270 o := otherContext{c}
271 testDeadline(o, 200*time.Millisecond, t)
272
Sameer Ajmania67aa992014-07-30 12:14:59 -0400273 c, _ = WithTimeout(Background(), 100*time.Millisecond)
Sameer Ajmanif5729742014-05-16 16:11:29 -0400274 o = otherContext{c}
275 c, _ = WithTimeout(o, 300*time.Millisecond)
276 testDeadline(c, 200*time.Millisecond, t)
277}
278
Sameer Ajmani9c40a722014-08-01 09:28:31 -0400279func TestCanceledTimeout(t *testing.T) {
Sameer Ajmania67aa992014-07-30 12:14:59 -0400280 c, _ := WithTimeout(Background(), 200*time.Millisecond)
Sameer Ajmanif5729742014-05-16 16:11:29 -0400281 o := otherContext{c}
282 c, cancel := WithTimeout(o, 400*time.Millisecond)
283 cancel()
Sameer Ajmani9c40a722014-08-01 09:28:31 -0400284 time.Sleep(100 * time.Millisecond) // let cancelation propagate
Sameer Ajmanif5729742014-05-16 16:11:29 -0400285 select {
286 case <-c.Done():
287 default:
288 t.Errorf("<-c.Done() blocked, but shouldn't have")
289 }
290 if e := c.Err(); e != Canceled {
291 t.Errorf("c.Err() == %v want %v", e, Canceled)
292 }
293}
294
Sameer Ajmanibf13cf42014-07-10 14:57:25 -0400295type key1 int
296type key2 int
297
298var k1 = key1(1)
299var k2 = key2(1) // same int as k1, different type
300var k3 = key2(3) // same type as k2, different int
Sameer Ajmanif5729742014-05-16 16:11:29 -0400301
302func TestValues(t *testing.T) {
Sameer Ajmanibf13cf42014-07-10 14:57:25 -0400303 check := func(c Context, nm, v1, v2, v3 string) {
Sameer Ajmanif5729742014-05-16 16:11:29 -0400304 if v, ok := c.Value(k1).(string); ok == (len(v1) == 0) || v != v1 {
305 t.Errorf(`%s.Value(k1).(string) = %q, %t want %q, %t`, nm, v, ok, v1, len(v1) != 0)
306 }
307 if v, ok := c.Value(k2).(string); ok == (len(v2) == 0) || v != v2 {
308 t.Errorf(`%s.Value(k2).(string) = %q, %t want %q, %t`, nm, v, ok, v2, len(v2) != 0)
309 }
Sameer Ajmanibf13cf42014-07-10 14:57:25 -0400310 if v, ok := c.Value(k3).(string); ok == (len(v3) == 0) || v != v3 {
311 t.Errorf(`%s.Value(k3).(string) = %q, %t want %q, %t`, nm, v, ok, v3, len(v3) != 0)
312 }
Sameer Ajmanif5729742014-05-16 16:11:29 -0400313 }
314
315 c0 := Background()
Sameer Ajmanibf13cf42014-07-10 14:57:25 -0400316 check(c0, "c0", "", "", "")
Sameer Ajmanif5729742014-05-16 16:11:29 -0400317
Sameer Ajmania67aa992014-07-30 12:14:59 -0400318 c1 := WithValue(Background(), k1, "c1k1")
Sameer Ajmanibf13cf42014-07-10 14:57:25 -0400319 check(c1, "c1", "c1k1", "", "")
Sameer Ajmanif5729742014-05-16 16:11:29 -0400320
Sameer Ajmani9c40a722014-08-01 09:28:31 -0400321 if got, want := fmt.Sprint(c1), `context.Background.WithValue(1, "c1k1")`; got != want {
322 t.Errorf("c.String() = %q want %q", got, want)
323 }
324
Sameer Ajmanif5729742014-05-16 16:11:29 -0400325 c2 := WithValue(c1, k2, "c2k2")
Sameer Ajmanibf13cf42014-07-10 14:57:25 -0400326 check(c2, "c2", "c1k1", "c2k2", "")
Sameer Ajmanif5729742014-05-16 16:11:29 -0400327
Sameer Ajmanibf13cf42014-07-10 14:57:25 -0400328 c3 := WithValue(c2, k3, "c3k3")
329 check(c3, "c2", "c1k1", "c2k2", "c3k3")
330
331 c4 := WithValue(c3, k1, nil)
332 check(c4, "c4", "", "c2k2", "c3k3")
Sameer Ajmanif5729742014-05-16 16:11:29 -0400333
334 o0 := otherContext{Background()}
Sameer Ajmanibf13cf42014-07-10 14:57:25 -0400335 check(o0, "o0", "", "", "")
Sameer Ajmanif5729742014-05-16 16:11:29 -0400336
Sameer Ajmania67aa992014-07-30 12:14:59 -0400337 o1 := otherContext{WithValue(Background(), k1, "c1k1")}
Sameer Ajmanibf13cf42014-07-10 14:57:25 -0400338 check(o1, "o1", "c1k1", "", "")
Sameer Ajmanif5729742014-05-16 16:11:29 -0400339
340 o2 := WithValue(o1, k2, "o2k2")
Sameer Ajmanibf13cf42014-07-10 14:57:25 -0400341 check(o2, "o2", "c1k1", "o2k2", "")
Sameer Ajmanif5729742014-05-16 16:11:29 -0400342
Sameer Ajmanibf13cf42014-07-10 14:57:25 -0400343 o3 := otherContext{c4}
344 check(o3, "o3", "", "c2k2", "c3k3")
345
346 o4 := WithValue(o3, k3, nil)
347 check(o4, "o4", "", "c2k2", "")
Sameer Ajmanif5729742014-05-16 16:11:29 -0400348}
349
350func TestAllocs(t *testing.T) {
351 bg := Background()
352 for _, test := range []struct {
353 desc string
354 f func()
355 limit float64
356 gccgoLimit float64
357 }{
358 {
359 desc: "Background()",
360 f: func() { Background() },
361 limit: 0,
362 gccgoLimit: 0,
363 },
364 {
365 desc: fmt.Sprintf("WithValue(bg, %v, nil)", k1),
366 f: func() {
367 c := WithValue(bg, k1, nil)
368 c.Value(k1)
369 },
Sameer Ajmani3ffb8fd2014-10-09 13:51:22 -0400370 limit: 3,
Sameer Ajmanif5729742014-05-16 16:11:29 -0400371 gccgoLimit: 3,
372 },
373 {
Alex Brainman6b9623c2014-06-18 10:02:55 +1000374 desc: "WithTimeout(bg, 15*time.Millisecond)",
Sameer Ajmanif5729742014-05-16 16:11:29 -0400375 f: func() {
Alex Brainman6b9623c2014-06-18 10:02:55 +1000376 c, _ := WithTimeout(bg, 15*time.Millisecond)
Sameer Ajmanif5729742014-05-16 16:11:29 -0400377 <-c.Done()
378 },
Sameer Ajmania67aa992014-07-30 12:14:59 -0400379 limit: 8,
David Symondsfb939262016-04-13 08:48:50 +1000380 gccgoLimit: 16,
Sameer Ajmanif5729742014-05-16 16:11:29 -0400381 },
382 {
383 desc: "WithCancel(bg)",
384 f: func() {
385 c, cancel := WithCancel(bg)
386 cancel()
387 <-c.Done()
388 },
Sameer Ajmania67aa992014-07-30 12:14:59 -0400389 limit: 5,
Sameer Ajmanif5729742014-05-16 16:11:29 -0400390 gccgoLimit: 8,
391 },
392 {
393 desc: "WithTimeout(bg, 100*time.Millisecond)",
394 f: func() {
395 c, cancel := WithTimeout(bg, 100*time.Millisecond)
396 cancel()
397 <-c.Done()
398 },
Sameer Ajmania67aa992014-07-30 12:14:59 -0400399 limit: 8,
Sameer Ajmanif5729742014-05-16 16:11:29 -0400400 gccgoLimit: 25,
401 },
402 } {
403 limit := test.limit
404 if runtime.Compiler == "gccgo" {
405 // gccgo does not yet do escape analysis.
Ian Lance Taylor2a35e682016-05-06 12:47:26 -0700406 // TODO(iant): Remove this when gccgo does do escape analysis.
Sameer Ajmanif5729742014-05-16 16:11:29 -0400407 limit = test.gccgoLimit
408 }
Alex Brainman6b9623c2014-06-18 10:02:55 +1000409 if n := testing.AllocsPerRun(100, test.f); n > limit {
Sameer Ajmanif5729742014-05-16 16:11:29 -0400410 t.Errorf("%s allocs = %f want %d", test.desc, n, int(limit))
411 }
412 }
413}
414
415func TestSimultaneousCancels(t *testing.T) {
416 root, cancel := WithCancel(Background())
417 m := map[Context]CancelFunc{root: cancel}
418 q := []Context{root}
419 // Create a tree of contexts.
420 for len(q) != 0 && len(m) < 100 {
421 parent := q[0]
422 q = q[1:]
423 for i := 0; i < 4; i++ {
424 ctx, cancel := WithCancel(parent)
425 m[ctx] = cancel
426 q = append(q, ctx)
427 }
428 }
429 // Start all the cancels in a random order.
430 var wg sync.WaitGroup
431 wg.Add(len(m))
432 for _, cancel := range m {
433 go func(cancel CancelFunc) {
434 cancel()
435 wg.Done()
436 }(cancel)
437 }
438 // Wait on all the contexts in a random order.
439 for ctx := range m {
440 select {
441 case <-ctx.Done():
442 case <-time.After(1 * time.Second):
443 buf := make([]byte, 10<<10)
444 n := runtime.Stack(buf, true)
445 t.Fatalf("timed out waiting for <-ctx.Done(); stacks:\n%s", buf[:n])
446 }
447 }
448 // Wait for all the cancel functions to return.
449 done := make(chan struct{})
450 go func() {
451 wg.Wait()
452 close(done)
453 }()
454 select {
455 case <-done:
456 case <-time.After(1 * time.Second):
457 buf := make([]byte, 10<<10)
458 n := runtime.Stack(buf, true)
459 t.Fatalf("timed out waiting for cancel functions; stacks:\n%s", buf[:n])
460 }
461}
462
463func TestInterlockedCancels(t *testing.T) {
464 parent, cancelParent := WithCancel(Background())
465 child, cancelChild := WithCancel(parent)
466 go func() {
467 parent.Done()
468 cancelChild()
469 }()
470 cancelParent()
471 select {
472 case <-child.Done():
473 case <-time.After(1 * time.Second):
474 buf := make([]byte, 10<<10)
475 n := runtime.Stack(buf, true)
476 t.Fatalf("timed out waiting for child.Done(); stacks:\n%s", buf[:n])
477 }
478}
Sameer Ajmania1f36092014-07-29 14:21:02 -0400479
480func TestLayersCancel(t *testing.T) {
481 testLayers(t, time.Now().UnixNano(), false)
482}
483
484func TestLayersTimeout(t *testing.T) {
485 testLayers(t, time.Now().UnixNano(), true)
486}
487
488func testLayers(t *testing.T, seed int64, testTimeout bool) {
489 rand.Seed(seed)
490 errorf := func(format string, a ...interface{}) {
491 t.Errorf(fmt.Sprintf("seed=%d: %s", seed, format), a...)
492 }
493 const (
494 timeout = 200 * time.Millisecond
495 minLayers = 30
496 )
497 type value int
498 var (
499 vals []*value
500 cancels []CancelFunc
501 numTimers int
502 ctx = Background()
503 )
504 for i := 0; i < minLayers || numTimers == 0 || len(cancels) == 0 || len(vals) == 0; i++ {
505 switch rand.Intn(3) {
506 case 0:
507 v := new(value)
Sameer Ajmania1f36092014-07-29 14:21:02 -0400508 ctx = WithValue(ctx, v, v)
509 vals = append(vals, v)
510 case 1:
511 var cancel CancelFunc
Sameer Ajmania1f36092014-07-29 14:21:02 -0400512 ctx, cancel = WithCancel(ctx)
513 cancels = append(cancels, cancel)
514 case 2:
515 var cancel CancelFunc
Sameer Ajmania1f36092014-07-29 14:21:02 -0400516 ctx, cancel = WithTimeout(ctx, timeout)
517 cancels = append(cancels, cancel)
518 numTimers++
519 }
520 }
521 checkValues := func(when string) {
522 for _, key := range vals {
523 if val := ctx.Value(key).(*value); key != val {
524 errorf("%s: ctx.Value(%p) = %p want %p", when, key, val, key)
525 }
526 }
527 }
528 select {
529 case <-ctx.Done():
530 errorf("ctx should not be canceled yet")
531 default:
532 }
Sameer Ajmani9c40a722014-08-01 09:28:31 -0400533 if s, prefix := fmt.Sprint(ctx), "context.Background."; !strings.HasPrefix(s, prefix) {
534 t.Errorf("ctx.String() = %q want prefix %q", s, prefix)
535 }
536 t.Log(ctx)
Sameer Ajmania1f36092014-07-29 14:21:02 -0400537 checkValues("before cancel")
538 if testTimeout {
539 select {
540 case <-ctx.Done():
Sameer Ajmani96feaeb2015-08-14 18:05:50 +0100541 case <-time.After(timeout + 100*time.Millisecond):
Sameer Ajmania1f36092014-07-29 14:21:02 -0400542 errorf("ctx should have timed out")
543 }
544 checkValues("after timeout")
545 } else {
546 cancel := cancels[rand.Intn(len(cancels))]
547 cancel()
548 select {
549 case <-ctx.Done():
550 default:
551 errorf("ctx should be canceled")
552 }
553 checkValues("after cancel")
554 }
555}
Damien Neilf090b052015-02-04 12:47:08 -0800556
557func TestCancelRemoves(t *testing.T) {
558 checkChildren := func(when string, ctx Context, want int) {
559 if got := len(ctx.(*cancelCtx).children); got != want {
560 t.Errorf("%s: context has %d children, want %d", when, got, want)
561 }
562 }
563
564 ctx, _ := WithCancel(Background())
565 checkChildren("after creation", ctx, 0)
566 _, cancel := WithCancel(ctx)
567 checkChildren("with WithCancel child ", ctx, 1)
568 cancel()
569 checkChildren("after cancelling WithCancel child", ctx, 0)
570
571 ctx, _ = WithCancel(Background())
572 checkChildren("after creation", ctx, 0)
573 _, cancel = WithTimeout(ctx, 60*time.Minute)
574 checkChildren("with WithTimeout child ", ctx, 1)
575 cancel()
576 checkChildren("after cancelling WithTimeout child", ctx, 0)
577}