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.
17 type testingT interface {
18 Deadline() (time.Time, bool)
20 Errorf(format string, args ...any)
25 Fatalf(format string, args ...any)
28 Logf(format string, args ...any)
33 Skipf(format string, args ...any)
37 // otherContext is a Context that's not one of the types defined in context.go.
38 // This lets us test code paths that differ based on the underlying type of the
40 type otherContext struct {
45 shortDuration = 1 * time.Millisecond // a reasonable duration to block in a test
46 veryLongDuration = 1000 * time.Hour // an arbitrary upper bound on the test's running time
49 // quiescent returns an arbitrary duration by which the program should have
50 // completed any remaining work and reached a steady (idle) state.
51 func quiescent(t testingT) time.Duration {
52 deadline, ok := t.Deadline()
54 return 5 * time.Second
57 const arbitraryCleanupMargin = 1 * time.Second
58 return time.Until(deadline) - arbitraryCleanupMargin
61 func XTestBackground(t testingT) {
64 t.Fatalf("Background returned nil")
68 t.Errorf("<-c.Done() == %v want nothing (it should block)", x)
71 if got, want := fmt.Sprint(c), "context.Background"; got != want {
72 t.Errorf("Background().String() = %q want %q", got, want)
76 func XTestTODO(t testingT) {
79 t.Fatalf("TODO returned nil")
83 t.Errorf("<-c.Done() == %v want nothing (it should block)", x)
86 if got, want := fmt.Sprint(c), "context.TODO"; got != want {
87 t.Errorf("TODO().String() = %q want %q", got, want)
91 func XTestWithCancel(t testingT) {
92 c1, cancel := WithCancel(Background())
94 if got, want := fmt.Sprint(c1), "context.Background.WithCancel"; got != want {
95 t.Errorf("c1.String() = %q want %q", got, want)
99 c2, _ := WithCancel(o)
100 contexts := []Context{c1, o, c2}
102 for i, c := range contexts {
103 if d := c.Done(); d == nil {
104 t.Errorf("c[%d].Done() == %v want non-nil", i, d)
106 if e := c.Err(); e != nil {
107 t.Errorf("c[%d].Err() == %v want nil", i, e)
111 case x := <-c.Done():
112 t.Errorf("<-c.Done() == %v want nothing (it should block)", x)
117 cancel() // Should propagate synchronously.
118 for i, c := range contexts {
122 t.Errorf("<-c[%d].Done() blocked, but shouldn't have", i)
124 if e := c.Err(); e != Canceled {
125 t.Errorf("c[%d].Err() == %v want %v", i, e, Canceled)
130 func contains(m map[canceler]struct{}, key canceler) bool {
135 func XTestParentFinishesChild(t testingT) {
137 // parent -> cancelChild
138 // parent -> valueChild -> timerChild
139 parent, cancel := WithCancel(Background())
140 cancelChild, stop := WithCancel(parent)
142 valueChild := WithValue(parent, "key", "value")
143 timerChild, stop := WithTimeout(valueChild, veryLongDuration)
147 case x := <-parent.Done():
148 t.Errorf("<-parent.Done() == %v want nothing (it should block)", x)
149 case x := <-cancelChild.Done():
150 t.Errorf("<-cancelChild.Done() == %v want nothing (it should block)", x)
151 case x := <-timerChild.Done():
152 t.Errorf("<-timerChild.Done() == %v want nothing (it should block)", x)
153 case x := <-valueChild.Done():
154 t.Errorf("<-valueChild.Done() == %v want nothing (it should block)", x)
158 // The parent's children should contain the two cancelable children.
159 pc := parent.(*cancelCtx)
160 cc := cancelChild.(*cancelCtx)
161 tc := timerChild.(*timerCtx)
163 if len(pc.children) != 2 || !contains(pc.children, cc) || !contains(pc.children, tc) {
164 t.Errorf("bad linkage: pc.children = %v, want %v and %v",
169 if p, ok := parentCancelCtx(cc.Context); !ok || p != pc {
170 t.Errorf("bad linkage: parentCancelCtx(cancelChild.Context) = %v, %v want %v, true", p, ok, pc)
172 if p, ok := parentCancelCtx(tc.Context); !ok || p != pc {
173 t.Errorf("bad linkage: parentCancelCtx(timerChild.Context) = %v, %v want %v, true", p, ok, pc)
179 if len(pc.children) != 0 {
180 t.Errorf("pc.cancel didn't clear pc.children = %v", pc.children)
184 // parent and children should all be finished.
185 check := func(ctx Context, name string) {
189 t.Errorf("<-%s.Done() blocked, but shouldn't have", name)
191 if e := ctx.Err(); e != Canceled {
192 t.Errorf("%s.Err() == %v want %v", name, e, Canceled)
195 check(parent, "parent")
196 check(cancelChild, "cancelChild")
197 check(valueChild, "valueChild")
198 check(timerChild, "timerChild")
200 // WithCancel should return a canceled context on a canceled parent.
201 precanceledChild := WithValue(parent, "key", "value")
203 case <-precanceledChild.Done():
205 t.Errorf("<-precanceledChild.Done() blocked, but shouldn't have")
207 if e := precanceledChild.Err(); e != Canceled {
208 t.Errorf("precanceledChild.Err() == %v want %v", e, Canceled)
212 func XTestChildFinishesFirst(t testingT) {
213 cancelable, stop := WithCancel(Background())
215 for _, parent := range []Context{Background(), cancelable} {
216 child, cancel := WithCancel(parent)
219 case x := <-parent.Done():
220 t.Errorf("<-parent.Done() == %v want nothing (it should block)", x)
221 case x := <-child.Done():
222 t.Errorf("<-child.Done() == %v want nothing (it should block)", x)
226 cc := child.(*cancelCtx)
227 pc, pcok := parent.(*cancelCtx) // pcok == false when parent == Background()
228 if p, ok := parentCancelCtx(cc.Context); ok != pcok || (ok && pc != p) {
229 t.Errorf("bad linkage: parentCancelCtx(cc.Context) = %v, %v want %v, %v", p, ok, pc, pcok)
234 if len(pc.children) != 1 || !contains(pc.children, cc) {
235 t.Errorf("bad linkage: pc.children = %v, cc = %v", pc.children, cc)
244 if len(pc.children) != 0 {
245 t.Errorf("child's cancel didn't remove self from pc.children = %v", pc.children)
250 // child should be finished.
254 t.Errorf("<-child.Done() blocked, but shouldn't have")
256 if e := child.Err(); e != Canceled {
257 t.Errorf("child.Err() == %v want %v", e, Canceled)
260 // parent should not be finished.
262 case x := <-parent.Done():
263 t.Errorf("<-parent.Done() == %v want nothing (it should block)", x)
266 if e := parent.Err(); e != nil {
267 t.Errorf("parent.Err() == %v want nil", e)
272 func testDeadline(c Context, name string, t testingT) {
275 timer := time.NewTimer(d)
279 t.Fatalf("%s: context not timed out after %v", name, d)
282 if e := c.Err(); e != DeadlineExceeded {
283 t.Errorf("%s: c.Err() == %v; want %v", name, e, DeadlineExceeded)
287 func XTestDeadline(t testingT) {
290 c, _ := WithDeadline(Background(), time.Now().Add(shortDuration))
291 if got, prefix := fmt.Sprint(c), "context.Background.WithDeadline("; !strings.HasPrefix(got, prefix) {
292 t.Errorf("c.String() = %q want prefix %q", got, prefix)
294 testDeadline(c, "WithDeadline", t)
296 c, _ = WithDeadline(Background(), time.Now().Add(shortDuration))
298 testDeadline(o, "WithDeadline+otherContext", t)
300 c, _ = WithDeadline(Background(), time.Now().Add(shortDuration))
302 c, _ = WithDeadline(o, time.Now().Add(veryLongDuration))
303 testDeadline(c, "WithDeadline+otherContext+WithDeadline", t)
305 c, _ = WithDeadline(Background(), time.Now().Add(-shortDuration))
306 testDeadline(c, "WithDeadline+inthepast", t)
308 c, _ = WithDeadline(Background(), time.Now())
309 testDeadline(c, "WithDeadline+now", t)
312 func XTestTimeout(t testingT) {
315 c, _ := WithTimeout(Background(), shortDuration)
316 if got, prefix := fmt.Sprint(c), "context.Background.WithDeadline("; !strings.HasPrefix(got, prefix) {
317 t.Errorf("c.String() = %q want prefix %q", got, prefix)
319 testDeadline(c, "WithTimeout", t)
321 c, _ = WithTimeout(Background(), shortDuration)
323 testDeadline(o, "WithTimeout+otherContext", t)
325 c, _ = WithTimeout(Background(), shortDuration)
327 c, _ = WithTimeout(o, veryLongDuration)
328 testDeadline(c, "WithTimeout+otherContext+WithTimeout", t)
331 func XTestCanceledTimeout(t testingT) {
332 c, _ := WithTimeout(Background(), time.Second)
334 c, cancel := WithTimeout(o, veryLongDuration)
335 cancel() // Should propagate synchronously.
339 t.Errorf("<-c.Done() blocked, but shouldn't have")
341 if e := c.Err(); e != Canceled {
342 t.Errorf("c.Err() == %v want %v", e, Canceled)
350 var k2 = key2(1) // same int as k1, different type
351 var k3 = key2(3) // same type as k2, different int
353 func XTestValues(t testingT) {
354 check := func(c Context, nm, v1, v2, v3 string) {
355 if v, ok := c.Value(k1).(string); ok == (len(v1) == 0) || v != v1 {
356 t.Errorf(`%s.Value(k1).(string) = %q, %t want %q, %t`, nm, v, ok, v1, len(v1) != 0)
358 if v, ok := c.Value(k2).(string); ok == (len(v2) == 0) || v != v2 {
359 t.Errorf(`%s.Value(k2).(string) = %q, %t want %q, %t`, nm, v, ok, v2, len(v2) != 0)
361 if v, ok := c.Value(k3).(string); ok == (len(v3) == 0) || v != v3 {
362 t.Errorf(`%s.Value(k3).(string) = %q, %t want %q, %t`, nm, v, ok, v3, len(v3) != 0)
367 check(c0, "c0", "", "", "")
369 c1 := WithValue(Background(), k1, "c1k1")
370 check(c1, "c1", "c1k1", "", "")
372 if got, want := fmt.Sprint(c1), `context.Background.WithValue(type context.key1, val c1k1)`; got != want {
373 t.Errorf("c.String() = %q want %q", got, want)
376 c2 := WithValue(c1, k2, "c2k2")
377 check(c2, "c2", "c1k1", "c2k2", "")
379 c3 := WithValue(c2, k3, "c3k3")
380 check(c3, "c2", "c1k1", "c2k2", "c3k3")
382 c4 := WithValue(c3, k1, nil)
383 check(c4, "c4", "", "c2k2", "c3k3")
385 o0 := otherContext{Background()}
386 check(o0, "o0", "", "", "")
388 o1 := otherContext{WithValue(Background(), k1, "c1k1")}
389 check(o1, "o1", "c1k1", "", "")
391 o2 := WithValue(o1, k2, "o2k2")
392 check(o2, "o2", "c1k1", "o2k2", "")
394 o3 := otherContext{c4}
395 check(o3, "o3", "", "c2k2", "c3k3")
397 o4 := WithValue(o3, k3, nil)
398 check(o4, "o4", "", "c2k2", "")
401 func XTestAllocs(t testingT, testingShort func() bool, testingAllocsPerRun func(int, func()) float64) {
403 for _, test := range []struct {
410 desc: "Background()",
411 f: func() { Background() },
416 desc: fmt.Sprintf("WithValue(bg, %v, nil)", k1),
418 c := WithValue(bg, k1, nil)
425 desc: "WithTimeout(bg, 1*time.Nanosecond)",
427 c, _ := WithTimeout(bg, 1*time.Nanosecond)
434 desc: "WithCancel(bg)",
436 c, cancel := WithCancel(bg)
444 desc: "WithTimeout(bg, 5*time.Millisecond)",
446 c, cancel := WithTimeout(bg, 5*time.Millisecond)
455 if runtime.Compiler == "gccgo" {
456 // gccgo does not yet do escape analysis.
457 // TODO(iant): Remove this when gccgo does do escape analysis.
458 limit = test.gccgoLimit
464 if n := testingAllocsPerRun(numRuns, test.f); n > limit {
465 t.Errorf("%s allocs = %f want %d", test.desc, n, int(limit))
470 func XTestSimultaneousCancels(t testingT) {
471 root, cancel := WithCancel(Background())
472 m := map[Context]CancelFunc{root: cancel}
474 // Create a tree of contexts.
475 for len(q) != 0 && len(m) < 100 {
478 for i := 0; i < 4; i++ {
479 ctx, cancel := WithCancel(parent)
484 // Start all the cancels in a random order.
485 var wg sync.WaitGroup
487 for _, cancel := range m {
488 go func(cancel CancelFunc) {
495 stuck := make(chan struct{})
496 timer := time.AfterFunc(d, func() { close(stuck) })
499 // Wait on all the contexts in a random order.
504 buf := make([]byte, 10<<10)
505 n := runtime.Stack(buf, true)
506 t.Fatalf("timed out after %v waiting for <-ctx.Done(); stacks:\n%s", d, buf[:n])
509 // Wait for all the cancel functions to return.
510 done := make(chan struct{})
518 buf := make([]byte, 10<<10)
519 n := runtime.Stack(buf, true)
520 t.Fatalf("timed out after %v waiting for cancel functions; stacks:\n%s", d, buf[:n])
524 func XTestInterlockedCancels(t testingT) {
525 parent, cancelParent := WithCancel(Background())
526 child, cancelChild := WithCancel(parent)
533 timer := time.NewTimer(d)
538 buf := make([]byte, 10<<10)
539 n := runtime.Stack(buf, true)
540 t.Fatalf("timed out after %v waiting for child.Done(); stacks:\n%s", d, buf[:n])
544 func XTestLayersCancel(t testingT) {
545 testLayers(t, time.Now().UnixNano(), false)
548 func XTestLayersTimeout(t testingT) {
549 testLayers(t, time.Now().UnixNano(), true)
552 func testLayers(t testingT, seed int64, testTimeout bool) {
555 r := rand.New(rand.NewSource(seed))
556 errorf := func(format string, a ...any) {
557 t.Errorf(fmt.Sprintf("seed=%d: %s", seed, format), a...)
569 for i := 0; i < minLayers || numTimers == 0 || len(cancels) == 0 || len(vals) == 0; i++ {
573 ctx = WithValue(ctx, v, v)
574 vals = append(vals, v)
576 var cancel CancelFunc
577 ctx, cancel = WithCancel(ctx)
578 cancels = append(cancels, cancel)
580 var cancel CancelFunc
581 d := veryLongDuration
585 ctx, cancel = WithTimeout(ctx, d)
586 cancels = append(cancels, cancel)
590 checkValues := func(when string) {
591 for _, key := range vals {
592 if val := ctx.Value(key).(*value); key != val {
593 errorf("%s: ctx.Value(%p) = %p want %p", when, key, val, key)
600 errorf("ctx should not be canceled yet")
604 if s, prefix := fmt.Sprint(ctx), "context.Background."; !strings.HasPrefix(s, prefix) {
605 t.Errorf("ctx.String() = %q want prefix %q", s, prefix)
608 checkValues("before cancel")
611 timer := time.NewTimer(d)
616 errorf("ctx should have timed out after %v", d)
618 checkValues("after timeout")
620 cancel := cancels[r.Intn(len(cancels))]
625 errorf("ctx should be canceled")
627 checkValues("after cancel")
631 func XTestCancelRemoves(t testingT) {
632 checkChildren := func(when string, ctx Context, want int) {
633 if got := len(ctx.(*cancelCtx).children); got != want {
634 t.Errorf("%s: context has %d children, want %d", when, got, want)
638 ctx, _ := WithCancel(Background())
639 checkChildren("after creation", ctx, 0)
640 _, cancel := WithCancel(ctx)
641 checkChildren("with WithCancel child ", ctx, 1)
643 checkChildren("after canceling WithCancel child", ctx, 0)
645 ctx, _ = WithCancel(Background())
646 checkChildren("after creation", ctx, 0)
647 _, cancel = WithTimeout(ctx, 60*time.Minute)
648 checkChildren("with WithTimeout child ", ctx, 1)
650 checkChildren("after canceling WithTimeout child", ctx, 0)
653 func XTestWithCancelCanceledParent(t testingT) {
654 parent, pcancel := WithCancelCause(Background())
655 cause := fmt.Errorf("Because!")
658 c, _ := WithCancel(parent)
662 t.Errorf("child not done immediately upon construction")
664 if got, want := c.Err(), Canceled; got != want {
665 t.Errorf("child not canceled; got = %v, want = %v", got, want)
667 if got, want := Cause(c), cause; got != want {
668 t.Errorf("child has wrong cause; got = %v, want = %v", got, want)
672 func XTestWithValueChecksKey(t testingT) {
673 panicVal := recoveredValue(func() { WithValue(Background(), []byte("foo"), "bar") })
675 t.Error("expected panic")
677 panicVal = recoveredValue(func() { WithValue(Background(), nil, "bar") })
678 if got, want := fmt.Sprint(panicVal), "nil key"; got != want {
679 t.Errorf("panic = %q; want %q", got, want)
683 func XTestInvalidDerivedFail(t testingT) {
684 panicVal := recoveredValue(func() { WithCancel(nil) })
686 t.Error("expected panic")
688 panicVal = recoveredValue(func() { WithDeadline(nil, time.Now().Add(shortDuration)) })
690 t.Error("expected panic")
692 panicVal = recoveredValue(func() { WithValue(nil, "foo", "bar") })
694 t.Error("expected panic")
698 func recoveredValue(fn func()) (v any) {
699 defer func() { v = recover() }()
704 func XTestDeadlineExceededSupportsTimeout(t testingT) {
705 i, ok := DeadlineExceeded.(interface {
709 t.Fatal("DeadlineExceeded does not support Timeout interface")
712 t.Fatal("wrong value for timeout")
720 type myDoneCtx struct {
724 func (d *myDoneCtx) Done() <-chan struct{} {
725 c := make(chan struct{})
729 func XTestCustomContextGoroutines(t testingT) {
730 g := goroutines.Load()
731 checkNoGoroutine := func() {
733 now := goroutines.Load()
735 t.Fatalf("%d goroutines created", now-g)
738 checkCreatedGoroutine := func() {
740 now := goroutines.Load()
742 t.Fatalf("%d goroutines created, want 1", now-g)
747 _, cancel0 := WithCancel(&myDoneCtx{Background()})
749 checkCreatedGoroutine()
751 _, cancel0 = WithTimeout(&myDoneCtx{Background()}, veryLongDuration)
753 checkCreatedGoroutine()
756 defer checkNoGoroutine()
758 ctx1, cancel1 := WithCancel(Background())
763 ctx3, cancel3 := WithCancel(ctx2)
767 _, cancel3b := WithCancel(&myDoneCtx{ctx2})
769 checkCreatedGoroutine() // ctx1 is not providing Done, must not be used
771 ctx4, cancel4 := WithTimeout(ctx3, veryLongDuration)
775 ctx5, cancel5 := WithCancel(ctx4)
782 _, cancel6 := WithTimeout(ctx5, veryLongDuration)
786 // Check applied to canceled context.
789 _, cancel7 := WithCancel(ctx5)
794 func XTestCause(t testingT) {
796 forever = 1e6 * time.Second
797 parentCause = fmt.Errorf("parentCause")
798 childCause = fmt.Errorf("childCause")
799 tooSlow = fmt.Errorf("tooSlow")
800 finishedEarly = fmt.Errorf("finishedEarly")
802 for _, test := range []struct {
822 ctx: func() Context {
823 ctx, cancel := WithCancel(Background())
831 name: "WithCancelCause",
832 ctx: func() Context {
833 ctx, cancel := WithCancelCause(Background())
841 name: "WithCancelCause nil",
842 ctx: func() Context {
843 ctx, cancel := WithCancelCause(Background())
851 name: "WithCancelCause: parent cause before child",
852 ctx: func() Context {
853 ctx, cancelParent := WithCancelCause(Background())
854 ctx, cancelChild := WithCancelCause(ctx)
855 cancelParent(parentCause)
856 cancelChild(childCause)
863 name: "WithCancelCause: parent cause after child",
864 ctx: func() Context {
865 ctx, cancelParent := WithCancelCause(Background())
866 ctx, cancelChild := WithCancelCause(ctx)
867 cancelChild(childCause)
868 cancelParent(parentCause)
875 name: "WithCancelCause: parent cause before nil",
876 ctx: func() Context {
877 ctx, cancelParent := WithCancelCause(Background())
878 ctx, cancelChild := WithCancel(ctx)
879 cancelParent(parentCause)
887 name: "WithCancelCause: parent cause after nil",
888 ctx: func() Context {
889 ctx, cancelParent := WithCancelCause(Background())
890 ctx, cancelChild := WithCancel(ctx)
892 cancelParent(parentCause)
899 name: "WithCancelCause: child cause after nil",
900 ctx: func() Context {
901 ctx, cancelParent := WithCancel(Background())
902 ctx, cancelChild := WithCancelCause(ctx)
904 cancelChild(childCause)
911 name: "WithCancelCause: child cause before nil",
912 ctx: func() Context {
913 ctx, cancelParent := WithCancel(Background())
914 ctx, cancelChild := WithCancelCause(ctx)
915 cancelChild(childCause)
924 ctx: func() Context {
925 ctx, cancel := WithTimeout(Background(), 0)
929 err: DeadlineExceeded,
930 cause: DeadlineExceeded,
933 name: "WithTimeout canceled",
934 ctx: func() Context {
935 ctx, cancel := WithTimeout(Background(), forever)
943 name: "WithTimeoutCause",
944 ctx: func() Context {
945 ctx, cancel := WithTimeoutCause(Background(), 0, tooSlow)
949 err: DeadlineExceeded,
953 name: "WithTimeoutCause canceled",
954 ctx: func() Context {
955 ctx, cancel := WithTimeoutCause(Background(), forever, tooSlow)
963 name: "WithTimeoutCause stacked",
964 ctx: func() Context {
965 ctx, cancel := WithCancelCause(Background())
966 ctx, _ = WithTimeoutCause(ctx, 0, tooSlow)
967 cancel(finishedEarly)
970 err: DeadlineExceeded,
974 name: "WithTimeoutCause stacked canceled",
975 ctx: func() Context {
976 ctx, cancel := WithCancelCause(Background())
977 ctx, _ = WithTimeoutCause(ctx, forever, tooSlow)
978 cancel(finishedEarly)
982 cause: finishedEarly,
985 name: "WithoutCancel",
986 ctx: func() Context {
987 return WithoutCancel(Background())
993 name: "WithoutCancel canceled",
994 ctx: func() Context {
995 ctx, cancel := WithCancelCause(Background())
996 ctx = WithoutCancel(ctx)
997 cancel(finishedEarly)
1004 name: "WithoutCancel timeout",
1005 ctx: func() Context {
1006 ctx, cancel := WithTimeoutCause(Background(), 0, tooSlow)
1007 ctx = WithoutCancel(ctx)
1015 if got, want := test.ctx.Err(), test.err; want != got {
1016 t.Errorf("%s: ctx.Err() = %v want %v", test.name, got, want)
1018 if got, want := Cause(test.ctx), test.cause; want != got {
1019 t.Errorf("%s: Cause(ctx) = %v want %v", test.name, got, want)
1024 func XTestCauseRace(t testingT) {
1025 cause := errors.New("TestCauseRace")
1026 ctx, cancel := WithCancelCause(Background())
1031 // Poll Cause, rather than waiting for Done, to test that
1032 // access to the underlying cause is synchronized properly.
1033 if err := Cause(ctx); err != nil {
1035 t.Errorf("Cause returned %v, want %v", err, cause)
1043 func XTestWithoutCancel(t testingT) {
1044 key, value := "key", "value"
1045 ctx := WithValue(Background(), key, value)
1046 ctx = WithoutCancel(ctx)
1047 if d, ok := ctx.Deadline(); !d.IsZero() || ok != false {
1048 t.Errorf("ctx.Deadline() = %v, %v want zero, false", d, ok)
1050 if done := ctx.Done(); done != nil {
1051 t.Errorf("ctx.Deadline() = %v want nil", done)
1053 if err := ctx.Err(); err != nil {
1054 t.Errorf("ctx.Err() = %v want nil", err)
1056 if v := ctx.Value(key); v != value {
1057 t.Errorf("ctx.Value(%q) = %q want %q", key, v, value)