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.
7 // Tests in package context cannot depend directly on package testing due to an import cycle.
8 // If your test does requires access to unexported members of the context package,
9 // add your test below as `func XTestFoo(t testingT)` and add a `TestFoo` to x_test.go
10 // that calls it. Otherwise, write a regular test in a test.go file in package context_test.
16 type testingT interface {
17 Deadline() (time.Time, bool)
19 Errorf(format string, args ...any)
24 Fatalf(format string, args ...any)
27 Logf(format string, args ...any)
32 Skipf(format string, args ...any)
36 const veryLongDuration = 1000 * time.Hour // an arbitrary upper bound on the test's running time
38 func contains(m map[canceler]struct{}, key canceler) bool {
43 func XTestParentFinishesChild(t testingT) {
45 // parent -> cancelChild
46 // parent -> valueChild -> timerChild
47 parent, cancel := WithCancel(Background())
48 cancelChild, stop := WithCancel(parent)
50 valueChild := WithValue(parent, "key", "value")
51 timerChild, stop := WithTimeout(valueChild, veryLongDuration)
55 case x := <-parent.Done():
56 t.Errorf("<-parent.Done() == %v want nothing (it should block)", x)
57 case x := <-cancelChild.Done():
58 t.Errorf("<-cancelChild.Done() == %v want nothing (it should block)", x)
59 case x := <-timerChild.Done():
60 t.Errorf("<-timerChild.Done() == %v want nothing (it should block)", x)
61 case x := <-valueChild.Done():
62 t.Errorf("<-valueChild.Done() == %v want nothing (it should block)", x)
66 // The parent's children should contain the two cancelable children.
67 pc := parent.(*cancelCtx)
68 cc := cancelChild.(*cancelCtx)
69 tc := timerChild.(*timerCtx)
71 if len(pc.children) != 2 || !contains(pc.children, cc) || !contains(pc.children, tc) {
72 t.Errorf("bad linkage: pc.children = %v, want %v and %v",
77 if p, ok := parentCancelCtx(cc.Context); !ok || p != pc {
78 t.Errorf("bad linkage: parentCancelCtx(cancelChild.Context) = %v, %v want %v, true", p, ok, pc)
80 if p, ok := parentCancelCtx(tc.Context); !ok || p != pc {
81 t.Errorf("bad linkage: parentCancelCtx(timerChild.Context) = %v, %v want %v, true", p, ok, pc)
87 if len(pc.children) != 0 {
88 t.Errorf("pc.cancel didn't clear pc.children = %v", pc.children)
92 // parent and children should all be finished.
93 check := func(ctx Context, name string) {
97 t.Errorf("<-%s.Done() blocked, but shouldn't have", name)
99 if e := ctx.Err(); e != Canceled {
100 t.Errorf("%s.Err() == %v want %v", name, e, Canceled)
103 check(parent, "parent")
104 check(cancelChild, "cancelChild")
105 check(valueChild, "valueChild")
106 check(timerChild, "timerChild")
108 // WithCancel should return a canceled context on a canceled parent.
109 precanceledChild := WithValue(parent, "key", "value")
111 case <-precanceledChild.Done():
113 t.Errorf("<-precanceledChild.Done() blocked, but shouldn't have")
115 if e := precanceledChild.Err(); e != Canceled {
116 t.Errorf("precanceledChild.Err() == %v want %v", e, Canceled)
120 func XTestChildFinishesFirst(t testingT) {
121 cancelable, stop := WithCancel(Background())
123 for _, parent := range []Context{Background(), cancelable} {
124 child, cancel := WithCancel(parent)
127 case x := <-parent.Done():
128 t.Errorf("<-parent.Done() == %v want nothing (it should block)", x)
129 case x := <-child.Done():
130 t.Errorf("<-child.Done() == %v want nothing (it should block)", x)
134 cc := child.(*cancelCtx)
135 pc, pcok := parent.(*cancelCtx) // pcok == false when parent == Background()
136 if p, ok := parentCancelCtx(cc.Context); ok != pcok || (ok && pc != p) {
137 t.Errorf("bad linkage: parentCancelCtx(cc.Context) = %v, %v want %v, %v", p, ok, pc, pcok)
142 if len(pc.children) != 1 || !contains(pc.children, cc) {
143 t.Errorf("bad linkage: pc.children = %v, cc = %v", pc.children, cc)
152 if len(pc.children) != 0 {
153 t.Errorf("child's cancel didn't remove self from pc.children = %v", pc.children)
158 // child should be finished.
162 t.Errorf("<-child.Done() blocked, but shouldn't have")
164 if e := child.Err(); e != Canceled {
165 t.Errorf("child.Err() == %v want %v", e, Canceled)
168 // parent should not be finished.
170 case x := <-parent.Done():
171 t.Errorf("<-parent.Done() == %v want nothing (it should block)", x)
174 if e := parent.Err(); e != nil {
175 t.Errorf("parent.Err() == %v want nil", e)
180 func XTestCancelRemoves(t testingT) {
181 checkChildren := func(when string, ctx Context, want int) {
182 if got := len(ctx.(*cancelCtx).children); got != want {
183 t.Errorf("%s: context has %d children, want %d", when, got, want)
187 ctx, _ := WithCancel(Background())
188 checkChildren("after creation", ctx, 0)
189 _, cancel := WithCancel(ctx)
190 checkChildren("with WithCancel child ", ctx, 1)
192 checkChildren("after canceling WithCancel child", ctx, 0)
194 ctx, _ = WithCancel(Background())
195 checkChildren("after creation", ctx, 0)
196 _, cancel = WithTimeout(ctx, 60*time.Minute)
197 checkChildren("with WithTimeout child ", ctx, 1)
199 checkChildren("after canceling WithTimeout child", ctx, 0)
206 type myDoneCtx struct {
210 func (d *myDoneCtx) Done() <-chan struct{} {
211 c := make(chan struct{})
214 func XTestCustomContextGoroutines(t testingT) {
215 g := goroutines.Load()
216 checkNoGoroutine := func() {
218 now := goroutines.Load()
220 t.Fatalf("%d goroutines created", now-g)
223 checkCreatedGoroutine := func() {
225 now := goroutines.Load()
227 t.Fatalf("%d goroutines created, want 1", now-g)
232 _, cancel0 := WithCancel(&myDoneCtx{Background()})
234 checkCreatedGoroutine()
236 _, cancel0 = WithTimeout(&myDoneCtx{Background()}, veryLongDuration)
238 checkCreatedGoroutine()
241 defer checkNoGoroutine()
243 ctx1, cancel1 := WithCancel(Background())
248 ctx3, cancel3 := WithCancel(ctx2)
252 _, cancel3b := WithCancel(&myDoneCtx{ctx2})
254 checkCreatedGoroutine() // ctx1 is not providing Done, must not be used
256 ctx4, cancel4 := WithTimeout(ctx3, veryLongDuration)
260 ctx5, cancel5 := WithCancel(ctx4)
267 _, cancel6 := WithTimeout(ctx5, veryLongDuration)
271 // Check applied to canceled context.
274 _, cancel7 := WithCancel(ctx5)