libgo: update to go1.9
[official-gcc.git] / libgo / go / context / context_test.go
blob548476f290d4976a5ac373034774db831b175e0d
1 // 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.
5 package context
7 import (
8 "fmt"
9 "math/rand"
10 "runtime"
11 "strings"
12 "sync"
13 "time"
16 type testingT interface {
17 Error(args ...interface{})
18 Errorf(format string, args ...interface{})
19 Fail()
20 FailNow()
21 Failed() bool
22 Fatal(args ...interface{})
23 Fatalf(format string, args ...interface{})
24 Log(args ...interface{})
25 Logf(format string, args ...interface{})
26 Name() string
27 Skip(args ...interface{})
28 SkipNow()
29 Skipf(format string, args ...interface{})
30 Skipped() bool
33 // otherContext is a Context that's not one of the types defined in context.go.
34 // This lets us test code paths that differ based on the underlying type of the
35 // Context.
36 type otherContext struct {
37 Context
40 func XTestBackground(t testingT) {
41 c := Background()
42 if c == nil {
43 t.Fatalf("Background returned nil")
45 select {
46 case x := <-c.Done():
47 t.Errorf("<-c.Done() == %v want nothing (it should block)", x)
48 default:
50 if got, want := fmt.Sprint(c), "context.Background"; got != want {
51 t.Errorf("Background().String() = %q want %q", got, want)
55 func XTestTODO(t testingT) {
56 c := TODO()
57 if c == nil {
58 t.Fatalf("TODO returned nil")
60 select {
61 case x := <-c.Done():
62 t.Errorf("<-c.Done() == %v want nothing (it should block)", x)
63 default:
65 if got, want := fmt.Sprint(c), "context.TODO"; got != want {
66 t.Errorf("TODO().String() = %q want %q", got, want)
70 func XTestWithCancel(t testingT) {
71 c1, cancel := WithCancel(Background())
73 if got, want := fmt.Sprint(c1), "context.Background.WithCancel"; got != want {
74 t.Errorf("c1.String() = %q want %q", got, want)
77 o := otherContext{c1}
78 c2, _ := WithCancel(o)
79 contexts := []Context{c1, o, c2}
81 for i, c := range contexts {
82 if d := c.Done(); d == nil {
83 t.Errorf("c[%d].Done() == %v want non-nil", i, d)
85 if e := c.Err(); e != nil {
86 t.Errorf("c[%d].Err() == %v want nil", i, e)
89 select {
90 case x := <-c.Done():
91 t.Errorf("<-c.Done() == %v want nothing (it should block)", x)
92 default:
96 cancel()
97 time.Sleep(100 * time.Millisecond) // let cancelation propagate
99 for i, c := range contexts {
100 select {
101 case <-c.Done():
102 default:
103 t.Errorf("<-c[%d].Done() blocked, but shouldn't have", i)
105 if e := c.Err(); e != Canceled {
106 t.Errorf("c[%d].Err() == %v want %v", i, e, Canceled)
111 func contains(m map[canceler]struct{}, key canceler) bool {
112 _, ret := m[key]
113 return ret
116 func XTestParentFinishesChild(t testingT) {
117 // Context tree:
118 // parent -> cancelChild
119 // parent -> valueChild -> timerChild
120 parent, cancel := WithCancel(Background())
121 cancelChild, stop := WithCancel(parent)
122 defer stop()
123 valueChild := WithValue(parent, "key", "value")
124 timerChild, stop := WithTimeout(valueChild, 10000*time.Hour)
125 defer stop()
127 select {
128 case x := <-parent.Done():
129 t.Errorf("<-parent.Done() == %v want nothing (it should block)", x)
130 case x := <-cancelChild.Done():
131 t.Errorf("<-cancelChild.Done() == %v want nothing (it should block)", x)
132 case x := <-timerChild.Done():
133 t.Errorf("<-timerChild.Done() == %v want nothing (it should block)", x)
134 case x := <-valueChild.Done():
135 t.Errorf("<-valueChild.Done() == %v want nothing (it should block)", x)
136 default:
139 // The parent's children should contain the two cancelable children.
140 pc := parent.(*cancelCtx)
141 cc := cancelChild.(*cancelCtx)
142 tc := timerChild.(*timerCtx)
143 pc.mu.Lock()
144 if len(pc.children) != 2 || !contains(pc.children, cc) || !contains(pc.children, tc) {
145 t.Errorf("bad linkage: pc.children = %v, want %v and %v",
146 pc.children, cc, tc)
148 pc.mu.Unlock()
150 if p, ok := parentCancelCtx(cc.Context); !ok || p != pc {
151 t.Errorf("bad linkage: parentCancelCtx(cancelChild.Context) = %v, %v want %v, true", p, ok, pc)
153 if p, ok := parentCancelCtx(tc.Context); !ok || p != pc {
154 t.Errorf("bad linkage: parentCancelCtx(timerChild.Context) = %v, %v want %v, true", p, ok, pc)
157 cancel()
159 pc.mu.Lock()
160 if len(pc.children) != 0 {
161 t.Errorf("pc.cancel didn't clear pc.children = %v", pc.children)
163 pc.mu.Unlock()
165 // parent and children should all be finished.
166 check := func(ctx Context, name string) {
167 select {
168 case <-ctx.Done():
169 default:
170 t.Errorf("<-%s.Done() blocked, but shouldn't have", name)
172 if e := ctx.Err(); e != Canceled {
173 t.Errorf("%s.Err() == %v want %v", name, e, Canceled)
176 check(parent, "parent")
177 check(cancelChild, "cancelChild")
178 check(valueChild, "valueChild")
179 check(timerChild, "timerChild")
181 // WithCancel should return a canceled context on a canceled parent.
182 precanceledChild := WithValue(parent, "key", "value")
183 select {
184 case <-precanceledChild.Done():
185 default:
186 t.Errorf("<-precanceledChild.Done() blocked, but shouldn't have")
188 if e := precanceledChild.Err(); e != Canceled {
189 t.Errorf("precanceledChild.Err() == %v want %v", e, Canceled)
193 func XTestChildFinishesFirst(t testingT) {
194 cancelable, stop := WithCancel(Background())
195 defer stop()
196 for _, parent := range []Context{Background(), cancelable} {
197 child, cancel := WithCancel(parent)
199 select {
200 case x := <-parent.Done():
201 t.Errorf("<-parent.Done() == %v want nothing (it should block)", x)
202 case x := <-child.Done():
203 t.Errorf("<-child.Done() == %v want nothing (it should block)", x)
204 default:
207 cc := child.(*cancelCtx)
208 pc, pcok := parent.(*cancelCtx) // pcok == false when parent == Background()
209 if p, ok := parentCancelCtx(cc.Context); ok != pcok || (ok && pc != p) {
210 t.Errorf("bad linkage: parentCancelCtx(cc.Context) = %v, %v want %v, %v", p, ok, pc, pcok)
213 if pcok {
214 pc.mu.Lock()
215 if len(pc.children) != 1 || !contains(pc.children, cc) {
216 t.Errorf("bad linkage: pc.children = %v, cc = %v", pc.children, cc)
218 pc.mu.Unlock()
221 cancel()
223 if pcok {
224 pc.mu.Lock()
225 if len(pc.children) != 0 {
226 t.Errorf("child's cancel didn't remove self from pc.children = %v", pc.children)
228 pc.mu.Unlock()
231 // child should be finished.
232 select {
233 case <-child.Done():
234 default:
235 t.Errorf("<-child.Done() blocked, but shouldn't have")
237 if e := child.Err(); e != Canceled {
238 t.Errorf("child.Err() == %v want %v", e, Canceled)
241 // parent should not be finished.
242 select {
243 case x := <-parent.Done():
244 t.Errorf("<-parent.Done() == %v want nothing (it should block)", x)
245 default:
247 if e := parent.Err(); e != nil {
248 t.Errorf("parent.Err() == %v want nil", e)
253 func testDeadline(c Context, name string, failAfter time.Duration, t testingT) {
254 select {
255 case <-time.After(failAfter):
256 t.Fatalf("%s: context should have timed out", name)
257 case <-c.Done():
259 if e := c.Err(); e != DeadlineExceeded {
260 t.Errorf("%s: c.Err() == %v; want %v", name, e, DeadlineExceeded)
264 func XTestDeadline(t testingT) {
265 c, _ := WithDeadline(Background(), time.Now().Add(50*time.Millisecond))
266 if got, prefix := fmt.Sprint(c), "context.Background.WithDeadline("; !strings.HasPrefix(got, prefix) {
267 t.Errorf("c.String() = %q want prefix %q", got, prefix)
269 testDeadline(c, "WithDeadline", time.Second, t)
271 c, _ = WithDeadline(Background(), time.Now().Add(50*time.Millisecond))
272 o := otherContext{c}
273 testDeadline(o, "WithDeadline+otherContext", time.Second, t)
275 c, _ = WithDeadline(Background(), time.Now().Add(50*time.Millisecond))
276 o = otherContext{c}
277 c, _ = WithDeadline(o, time.Now().Add(4*time.Second))
278 testDeadline(c, "WithDeadline+otherContext+WithDeadline", 2*time.Second, t)
280 c, _ = WithDeadline(Background(), time.Now().Add(-time.Millisecond))
281 testDeadline(c, "WithDeadline+inthepast", time.Second, t)
283 c, _ = WithDeadline(Background(), time.Now())
284 testDeadline(c, "WithDeadline+now", time.Second, t)
287 func XTestTimeout(t testingT) {
288 c, _ := WithTimeout(Background(), 50*time.Millisecond)
289 if got, prefix := fmt.Sprint(c), "context.Background.WithDeadline("; !strings.HasPrefix(got, prefix) {
290 t.Errorf("c.String() = %q want prefix %q", got, prefix)
292 testDeadline(c, "WithTimeout", time.Second, t)
294 c, _ = WithTimeout(Background(), 50*time.Millisecond)
295 o := otherContext{c}
296 testDeadline(o, "WithTimeout+otherContext", time.Second, t)
298 c, _ = WithTimeout(Background(), 50*time.Millisecond)
299 o = otherContext{c}
300 c, _ = WithTimeout(o, 3*time.Second)
301 testDeadline(c, "WithTimeout+otherContext+WithTimeout", 2*time.Second, t)
304 func XTestCanceledTimeout(t testingT) {
305 c, _ := WithTimeout(Background(), time.Second)
306 o := otherContext{c}
307 c, cancel := WithTimeout(o, 2*time.Second)
308 cancel()
309 time.Sleep(100 * time.Millisecond) // let cancelation propagate
310 select {
311 case <-c.Done():
312 default:
313 t.Errorf("<-c.Done() blocked, but shouldn't have")
315 if e := c.Err(); e != Canceled {
316 t.Errorf("c.Err() == %v want %v", e, Canceled)
320 type key1 int
321 type key2 int
323 var k1 = key1(1)
324 var k2 = key2(1) // same int as k1, different type
325 var k3 = key2(3) // same type as k2, different int
327 func XTestValues(t testingT) {
328 check := func(c Context, nm, v1, v2, v3 string) {
329 if v, ok := c.Value(k1).(string); ok == (len(v1) == 0) || v != v1 {
330 t.Errorf(`%s.Value(k1).(string) = %q, %t want %q, %t`, nm, v, ok, v1, len(v1) != 0)
332 if v, ok := c.Value(k2).(string); ok == (len(v2) == 0) || v != v2 {
333 t.Errorf(`%s.Value(k2).(string) = %q, %t want %q, %t`, nm, v, ok, v2, len(v2) != 0)
335 if v, ok := c.Value(k3).(string); ok == (len(v3) == 0) || v != v3 {
336 t.Errorf(`%s.Value(k3).(string) = %q, %t want %q, %t`, nm, v, ok, v3, len(v3) != 0)
340 c0 := Background()
341 check(c0, "c0", "", "", "")
343 c1 := WithValue(Background(), k1, "c1k1")
344 check(c1, "c1", "c1k1", "", "")
346 if got, want := fmt.Sprint(c1), `context.Background.WithValue(1, "c1k1")`; got != want {
347 t.Errorf("c.String() = %q want %q", got, want)
350 c2 := WithValue(c1, k2, "c2k2")
351 check(c2, "c2", "c1k1", "c2k2", "")
353 c3 := WithValue(c2, k3, "c3k3")
354 check(c3, "c2", "c1k1", "c2k2", "c3k3")
356 c4 := WithValue(c3, k1, nil)
357 check(c4, "c4", "", "c2k2", "c3k3")
359 o0 := otherContext{Background()}
360 check(o0, "o0", "", "", "")
362 o1 := otherContext{WithValue(Background(), k1, "c1k1")}
363 check(o1, "o1", "c1k1", "", "")
365 o2 := WithValue(o1, k2, "o2k2")
366 check(o2, "o2", "c1k1", "o2k2", "")
368 o3 := otherContext{c4}
369 check(o3, "o3", "", "c2k2", "c3k3")
371 o4 := WithValue(o3, k3, nil)
372 check(o4, "o4", "", "c2k2", "")
375 func XTestAllocs(t testingT, testingShort func() bool, testingAllocsPerRun func(int, func()) float64) {
376 bg := Background()
377 for _, test := range []struct {
378 desc string
379 f func()
380 limit float64
381 gccgoLimit float64
384 desc: "Background()",
385 f: func() { Background() },
386 limit: 0,
387 gccgoLimit: 0,
390 desc: fmt.Sprintf("WithValue(bg, %v, nil)", k1),
391 f: func() {
392 c := WithValue(bg, k1, nil)
393 c.Value(k1)
395 limit: 3,
396 gccgoLimit: 3,
399 desc: "WithTimeout(bg, 15*time.Millisecond)",
400 f: func() {
401 c, _ := WithTimeout(bg, 15*time.Millisecond)
402 <-c.Done()
404 limit: 8,
405 gccgoLimit: 18,
408 desc: "WithCancel(bg)",
409 f: func() {
410 c, cancel := WithCancel(bg)
411 cancel()
412 <-c.Done()
414 limit: 5,
415 gccgoLimit: 8,
418 desc: "WithTimeout(bg, 5*time.Millisecond)",
419 f: func() {
420 c, cancel := WithTimeout(bg, 5*time.Millisecond)
421 cancel()
422 <-c.Done()
424 limit: 8,
425 gccgoLimit: 25,
428 limit := test.limit
429 if runtime.Compiler == "gccgo" {
430 // gccgo does not yet do escape analysis.
431 // TODO(iant): Remove this when gccgo does do escape analysis.
432 limit = test.gccgoLimit
434 numRuns := 100
435 if testingShort() {
436 numRuns = 10
438 if n := testingAllocsPerRun(numRuns, test.f); n > limit {
439 t.Errorf("%s allocs = %f want %d", test.desc, n, int(limit))
444 func XTestSimultaneousCancels(t testingT) {
445 root, cancel := WithCancel(Background())
446 m := map[Context]CancelFunc{root: cancel}
447 q := []Context{root}
448 // Create a tree of contexts.
449 for len(q) != 0 && len(m) < 100 {
450 parent := q[0]
451 q = q[1:]
452 for i := 0; i < 4; i++ {
453 ctx, cancel := WithCancel(parent)
454 m[ctx] = cancel
455 q = append(q, ctx)
458 // Start all the cancels in a random order.
459 var wg sync.WaitGroup
460 wg.Add(len(m))
461 for _, cancel := range m {
462 go func(cancel CancelFunc) {
463 cancel()
464 wg.Done()
465 }(cancel)
467 // Wait on all the contexts in a random order.
468 for ctx := range m {
469 select {
470 case <-ctx.Done():
471 case <-time.After(1 * time.Second):
472 buf := make([]byte, 10<<10)
473 n := runtime.Stack(buf, true)
474 t.Fatalf("timed out waiting for <-ctx.Done(); stacks:\n%s", buf[:n])
477 // Wait for all the cancel functions to return.
478 done := make(chan struct{})
479 go func() {
480 wg.Wait()
481 close(done)
483 select {
484 case <-done:
485 case <-time.After(1 * time.Second):
486 buf := make([]byte, 10<<10)
487 n := runtime.Stack(buf, true)
488 t.Fatalf("timed out waiting for cancel functions; stacks:\n%s", buf[:n])
492 func XTestInterlockedCancels(t testingT) {
493 parent, cancelParent := WithCancel(Background())
494 child, cancelChild := WithCancel(parent)
495 go func() {
496 parent.Done()
497 cancelChild()
499 cancelParent()
500 select {
501 case <-child.Done():
502 case <-time.After(1 * time.Second):
503 buf := make([]byte, 10<<10)
504 n := runtime.Stack(buf, true)
505 t.Fatalf("timed out waiting for child.Done(); stacks:\n%s", buf[:n])
509 func XTestLayersCancel(t testingT) {
510 testLayers(t, time.Now().UnixNano(), false)
513 func XTestLayersTimeout(t testingT) {
514 testLayers(t, time.Now().UnixNano(), true)
517 func testLayers(t testingT, seed int64, testTimeout bool) {
518 rand.Seed(seed)
519 errorf := func(format string, a ...interface{}) {
520 t.Errorf(fmt.Sprintf("seed=%d: %s", seed, format), a...)
522 const (
523 timeout = 200 * time.Millisecond
524 minLayers = 30
526 type value int
527 var (
528 vals []*value
529 cancels []CancelFunc
530 numTimers int
531 ctx = Background()
533 for i := 0; i < minLayers || numTimers == 0 || len(cancels) == 0 || len(vals) == 0; i++ {
534 switch rand.Intn(3) {
535 case 0:
536 v := new(value)
537 ctx = WithValue(ctx, v, v)
538 vals = append(vals, v)
539 case 1:
540 var cancel CancelFunc
541 ctx, cancel = WithCancel(ctx)
542 cancels = append(cancels, cancel)
543 case 2:
544 var cancel CancelFunc
545 ctx, cancel = WithTimeout(ctx, timeout)
546 cancels = append(cancels, cancel)
547 numTimers++
550 checkValues := func(when string) {
551 for _, key := range vals {
552 if val := ctx.Value(key).(*value); key != val {
553 errorf("%s: ctx.Value(%p) = %p want %p", when, key, val, key)
557 select {
558 case <-ctx.Done():
559 errorf("ctx should not be canceled yet")
560 default:
562 if s, prefix := fmt.Sprint(ctx), "context.Background."; !strings.HasPrefix(s, prefix) {
563 t.Errorf("ctx.String() = %q want prefix %q", s, prefix)
565 t.Log(ctx)
566 checkValues("before cancel")
567 if testTimeout {
568 select {
569 case <-ctx.Done():
570 case <-time.After(timeout + time.Second):
571 errorf("ctx should have timed out")
573 checkValues("after timeout")
574 } else {
575 cancel := cancels[rand.Intn(len(cancels))]
576 cancel()
577 select {
578 case <-ctx.Done():
579 default:
580 errorf("ctx should be canceled")
582 checkValues("after cancel")
586 func XTestCancelRemoves(t testingT) {
587 checkChildren := func(when string, ctx Context, want int) {
588 if got := len(ctx.(*cancelCtx).children); got != want {
589 t.Errorf("%s: context has %d children, want %d", when, got, want)
593 ctx, _ := WithCancel(Background())
594 checkChildren("after creation", ctx, 0)
595 _, cancel := WithCancel(ctx)
596 checkChildren("with WithCancel child ", ctx, 1)
597 cancel()
598 checkChildren("after canceling WithCancel child", ctx, 0)
600 ctx, _ = WithCancel(Background())
601 checkChildren("after creation", ctx, 0)
602 _, cancel = WithTimeout(ctx, 60*time.Minute)
603 checkChildren("with WithTimeout child ", ctx, 1)
604 cancel()
605 checkChildren("after canceling WithTimeout child", ctx, 0)
608 func XTestWithCancelCanceledParent(t testingT) {
609 parent, pcancel := WithCancel(Background())
610 pcancel()
612 c, _ := WithCancel(parent)
613 select {
614 case <-c.Done():
615 case <-time.After(5 * time.Second):
616 t.Fatal("timeout waiting for Done")
618 if got, want := c.Err(), Canceled; got != want {
619 t.Errorf("child not cancelled; got = %v, want = %v", got, want)
623 func XTestWithValueChecksKey(t testingT) {
624 panicVal := recoveredValue(func() { WithValue(Background(), []byte("foo"), "bar") })
625 if panicVal == nil {
626 t.Error("expected panic")
628 panicVal = recoveredValue(func() { WithValue(Background(), nil, "bar") })
629 if got, want := fmt.Sprint(panicVal), "nil key"; got != want {
630 t.Errorf("panic = %q; want %q", got, want)
634 func recoveredValue(fn func()) (v interface{}) {
635 defer func() { v = recover() }()
636 fn()
637 return
640 func XTestDeadlineExceededSupportsTimeout(t testingT) {
641 i, ok := DeadlineExceeded.(interface {
642 Timeout() bool
644 if !ok {
645 t.Fatal("DeadlineExceeded does not support Timeout interface")
647 if !i.Timeout() {
648 t.Fatal("wrong value for timeout")