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.
4
5package context
6
7import (
8	"fmt"
9	"math/rand"
10	"runtime"
11	"strings"
12	"sync"
13	"sync/atomic"
14	"time"
15)
16
17type testingT interface {
18	Deadline() (time.Time, bool)
19	Error(args ...interface{})
20	Errorf(format string, args ...interface{})
21	Fail()
22	FailNow()
23	Failed() bool
24	Fatal(args ...interface{})
25	Fatalf(format string, args ...interface{})
26	Helper()
27	Log(args ...interface{})
28	Logf(format string, args ...interface{})
29	Name() string
30	Parallel()
31	Skip(args ...interface{})
32	SkipNow()
33	Skipf(format string, args ...interface{})
34	Skipped() bool
35}
36
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
39// Context.
40type otherContext struct {
41	Context
42}
43
44const (
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
47)
48
49// quiescent returns an arbitrary duration by which the program should have
50// completed any remaining work and reached a steady (idle) state.
51func quiescent(t testingT) time.Duration {
52	deadline, ok := t.Deadline()
53	if !ok {
54		return 5 * time.Second
55	}
56
57	const arbitraryCleanupMargin = 1 * time.Second
58	return time.Until(deadline) - arbitraryCleanupMargin
59}
60
61func XTestBackground(t testingT) {
62	c := Background()
63	if c == nil {
64		t.Fatalf("Background returned nil")
65	}
66	select {
67	case x := <-c.Done():
68		t.Errorf("<-c.Done() == %v want nothing (it should block)", x)
69	default:
70	}
71	if got, want := fmt.Sprint(c), "context.Background"; got != want {
72		t.Errorf("Background().String() = %q want %q", got, want)
73	}
74}
75
76func XTestTODO(t testingT) {
77	c := TODO()
78	if c == nil {
79		t.Fatalf("TODO returned nil")
80	}
81	select {
82	case x := <-c.Done():
83		t.Errorf("<-c.Done() == %v want nothing (it should block)", x)
84	default:
85	}
86	if got, want := fmt.Sprint(c), "context.TODO"; got != want {
87		t.Errorf("TODO().String() = %q want %q", got, want)
88	}
89}
90
91func XTestWithCancel(t testingT) {
92	c1, cancel := WithCancel(Background())
93
94	if got, want := fmt.Sprint(c1), "context.Background.WithCancel"; got != want {
95		t.Errorf("c1.String() = %q want %q", got, want)
96	}
97
98	o := otherContext{c1}
99	c2, _ := WithCancel(o)
100	contexts := []Context{c1, o, c2}
101
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)
105		}
106		if e := c.Err(); e != nil {
107			t.Errorf("c[%d].Err() == %v want nil", i, e)
108		}
109
110		select {
111		case x := <-c.Done():
112			t.Errorf("<-c.Done() == %v want nothing (it should block)", x)
113		default:
114		}
115	}
116
117	cancel() // Should propagate synchronously.
118	for i, c := range contexts {
119		select {
120		case <-c.Done():
121		default:
122			t.Errorf("<-c[%d].Done() blocked, but shouldn't have", i)
123		}
124		if e := c.Err(); e != Canceled {
125			t.Errorf("c[%d].Err() == %v want %v", i, e, Canceled)
126		}
127	}
128}
129
130func contains(m map[canceler]struct{}, key canceler) bool {
131	_, ret := m[key]
132	return ret
133}
134
135func XTestParentFinishesChild(t testingT) {
136	// Context tree:
137	// parent -> cancelChild
138	// parent -> valueChild -> timerChild
139	parent, cancel := WithCancel(Background())
140	cancelChild, stop := WithCancel(parent)
141	defer stop()
142	valueChild := WithValue(parent, "key", "value")
143	timerChild, stop := WithTimeout(valueChild, veryLongDuration)
144	defer stop()
145
146	select {
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)
155	default:
156	}
157
158	// The parent's children should contain the two cancelable children.
159	pc := parent.(*cancelCtx)
160	cc := cancelChild.(*cancelCtx)
161	tc := timerChild.(*timerCtx)
162	pc.mu.Lock()
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",
165			pc.children, cc, tc)
166	}
167	pc.mu.Unlock()
168
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)
171	}
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)
174	}
175
176	cancel()
177
178	pc.mu.Lock()
179	if len(pc.children) != 0 {
180		t.Errorf("pc.cancel didn't clear pc.children = %v", pc.children)
181	}
182	pc.mu.Unlock()
183
184	// parent and children should all be finished.
185	check := func(ctx Context, name string) {
186		select {
187		case <-ctx.Done():
188		default:
189			t.Errorf("<-%s.Done() blocked, but shouldn't have", name)
190		}
191		if e := ctx.Err(); e != Canceled {
192			t.Errorf("%s.Err() == %v want %v", name, e, Canceled)
193		}
194	}
195	check(parent, "parent")
196	check(cancelChild, "cancelChild")
197	check(valueChild, "valueChild")
198	check(timerChild, "timerChild")
199
200	// WithCancel should return a canceled context on a canceled parent.
201	precanceledChild := WithValue(parent, "key", "value")
202	select {
203	case <-precanceledChild.Done():
204	default:
205		t.Errorf("<-precanceledChild.Done() blocked, but shouldn't have")
206	}
207	if e := precanceledChild.Err(); e != Canceled {
208		t.Errorf("precanceledChild.Err() == %v want %v", e, Canceled)
209	}
210}
211
212func XTestChildFinishesFirst(t testingT) {
213	cancelable, stop := WithCancel(Background())
214	defer stop()
215	for _, parent := range []Context{Background(), cancelable} {
216		child, cancel := WithCancel(parent)
217
218		select {
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)
223		default:
224		}
225
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)
230		}
231
232		if pcok {
233			pc.mu.Lock()
234			if len(pc.children) != 1 || !contains(pc.children, cc) {
235				t.Errorf("bad linkage: pc.children = %v, cc = %v", pc.children, cc)
236			}
237			pc.mu.Unlock()
238		}
239
240		cancel()
241
242		if pcok {
243			pc.mu.Lock()
244			if len(pc.children) != 0 {
245				t.Errorf("child's cancel didn't remove self from pc.children = %v", pc.children)
246			}
247			pc.mu.Unlock()
248		}
249
250		// child should be finished.
251		select {
252		case <-child.Done():
253		default:
254			t.Errorf("<-child.Done() blocked, but shouldn't have")
255		}
256		if e := child.Err(); e != Canceled {
257			t.Errorf("child.Err() == %v want %v", e, Canceled)
258		}
259
260		// parent should not be finished.
261		select {
262		case x := <-parent.Done():
263			t.Errorf("<-parent.Done() == %v want nothing (it should block)", x)
264		default:
265		}
266		if e := parent.Err(); e != nil {
267			t.Errorf("parent.Err() == %v want nil", e)
268		}
269	}
270}
271
272func testDeadline(c Context, name string, t testingT) {
273	t.Helper()
274	d := quiescent(t)
275	timer := time.NewTimer(d)
276	defer timer.Stop()
277	select {
278	case <-timer.C:
279		t.Fatalf("%s: context not timed out after %v", name, d)
280	case <-c.Done():
281	}
282	if e := c.Err(); e != DeadlineExceeded {
283		t.Errorf("%s: c.Err() == %v; want %v", name, e, DeadlineExceeded)
284	}
285}
286
287func XTestDeadline(t testingT) {
288	t.Parallel()
289
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)
293	}
294	testDeadline(c, "WithDeadline", t)
295
296	c, _ = WithDeadline(Background(), time.Now().Add(shortDuration))
297	o := otherContext{c}
298	testDeadline(o, "WithDeadline+otherContext", t)
299
300	c, _ = WithDeadline(Background(), time.Now().Add(shortDuration))
301	o = otherContext{c}
302	c, _ = WithDeadline(o, time.Now().Add(veryLongDuration))
303	testDeadline(c, "WithDeadline+otherContext+WithDeadline", t)
304
305	c, _ = WithDeadline(Background(), time.Now().Add(-shortDuration))
306	testDeadline(c, "WithDeadline+inthepast", t)
307
308	c, _ = WithDeadline(Background(), time.Now())
309	testDeadline(c, "WithDeadline+now", t)
310}
311
312func XTestTimeout(t testingT) {
313	t.Parallel()
314
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)
318	}
319	testDeadline(c, "WithTimeout", t)
320
321	c, _ = WithTimeout(Background(), shortDuration)
322	o := otherContext{c}
323	testDeadline(o, "WithTimeout+otherContext", t)
324
325	c, _ = WithTimeout(Background(), shortDuration)
326	o = otherContext{c}
327	c, _ = WithTimeout(o, veryLongDuration)
328	testDeadline(c, "WithTimeout+otherContext+WithTimeout", t)
329}
330
331func XTestCanceledTimeout(t testingT) {
332	c, _ := WithTimeout(Background(), time.Second)
333	o := otherContext{c}
334	c, cancel := WithTimeout(o, veryLongDuration)
335	cancel() // Should propagate synchronously.
336	select {
337	case <-c.Done():
338	default:
339		t.Errorf("<-c.Done() blocked, but shouldn't have")
340	}
341	if e := c.Err(); e != Canceled {
342		t.Errorf("c.Err() == %v want %v", e, Canceled)
343	}
344}
345
346type key1 int
347type key2 int
348
349var k1 = key1(1)
350var k2 = key2(1) // same int as k1, different type
351var k3 = key2(3) // same type as k2, different int
352
353func 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)
357		}
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)
360		}
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)
363		}
364	}
365
366	c0 := Background()
367	check(c0, "c0", "", "", "")
368
369	c1 := WithValue(Background(), k1, "c1k1")
370	check(c1, "c1", "c1k1", "", "")
371
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)
374	}
375
376	c2 := WithValue(c1, k2, "c2k2")
377	check(c2, "c2", "c1k1", "c2k2", "")
378
379	c3 := WithValue(c2, k3, "c3k3")
380	check(c3, "c2", "c1k1", "c2k2", "c3k3")
381
382	c4 := WithValue(c3, k1, nil)
383	check(c4, "c4", "", "c2k2", "c3k3")
384
385	o0 := otherContext{Background()}
386	check(o0, "o0", "", "", "")
387
388	o1 := otherContext{WithValue(Background(), k1, "c1k1")}
389	check(o1, "o1", "c1k1", "", "")
390
391	o2 := WithValue(o1, k2, "o2k2")
392	check(o2, "o2", "c1k1", "o2k2", "")
393
394	o3 := otherContext{c4}
395	check(o3, "o3", "", "c2k2", "c3k3")
396
397	o4 := WithValue(o3, k3, nil)
398	check(o4, "o4", "", "c2k2", "")
399}
400
401func XTestAllocs(t testingT, testingShort func() bool, testingAllocsPerRun func(int, func()) float64) {
402	bg := Background()
403	for _, test := range []struct {
404		desc       string
405		f          func()
406		limit      float64
407		gccgoLimit float64
408	}{
409		{
410			desc:       "Background()",
411			f:          func() { Background() },
412			limit:      0,
413			gccgoLimit: 0,
414		},
415		{
416			desc: fmt.Sprintf("WithValue(bg, %v, nil)", k1),
417			f: func() {
418				c := WithValue(bg, k1, nil)
419				c.Value(k1)
420			},
421			limit:      3,
422			gccgoLimit: 3,
423		},
424		{
425			desc: "WithTimeout(bg, 1*time.Nanosecond)",
426			f: func() {
427				c, _ := WithTimeout(bg, 1*time.Nanosecond)
428				<-c.Done()
429			},
430			limit:      12,
431			gccgoLimit: 15,
432		},
433		{
434			desc: "WithCancel(bg)",
435			f: func() {
436				c, cancel := WithCancel(bg)
437				cancel()
438				<-c.Done()
439			},
440			limit:      5,
441			gccgoLimit: 8,
442		},
443		{
444			desc: "WithTimeout(bg, 5*time.Millisecond)",
445			f: func() {
446				c, cancel := WithTimeout(bg, 5*time.Millisecond)
447				cancel()
448				<-c.Done()
449			},
450			limit:      8,
451			gccgoLimit: 25,
452		},
453	} {
454		limit := test.limit
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
459		}
460		numRuns := 100
461		if testingShort() {
462			numRuns = 10
463		}
464		if n := testingAllocsPerRun(numRuns, test.f); n > limit {
465			t.Errorf("%s allocs = %f want %d", test.desc, n, int(limit))
466		}
467	}
468}
469
470func XTestSimultaneousCancels(t testingT) {
471	root, cancel := WithCancel(Background())
472	m := map[Context]CancelFunc{root: cancel}
473	q := []Context{root}
474	// Create a tree of contexts.
475	for len(q) != 0 && len(m) < 100 {
476		parent := q[0]
477		q = q[1:]
478		for i := 0; i < 4; i++ {
479			ctx, cancel := WithCancel(parent)
480			m[ctx] = cancel
481			q = append(q, ctx)
482		}
483	}
484	// Start all the cancels in a random order.
485	var wg sync.WaitGroup
486	wg.Add(len(m))
487	for _, cancel := range m {
488		go func(cancel CancelFunc) {
489			cancel()
490			wg.Done()
491		}(cancel)
492	}
493
494	d := quiescent(t)
495	stuck := make(chan struct{})
496	timer := time.AfterFunc(d, func() { close(stuck) })
497	defer timer.Stop()
498
499	// Wait on all the contexts in a random order.
500	for ctx := range m {
501		select {
502		case <-ctx.Done():
503		case <-stuck:
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])
507		}
508	}
509	// Wait for all the cancel functions to return.
510	done := make(chan struct{})
511	go func() {
512		wg.Wait()
513		close(done)
514	}()
515	select {
516	case <-done:
517	case <-stuck:
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])
521	}
522}
523
524func XTestInterlockedCancels(t testingT) {
525	parent, cancelParent := WithCancel(Background())
526	child, cancelChild := WithCancel(parent)
527	go func() {
528		parent.Done()
529		cancelChild()
530	}()
531	cancelParent()
532	d := quiescent(t)
533	timer := time.NewTimer(d)
534	defer timer.Stop()
535	select {
536	case <-child.Done():
537	case <-timer.C:
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])
541	}
542}
543
544func XTestLayersCancel(t testingT) {
545	testLayers(t, time.Now().UnixNano(), false)
546}
547
548func XTestLayersTimeout(t testingT) {
549	testLayers(t, time.Now().UnixNano(), true)
550}
551
552func testLayers(t testingT, seed int64, testTimeout bool) {
553	t.Parallel()
554
555	r := rand.New(rand.NewSource(seed))
556	errorf := func(format string, a ...interface{}) {
557		t.Errorf(fmt.Sprintf("seed=%d: %s", seed, format), a...)
558	}
559	const (
560		minLayers = 30
561	)
562	type value int
563	var (
564		vals      []*value
565		cancels   []CancelFunc
566		numTimers int
567		ctx       = Background()
568	)
569	for i := 0; i < minLayers || numTimers == 0 || len(cancels) == 0 || len(vals) == 0; i++ {
570		switch r.Intn(3) {
571		case 0:
572			v := new(value)
573			ctx = WithValue(ctx, v, v)
574			vals = append(vals, v)
575		case 1:
576			var cancel CancelFunc
577			ctx, cancel = WithCancel(ctx)
578			cancels = append(cancels, cancel)
579		case 2:
580			var cancel CancelFunc
581			d := veryLongDuration
582			if testTimeout {
583				d = shortDuration
584			}
585			ctx, cancel = WithTimeout(ctx, d)
586			cancels = append(cancels, cancel)
587			numTimers++
588		}
589	}
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)
594			}
595		}
596	}
597	if !testTimeout {
598		select {
599		case <-ctx.Done():
600			errorf("ctx should not be canceled yet")
601		default:
602		}
603	}
604	if s, prefix := fmt.Sprint(ctx), "context.Background."; !strings.HasPrefix(s, prefix) {
605		t.Errorf("ctx.String() = %q want prefix %q", s, prefix)
606	}
607	t.Log(ctx)
608	checkValues("before cancel")
609	if testTimeout {
610		d := quiescent(t)
611		timer := time.NewTimer(d)
612		defer timer.Stop()
613		select {
614		case <-ctx.Done():
615		case <-timer.C:
616			errorf("ctx should have timed out after %v", d)
617		}
618		checkValues("after timeout")
619	} else {
620		cancel := cancels[r.Intn(len(cancels))]
621		cancel()
622		select {
623		case <-ctx.Done():
624		default:
625			errorf("ctx should be canceled")
626		}
627		checkValues("after cancel")
628	}
629}
630
631func 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)
635		}
636	}
637
638	ctx, _ := WithCancel(Background())
639	checkChildren("after creation", ctx, 0)
640	_, cancel := WithCancel(ctx)
641	checkChildren("with WithCancel child ", ctx, 1)
642	cancel()
643	checkChildren("after canceling WithCancel child", ctx, 0)
644
645	ctx, _ = WithCancel(Background())
646	checkChildren("after creation", ctx, 0)
647	_, cancel = WithTimeout(ctx, 60*time.Minute)
648	checkChildren("with WithTimeout child ", ctx, 1)
649	cancel()
650	checkChildren("after canceling WithTimeout child", ctx, 0)
651}
652
653func XTestWithCancelCanceledParent(t testingT) {
654	parent, pcancel := WithCancel(Background())
655	pcancel()
656
657	c, _ := WithCancel(parent)
658	select {
659	case <-c.Done():
660	default:
661		t.Errorf("child not done immediately upon construction")
662	}
663	if got, want := c.Err(), Canceled; got != want {
664		t.Errorf("child not cancelled; got = %v, want = %v", got, want)
665	}
666}
667
668func XTestWithValueChecksKey(t testingT) {
669	panicVal := recoveredValue(func() { WithValue(Background(), []byte("foo"), "bar") })
670	if panicVal == nil {
671		t.Error("expected panic")
672	}
673	panicVal = recoveredValue(func() { WithValue(Background(), nil, "bar") })
674	if got, want := fmt.Sprint(panicVal), "nil key"; got != want {
675		t.Errorf("panic = %q; want %q", got, want)
676	}
677}
678
679func XTestInvalidDerivedFail(t testingT) {
680	panicVal := recoveredValue(func() { WithCancel(nil) })
681	if panicVal == nil {
682		t.Error("expected panic")
683	}
684	panicVal = recoveredValue(func() { WithDeadline(nil, time.Now().Add(shortDuration)) })
685	if panicVal == nil {
686		t.Error("expected panic")
687	}
688	panicVal = recoveredValue(func() { WithValue(nil, "foo", "bar") })
689	if panicVal == nil {
690		t.Error("expected panic")
691	}
692}
693
694func recoveredValue(fn func()) (v interface{}) {
695	defer func() { v = recover() }()
696	fn()
697	return
698}
699
700func XTestDeadlineExceededSupportsTimeout(t testingT) {
701	i, ok := DeadlineExceeded.(interface {
702		Timeout() bool
703	})
704	if !ok {
705		t.Fatal("DeadlineExceeded does not support Timeout interface")
706	}
707	if !i.Timeout() {
708		t.Fatal("wrong value for timeout")
709	}
710}
711
712type myCtx struct {
713	Context
714}
715
716type myDoneCtx struct {
717	Context
718}
719
720func (d *myDoneCtx) Done() <-chan struct{} {
721	c := make(chan struct{})
722	return c
723}
724
725func XTestCustomContextGoroutines(t testingT) {
726	g := atomic.LoadInt32(&goroutines)
727	checkNoGoroutine := func() {
728		t.Helper()
729		now := atomic.LoadInt32(&goroutines)
730		if now != g {
731			t.Fatalf("%d goroutines created", now-g)
732		}
733	}
734	checkCreatedGoroutine := func() {
735		t.Helper()
736		now := atomic.LoadInt32(&goroutines)
737		if now != g+1 {
738			t.Fatalf("%d goroutines created, want 1", now-g)
739		}
740		g = now
741	}
742
743	_, cancel0 := WithCancel(&myDoneCtx{Background()})
744	cancel0()
745	checkCreatedGoroutine()
746
747	_, cancel0 = WithTimeout(&myDoneCtx{Background()}, veryLongDuration)
748	cancel0()
749	checkCreatedGoroutine()
750
751	checkNoGoroutine()
752	defer checkNoGoroutine()
753
754	ctx1, cancel1 := WithCancel(Background())
755	defer cancel1()
756	checkNoGoroutine()
757
758	ctx2 := &myCtx{ctx1}
759	ctx3, cancel3 := WithCancel(ctx2)
760	defer cancel3()
761	checkNoGoroutine()
762
763	_, cancel3b := WithCancel(&myDoneCtx{ctx2})
764	defer cancel3b()
765	checkCreatedGoroutine() // ctx1 is not providing Done, must not be used
766
767	ctx4, cancel4 := WithTimeout(ctx3, veryLongDuration)
768	defer cancel4()
769	checkNoGoroutine()
770
771	ctx5, cancel5 := WithCancel(ctx4)
772	defer cancel5()
773	checkNoGoroutine()
774
775	cancel5()
776	checkNoGoroutine()
777
778	_, cancel6 := WithTimeout(ctx5, veryLongDuration)
779	defer cancel6()
780	checkNoGoroutine()
781
782	// Check applied to cancelled context.
783	cancel6()
784	cancel1()
785	_, cancel7 := WithCancel(ctx5)
786	defer cancel7()
787	checkNoGoroutine()
788}
789