]> Cypherpunks.ru repositories - gostls13.git/blob - src/context/x_test.go
context: add AfterFunc
[gostls13.git] / src / context / x_test.go
1 // Copyright 2016 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
5 package context_test
6
7 import (
8         . "context"
9         "errors"
10         "fmt"
11         "math/rand"
12         "runtime"
13         "strings"
14         "sync"
15         "testing"
16         "time"
17 )
18
19 // Each XTestFoo in context_test.go must be called from a TestFoo here to run.
20 func TestParentFinishesChild(t *testing.T) {
21         XTestParentFinishesChild(t) // uses unexported context types
22 }
23 func TestChildFinishesFirst(t *testing.T) {
24         XTestChildFinishesFirst(t) // uses unexported context types
25 }
26 func TestCancelRemoves(t *testing.T) {
27         XTestCancelRemoves(t) // uses unexported context types
28 }
29 func TestCustomContextGoroutines(t *testing.T) {
30         XTestCustomContextGoroutines(t) // reads the context.goroutines counter
31 }
32
33 // The following are regular tests in package context_test.
34
35 // otherContext is a Context that's not one of the types defined in context.go.
36 // This lets us test code paths that differ based on the underlying type of the
37 // Context.
38 type otherContext struct {
39         Context
40 }
41
42 const (
43         shortDuration    = 1 * time.Millisecond // a reasonable duration to block in a test
44         veryLongDuration = 1000 * time.Hour     // an arbitrary upper bound on the test's running time
45 )
46
47 // quiescent returns an arbitrary duration by which the program should have
48 // completed any remaining work and reached a steady (idle) state.
49 func quiescent(t *testing.T) time.Duration {
50         deadline, ok := t.Deadline()
51         if !ok {
52                 return 5 * time.Second
53         }
54
55         const arbitraryCleanupMargin = 1 * time.Second
56         return time.Until(deadline) - arbitraryCleanupMargin
57 }
58 func TestBackground(t *testing.T) {
59         c := Background()
60         if c == nil {
61                 t.Fatalf("Background returned nil")
62         }
63         select {
64         case x := <-c.Done():
65                 t.Errorf("<-c.Done() == %v want nothing (it should block)", x)
66         default:
67         }
68         if got, want := fmt.Sprint(c), "context.Background"; got != want {
69                 t.Errorf("Background().String() = %q want %q", got, want)
70         }
71 }
72
73 func TestTODO(t *testing.T) {
74         c := TODO()
75         if c == nil {
76                 t.Fatalf("TODO returned nil")
77         }
78         select {
79         case x := <-c.Done():
80                 t.Errorf("<-c.Done() == %v want nothing (it should block)", x)
81         default:
82         }
83         if got, want := fmt.Sprint(c), "context.TODO"; got != want {
84                 t.Errorf("TODO().String() = %q want %q", got, want)
85         }
86 }
87
88 func TestWithCancel(t *testing.T) {
89         c1, cancel := WithCancel(Background())
90
91         if got, want := fmt.Sprint(c1), "context.Background.WithCancel"; got != want {
92                 t.Errorf("c1.String() = %q want %q", got, want)
93         }
94
95         o := otherContext{c1}
96         c2, _ := WithCancel(o)
97         contexts := []Context{c1, o, c2}
98
99         for i, c := range contexts {
100                 if d := c.Done(); d == nil {
101                         t.Errorf("c[%d].Done() == %v want non-nil", i, d)
102                 }
103                 if e := c.Err(); e != nil {
104                         t.Errorf("c[%d].Err() == %v want nil", i, e)
105                 }
106
107                 select {
108                 case x := <-c.Done():
109                         t.Errorf("<-c.Done() == %v want nothing (it should block)", x)
110                 default:
111                 }
112         }
113
114         cancel() // Should propagate synchronously.
115         for i, c := range contexts {
116                 select {
117                 case <-c.Done():
118                 default:
119                         t.Errorf("<-c[%d].Done() blocked, but shouldn't have", i)
120                 }
121                 if e := c.Err(); e != Canceled {
122                         t.Errorf("c[%d].Err() == %v want %v", i, e, Canceled)
123                 }
124         }
125 }
126
127 func testDeadline(c Context, name string, t *testing.T) {
128         t.Helper()
129         d := quiescent(t)
130         timer := time.NewTimer(d)
131         defer timer.Stop()
132         select {
133         case <-timer.C:
134                 t.Fatalf("%s: context not timed out after %v", name, d)
135         case <-c.Done():
136         }
137         if e := c.Err(); e != DeadlineExceeded {
138                 t.Errorf("%s: c.Err() == %v; want %v", name, e, DeadlineExceeded)
139         }
140 }
141
142 func TestDeadline(t *testing.T) {
143         t.Parallel()
144
145         c, _ := WithDeadline(Background(), time.Now().Add(shortDuration))
146         if got, prefix := fmt.Sprint(c), "context.Background.WithDeadline("; !strings.HasPrefix(got, prefix) {
147                 t.Errorf("c.String() = %q want prefix %q", got, prefix)
148         }
149         testDeadline(c, "WithDeadline", t)
150
151         c, _ = WithDeadline(Background(), time.Now().Add(shortDuration))
152         o := otherContext{c}
153         testDeadline(o, "WithDeadline+otherContext", t)
154
155         c, _ = WithDeadline(Background(), time.Now().Add(shortDuration))
156         o = otherContext{c}
157         c, _ = WithDeadline(o, time.Now().Add(veryLongDuration))
158         testDeadline(c, "WithDeadline+otherContext+WithDeadline", t)
159
160         c, _ = WithDeadline(Background(), time.Now().Add(-shortDuration))
161         testDeadline(c, "WithDeadline+inthepast", t)
162
163         c, _ = WithDeadline(Background(), time.Now())
164         testDeadline(c, "WithDeadline+now", t)
165 }
166
167 func TestTimeout(t *testing.T) {
168         t.Parallel()
169
170         c, _ := WithTimeout(Background(), shortDuration)
171         if got, prefix := fmt.Sprint(c), "context.Background.WithDeadline("; !strings.HasPrefix(got, prefix) {
172                 t.Errorf("c.String() = %q want prefix %q", got, prefix)
173         }
174         testDeadline(c, "WithTimeout", t)
175
176         c, _ = WithTimeout(Background(), shortDuration)
177         o := otherContext{c}
178         testDeadline(o, "WithTimeout+otherContext", t)
179
180         c, _ = WithTimeout(Background(), shortDuration)
181         o = otherContext{c}
182         c, _ = WithTimeout(o, veryLongDuration)
183         testDeadline(c, "WithTimeout+otherContext+WithTimeout", t)
184 }
185
186 func TestCanceledTimeout(t *testing.T) {
187         c, _ := WithTimeout(Background(), time.Second)
188         o := otherContext{c}
189         c, cancel := WithTimeout(o, veryLongDuration)
190         cancel() // Should propagate synchronously.
191         select {
192         case <-c.Done():
193         default:
194                 t.Errorf("<-c.Done() blocked, but shouldn't have")
195         }
196         if e := c.Err(); e != Canceled {
197                 t.Errorf("c.Err() == %v want %v", e, Canceled)
198         }
199 }
200
201 type key1 int
202 type key2 int
203
204 var k1 = key1(1)
205 var k2 = key2(1) // same int as k1, different type
206 var k3 = key2(3) // same type as k2, different int
207
208 func TestValues(t *testing.T) {
209         check := func(c Context, nm, v1, v2, v3 string) {
210                 if v, ok := c.Value(k1).(string); ok == (len(v1) == 0) || v != v1 {
211                         t.Errorf(`%s.Value(k1).(string) = %q, %t want %q, %t`, nm, v, ok, v1, len(v1) != 0)
212                 }
213                 if v, ok := c.Value(k2).(string); ok == (len(v2) == 0) || v != v2 {
214                         t.Errorf(`%s.Value(k2).(string) = %q, %t want %q, %t`, nm, v, ok, v2, len(v2) != 0)
215                 }
216                 if v, ok := c.Value(k3).(string); ok == (len(v3) == 0) || v != v3 {
217                         t.Errorf(`%s.Value(k3).(string) = %q, %t want %q, %t`, nm, v, ok, v3, len(v3) != 0)
218                 }
219         }
220
221         c0 := Background()
222         check(c0, "c0", "", "", "")
223
224         c1 := WithValue(Background(), k1, "c1k1")
225         check(c1, "c1", "c1k1", "", "")
226
227         if got, want := fmt.Sprint(c1), `context.Background.WithValue(type context_test.key1, val c1k1)`; got != want {
228                 t.Errorf("c.String() = %q want %q", got, want)
229         }
230
231         c2 := WithValue(c1, k2, "c2k2")
232         check(c2, "c2", "c1k1", "c2k2", "")
233
234         c3 := WithValue(c2, k3, "c3k3")
235         check(c3, "c2", "c1k1", "c2k2", "c3k3")
236
237         c4 := WithValue(c3, k1, nil)
238         check(c4, "c4", "", "c2k2", "c3k3")
239
240         o0 := otherContext{Background()}
241         check(o0, "o0", "", "", "")
242
243         o1 := otherContext{WithValue(Background(), k1, "c1k1")}
244         check(o1, "o1", "c1k1", "", "")
245
246         o2 := WithValue(o1, k2, "o2k2")
247         check(o2, "o2", "c1k1", "o2k2", "")
248
249         o3 := otherContext{c4}
250         check(o3, "o3", "", "c2k2", "c3k3")
251
252         o4 := WithValue(o3, k3, nil)
253         check(o4, "o4", "", "c2k2", "")
254 }
255
256 func TestAllocs(t *testing.T) {
257         bg := Background()
258         for _, test := range []struct {
259                 desc       string
260                 f          func()
261                 limit      float64
262                 gccgoLimit float64
263         }{
264                 {
265                         desc:       "Background()",
266                         f:          func() { Background() },
267                         limit:      0,
268                         gccgoLimit: 0,
269                 },
270                 {
271                         desc: fmt.Sprintf("WithValue(bg, %v, nil)", k1),
272                         f: func() {
273                                 c := WithValue(bg, k1, nil)
274                                 c.Value(k1)
275                         },
276                         limit:      3,
277                         gccgoLimit: 3,
278                 },
279                 {
280                         desc: "WithTimeout(bg, 1*time.Nanosecond)",
281                         f: func() {
282                                 c, _ := WithTimeout(bg, 1*time.Nanosecond)
283                                 <-c.Done()
284                         },
285                         limit:      12,
286                         gccgoLimit: 15,
287                 },
288                 {
289                         desc: "WithCancel(bg)",
290                         f: func() {
291                                 c, cancel := WithCancel(bg)
292                                 cancel()
293                                 <-c.Done()
294                         },
295                         limit:      5,
296                         gccgoLimit: 8,
297                 },
298                 {
299                         desc: "WithTimeout(bg, 5*time.Millisecond)",
300                         f: func() {
301                                 c, cancel := WithTimeout(bg, 5*time.Millisecond)
302                                 cancel()
303                                 <-c.Done()
304                         },
305                         limit:      8,
306                         gccgoLimit: 25,
307                 },
308         } {
309                 limit := test.limit
310                 if runtime.Compiler == "gccgo" {
311                         // gccgo does not yet do escape analysis.
312                         // TODO(iant): Remove this when gccgo does do escape analysis.
313                         limit = test.gccgoLimit
314                 }
315                 numRuns := 100
316                 if testing.Short() {
317                         numRuns = 10
318                 }
319                 if n := testing.AllocsPerRun(numRuns, test.f); n > limit {
320                         t.Errorf("%s allocs = %f want %d", test.desc, n, int(limit))
321                 }
322         }
323 }
324
325 func TestSimultaneousCancels(t *testing.T) {
326         root, cancel := WithCancel(Background())
327         m := map[Context]CancelFunc{root: cancel}
328         q := []Context{root}
329         // Create a tree of contexts.
330         for len(q) != 0 && len(m) < 100 {
331                 parent := q[0]
332                 q = q[1:]
333                 for i := 0; i < 4; i++ {
334                         ctx, cancel := WithCancel(parent)
335                         m[ctx] = cancel
336                         q = append(q, ctx)
337                 }
338         }
339         // Start all the cancels in a random order.
340         var wg sync.WaitGroup
341         wg.Add(len(m))
342         for _, cancel := range m {
343                 go func(cancel CancelFunc) {
344                         cancel()
345                         wg.Done()
346                 }(cancel)
347         }
348
349         d := quiescent(t)
350         stuck := make(chan struct{})
351         timer := time.AfterFunc(d, func() { close(stuck) })
352         defer timer.Stop()
353
354         // Wait on all the contexts in a random order.
355         for ctx := range m {
356                 select {
357                 case <-ctx.Done():
358                 case <-stuck:
359                         buf := make([]byte, 10<<10)
360                         n := runtime.Stack(buf, true)
361                         t.Fatalf("timed out after %v waiting for <-ctx.Done(); stacks:\n%s", d, buf[:n])
362                 }
363         }
364         // Wait for all the cancel functions to return.
365         done := make(chan struct{})
366         go func() {
367                 wg.Wait()
368                 close(done)
369         }()
370         select {
371         case <-done:
372         case <-stuck:
373                 buf := make([]byte, 10<<10)
374                 n := runtime.Stack(buf, true)
375                 t.Fatalf("timed out after %v waiting for cancel functions; stacks:\n%s", d, buf[:n])
376         }
377 }
378
379 func TestInterlockedCancels(t *testing.T) {
380         parent, cancelParent := WithCancel(Background())
381         child, cancelChild := WithCancel(parent)
382         go func() {
383                 <-parent.Done()
384                 cancelChild()
385         }()
386         cancelParent()
387         d := quiescent(t)
388         timer := time.NewTimer(d)
389         defer timer.Stop()
390         select {
391         case <-child.Done():
392         case <-timer.C:
393                 buf := make([]byte, 10<<10)
394                 n := runtime.Stack(buf, true)
395                 t.Fatalf("timed out after %v waiting for child.Done(); stacks:\n%s", d, buf[:n])
396         }
397 }
398
399 func TestLayersCancel(t *testing.T) {
400         testLayers(t, time.Now().UnixNano(), false)
401 }
402
403 func TestLayersTimeout(t *testing.T) {
404         testLayers(t, time.Now().UnixNano(), true)
405 }
406
407 func testLayers(t *testing.T, seed int64, testTimeout bool) {
408         t.Parallel()
409
410         r := rand.New(rand.NewSource(seed))
411         errorf := func(format string, a ...any) {
412                 t.Errorf(fmt.Sprintf("seed=%d: %s", seed, format), a...)
413         }
414         const (
415                 minLayers = 30
416         )
417         type value int
418         var (
419                 vals      []*value
420                 cancels   []CancelFunc
421                 numTimers int
422                 ctx       = Background()
423         )
424         for i := 0; i < minLayers || numTimers == 0 || len(cancels) == 0 || len(vals) == 0; i++ {
425                 switch r.Intn(3) {
426                 case 0:
427                         v := new(value)
428                         ctx = WithValue(ctx, v, v)
429                         vals = append(vals, v)
430                 case 1:
431                         var cancel CancelFunc
432                         ctx, cancel = WithCancel(ctx)
433                         cancels = append(cancels, cancel)
434                 case 2:
435                         var cancel CancelFunc
436                         d := veryLongDuration
437                         if testTimeout {
438                                 d = shortDuration
439                         }
440                         ctx, cancel = WithTimeout(ctx, d)
441                         cancels = append(cancels, cancel)
442                         numTimers++
443                 }
444         }
445         checkValues := func(when string) {
446                 for _, key := range vals {
447                         if val := ctx.Value(key).(*value); key != val {
448                                 errorf("%s: ctx.Value(%p) = %p want %p", when, key, val, key)
449                         }
450                 }
451         }
452         if !testTimeout {
453                 select {
454                 case <-ctx.Done():
455                         errorf("ctx should not be canceled yet")
456                 default:
457                 }
458         }
459         if s, prefix := fmt.Sprint(ctx), "context.Background."; !strings.HasPrefix(s, prefix) {
460                 t.Errorf("ctx.String() = %q want prefix %q", s, prefix)
461         }
462         t.Log(ctx)
463         checkValues("before cancel")
464         if testTimeout {
465                 d := quiescent(t)
466                 timer := time.NewTimer(d)
467                 defer timer.Stop()
468                 select {
469                 case <-ctx.Done():
470                 case <-timer.C:
471                         errorf("ctx should have timed out after %v", d)
472                 }
473                 checkValues("after timeout")
474         } else {
475                 cancel := cancels[r.Intn(len(cancels))]
476                 cancel()
477                 select {
478                 case <-ctx.Done():
479                 default:
480                         errorf("ctx should be canceled")
481                 }
482                 checkValues("after cancel")
483         }
484 }
485
486 func TestWithCancelCanceledParent(t *testing.T) {
487         parent, pcancel := WithCancelCause(Background())
488         cause := fmt.Errorf("Because!")
489         pcancel(cause)
490
491         c, _ := WithCancel(parent)
492         select {
493         case <-c.Done():
494         default:
495                 t.Errorf("child not done immediately upon construction")
496         }
497         if got, want := c.Err(), Canceled; got != want {
498                 t.Errorf("child not canceled; got = %v, want = %v", got, want)
499         }
500         if got, want := Cause(c), cause; got != want {
501                 t.Errorf("child has wrong cause; got = %v, want = %v", got, want)
502         }
503 }
504
505 func TestWithCancelSimultaneouslyCanceledParent(t *testing.T) {
506         // Cancel the parent goroutine concurrently with creating a child.
507         for i := 0; i < 100; i++ {
508                 parent, pcancel := WithCancelCause(Background())
509                 cause := fmt.Errorf("Because!")
510                 go pcancel(cause)
511
512                 c, _ := WithCancel(parent)
513                 <-c.Done()
514                 if got, want := c.Err(), Canceled; got != want {
515                         t.Errorf("child not canceled; got = %v, want = %v", got, want)
516                 }
517                 if got, want := Cause(c), cause; got != want {
518                         t.Errorf("child has wrong cause; got = %v, want = %v", got, want)
519                 }
520         }
521 }
522
523 func TestWithValueChecksKey(t *testing.T) {
524         panicVal := recoveredValue(func() { WithValue(Background(), []byte("foo"), "bar") })
525         if panicVal == nil {
526                 t.Error("expected panic")
527         }
528         panicVal = recoveredValue(func() { WithValue(Background(), nil, "bar") })
529         if got, want := fmt.Sprint(panicVal), "nil key"; got != want {
530                 t.Errorf("panic = %q; want %q", got, want)
531         }
532 }
533
534 func TestInvalidDerivedFail(t *testing.T) {
535         panicVal := recoveredValue(func() { WithCancel(nil) })
536         if panicVal == nil {
537                 t.Error("expected panic")
538         }
539         panicVal = recoveredValue(func() { WithDeadline(nil, time.Now().Add(shortDuration)) })
540         if panicVal == nil {
541                 t.Error("expected panic")
542         }
543         panicVal = recoveredValue(func() { WithValue(nil, "foo", "bar") })
544         if panicVal == nil {
545                 t.Error("expected panic")
546         }
547 }
548
549 func recoveredValue(fn func()) (v any) {
550         defer func() { v = recover() }()
551         fn()
552         return
553 }
554
555 func TestDeadlineExceededSupportsTimeout(t *testing.T) {
556         i, ok := DeadlineExceeded.(interface {
557                 Timeout() bool
558         })
559         if !ok {
560                 t.Fatal("DeadlineExceeded does not support Timeout interface")
561         }
562         if !i.Timeout() {
563                 t.Fatal("wrong value for timeout")
564         }
565 }
566 func TestCause(t *testing.T) {
567         var (
568                 forever       = 1e6 * time.Second
569                 parentCause   = fmt.Errorf("parentCause")
570                 childCause    = fmt.Errorf("childCause")
571                 tooSlow       = fmt.Errorf("tooSlow")
572                 finishedEarly = fmt.Errorf("finishedEarly")
573         )
574         for _, test := range []struct {
575                 name  string
576                 ctx   func() Context
577                 err   error
578                 cause error
579         }{
580                 {
581                         name:  "Background",
582                         ctx:   Background,
583                         err:   nil,
584                         cause: nil,
585                 },
586                 {
587                         name:  "TODO",
588                         ctx:   TODO,
589                         err:   nil,
590                         cause: nil,
591                 },
592                 {
593                         name: "WithCancel",
594                         ctx: func() Context {
595                                 ctx, cancel := WithCancel(Background())
596                                 cancel()
597                                 return ctx
598                         },
599                         err:   Canceled,
600                         cause: Canceled,
601                 },
602                 {
603                         name: "WithCancelCause",
604                         ctx: func() Context {
605                                 ctx, cancel := WithCancelCause(Background())
606                                 cancel(parentCause)
607                                 return ctx
608                         },
609                         err:   Canceled,
610                         cause: parentCause,
611                 },
612                 {
613                         name: "WithCancelCause nil",
614                         ctx: func() Context {
615                                 ctx, cancel := WithCancelCause(Background())
616                                 cancel(nil)
617                                 return ctx
618                         },
619                         err:   Canceled,
620                         cause: Canceled,
621                 },
622                 {
623                         name: "WithCancelCause: parent cause before child",
624                         ctx: func() Context {
625                                 ctx, cancelParent := WithCancelCause(Background())
626                                 ctx, cancelChild := WithCancelCause(ctx)
627                                 cancelParent(parentCause)
628                                 cancelChild(childCause)
629                                 return ctx
630                         },
631                         err:   Canceled,
632                         cause: parentCause,
633                 },
634                 {
635                         name: "WithCancelCause: parent cause after child",
636                         ctx: func() Context {
637                                 ctx, cancelParent := WithCancelCause(Background())
638                                 ctx, cancelChild := WithCancelCause(ctx)
639                                 cancelChild(childCause)
640                                 cancelParent(parentCause)
641                                 return ctx
642                         },
643                         err:   Canceled,
644                         cause: childCause,
645                 },
646                 {
647                         name: "WithCancelCause: parent cause before nil",
648                         ctx: func() Context {
649                                 ctx, cancelParent := WithCancelCause(Background())
650                                 ctx, cancelChild := WithCancel(ctx)
651                                 cancelParent(parentCause)
652                                 cancelChild()
653                                 return ctx
654                         },
655                         err:   Canceled,
656                         cause: parentCause,
657                 },
658                 {
659                         name: "WithCancelCause: parent cause after nil",
660                         ctx: func() Context {
661                                 ctx, cancelParent := WithCancelCause(Background())
662                                 ctx, cancelChild := WithCancel(ctx)
663                                 cancelChild()
664                                 cancelParent(parentCause)
665                                 return ctx
666                         },
667                         err:   Canceled,
668                         cause: Canceled,
669                 },
670                 {
671                         name: "WithCancelCause: child cause after nil",
672                         ctx: func() Context {
673                                 ctx, cancelParent := WithCancel(Background())
674                                 ctx, cancelChild := WithCancelCause(ctx)
675                                 cancelParent()
676                                 cancelChild(childCause)
677                                 return ctx
678                         },
679                         err:   Canceled,
680                         cause: Canceled,
681                 },
682                 {
683                         name: "WithCancelCause: child cause before nil",
684                         ctx: func() Context {
685                                 ctx, cancelParent := WithCancel(Background())
686                                 ctx, cancelChild := WithCancelCause(ctx)
687                                 cancelChild(childCause)
688                                 cancelParent()
689                                 return ctx
690                         },
691                         err:   Canceled,
692                         cause: childCause,
693                 },
694                 {
695                         name: "WithTimeout",
696                         ctx: func() Context {
697                                 ctx, cancel := WithTimeout(Background(), 0)
698                                 cancel()
699                                 return ctx
700                         },
701                         err:   DeadlineExceeded,
702                         cause: DeadlineExceeded,
703                 },
704                 {
705                         name: "WithTimeout canceled",
706                         ctx: func() Context {
707                                 ctx, cancel := WithTimeout(Background(), forever)
708                                 cancel()
709                                 return ctx
710                         },
711                         err:   Canceled,
712                         cause: Canceled,
713                 },
714                 {
715                         name: "WithTimeoutCause",
716                         ctx: func() Context {
717                                 ctx, cancel := WithTimeoutCause(Background(), 0, tooSlow)
718                                 cancel()
719                                 return ctx
720                         },
721                         err:   DeadlineExceeded,
722                         cause: tooSlow,
723                 },
724                 {
725                         name: "WithTimeoutCause canceled",
726                         ctx: func() Context {
727                                 ctx, cancel := WithTimeoutCause(Background(), forever, tooSlow)
728                                 cancel()
729                                 return ctx
730                         },
731                         err:   Canceled,
732                         cause: Canceled,
733                 },
734                 {
735                         name: "WithTimeoutCause stacked",
736                         ctx: func() Context {
737                                 ctx, cancel := WithCancelCause(Background())
738                                 ctx, _ = WithTimeoutCause(ctx, 0, tooSlow)
739                                 cancel(finishedEarly)
740                                 return ctx
741                         },
742                         err:   DeadlineExceeded,
743                         cause: tooSlow,
744                 },
745                 {
746                         name: "WithTimeoutCause stacked canceled",
747                         ctx: func() Context {
748                                 ctx, cancel := WithCancelCause(Background())
749                                 ctx, _ = WithTimeoutCause(ctx, forever, tooSlow)
750                                 cancel(finishedEarly)
751                                 return ctx
752                         },
753                         err:   Canceled,
754                         cause: finishedEarly,
755                 },
756                 {
757                         name: "WithoutCancel",
758                         ctx: func() Context {
759                                 return WithoutCancel(Background())
760                         },
761                         err:   nil,
762                         cause: nil,
763                 },
764                 {
765                         name: "WithoutCancel canceled",
766                         ctx: func() Context {
767                                 ctx, cancel := WithCancelCause(Background())
768                                 ctx = WithoutCancel(ctx)
769                                 cancel(finishedEarly)
770                                 return ctx
771                         },
772                         err:   nil,
773                         cause: nil,
774                 },
775                 {
776                         name: "WithoutCancel timeout",
777                         ctx: func() Context {
778                                 ctx, cancel := WithTimeoutCause(Background(), 0, tooSlow)
779                                 ctx = WithoutCancel(ctx)
780                                 cancel()
781                                 return ctx
782                         },
783                         err:   nil,
784                         cause: nil,
785                 },
786         } {
787                 test := test
788                 t.Run(test.name, func(t *testing.T) {
789                         t.Parallel()
790                         ctx := test.ctx()
791                         if got, want := ctx.Err(), test.err; want != got {
792                                 t.Errorf("ctx.Err() = %v want %v", got, want)
793                         }
794                         if got, want := Cause(ctx), test.cause; want != got {
795                                 t.Errorf("Cause(ctx) = %v want %v", got, want)
796                         }
797                 })
798         }
799 }
800
801 func TestCauseRace(t *testing.T) {
802         cause := errors.New("TestCauseRace")
803         ctx, cancel := WithCancelCause(Background())
804         go func() {
805                 cancel(cause)
806         }()
807         for {
808                 // Poll Cause, rather than waiting for Done, to test that
809                 // access to the underlying cause is synchronized properly.
810                 if err := Cause(ctx); err != nil {
811                         if err != cause {
812                                 t.Errorf("Cause returned %v, want %v", err, cause)
813                         }
814                         break
815                 }
816                 runtime.Gosched()
817         }
818 }
819
820 func TestWithoutCancel(t *testing.T) {
821         key, value := "key", "value"
822         ctx := WithValue(Background(), key, value)
823         ctx = WithoutCancel(ctx)
824         if d, ok := ctx.Deadline(); !d.IsZero() || ok != false {
825                 t.Errorf("ctx.Deadline() = %v, %v want zero, false", d, ok)
826         }
827         if done := ctx.Done(); done != nil {
828                 t.Errorf("ctx.Deadline() = %v want nil", done)
829         }
830         if err := ctx.Err(); err != nil {
831                 t.Errorf("ctx.Err() = %v want nil", err)
832         }
833         if v := ctx.Value(key); v != value {
834                 t.Errorf("ctx.Value(%q) = %q want %q", key, v, value)
835         }
836 }
837
838 type customDoneContext struct {
839         Context
840         donec chan struct{}
841 }
842
843 func (c *customDoneContext) Done() <-chan struct{} {
844         return c.donec
845 }
846
847 func TestCustomContextPropagation(t *testing.T) {
848         cause := errors.New("TestCustomContextPropagation")
849         donec := make(chan struct{})
850         ctx1, cancel1 := WithCancelCause(Background())
851         ctx2 := &customDoneContext{
852                 Context: ctx1,
853                 donec:   donec,
854         }
855         ctx3, cancel3 := WithCancel(ctx2)
856         defer cancel3()
857
858         cancel1(cause)
859         close(donec)
860
861         <-ctx3.Done()
862         if got, want := ctx3.Err(), Canceled; got != want {
863                 t.Errorf("child not canceled; got = %v, want = %v", got, want)
864         }
865         if got, want := Cause(ctx3), cause; got != want {
866                 t.Errorf("child has wrong cause; got = %v, want = %v", got, want)
867         }
868 }
869
870 func TestAfterFuncCalledAfterCancel(t *testing.T) {
871         ctx, cancel := WithCancel(Background())
872         donec := make(chan struct{})
873         stop := AfterFunc(ctx, func() {
874                 close(donec)
875         })
876         select {
877         case <-donec:
878                 t.Fatalf("AfterFunc called before context is done")
879         case <-time.After(shortDuration):
880         }
881         cancel()
882         select {
883         case <-donec:
884         case <-time.After(veryLongDuration):
885                 t.Fatalf("AfterFunc not called after context is canceled")
886         }
887         if stop() {
888                 t.Fatalf("stop() = true, want false")
889         }
890 }
891
892 func TestAfterFuncCalledAfterTimeout(t *testing.T) {
893         ctx, cancel := WithTimeout(Background(), shortDuration)
894         defer cancel()
895         donec := make(chan struct{})
896         AfterFunc(ctx, func() {
897                 close(donec)
898         })
899         select {
900         case <-donec:
901         case <-time.After(veryLongDuration):
902                 t.Fatalf("AfterFunc not called after context is canceled")
903         }
904 }
905
906 func TestAfterFuncCalledImmediately(t *testing.T) {
907         ctx, cancel := WithCancel(Background())
908         cancel()
909         donec := make(chan struct{})
910         AfterFunc(ctx, func() {
911                 close(donec)
912         })
913         select {
914         case <-donec:
915         case <-time.After(veryLongDuration):
916                 t.Fatalf("AfterFunc not called for already-canceled context")
917         }
918 }
919
920 func TestAfterFuncNotCalledAfterStop(t *testing.T) {
921         ctx, cancel := WithCancel(Background())
922         donec := make(chan struct{})
923         stop := AfterFunc(ctx, func() {
924                 close(donec)
925         })
926         if !stop() {
927                 t.Fatalf("stop() = false, want true")
928         }
929         cancel()
930         select {
931         case <-donec:
932                 t.Fatalf("AfterFunc called for already-canceled context")
933         case <-time.After(shortDuration):
934         }
935         if stop() {
936                 t.Fatalf("stop() = true, want false")
937         }
938 }
939
940 // This test verifies that cancelling a context does not block waiting for AfterFuncs to finish.
941 func TestAfterFuncCalledAsynchronously(t *testing.T) {
942         ctx, cancel := WithCancel(Background())
943         donec := make(chan struct{})
944         stop := AfterFunc(ctx, func() {
945                 // The channel send blocks until donec is read from.
946                 donec <- struct{}{}
947         })
948         defer stop()
949         cancel()
950         // After cancel returns, read from donec and unblock the AfterFunc.
951         select {
952         case <-donec:
953         case <-time.After(veryLongDuration):
954                 t.Fatalf("AfterFunc not called after context is canceled")
955         }
956 }