]> Cypherpunks.ru repositories - gostls13.git/blob - src/context/context_test.go
context: add WithoutCancel
[gostls13.git] / src / context / context_test.go
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
5 package context
6
7 import (
8         "errors"
9         "fmt"
10         "math/rand"
11         "runtime"
12         "strings"
13         "sync"
14         "time"
15 )
16
17 type testingT interface {
18         Deadline() (time.Time, bool)
19         Error(args ...any)
20         Errorf(format string, args ...any)
21         Fail()
22         FailNow()
23         Failed() bool
24         Fatal(args ...any)
25         Fatalf(format string, args ...any)
26         Helper()
27         Log(args ...any)
28         Logf(format string, args ...any)
29         Name() string
30         Parallel()
31         Skip(args ...any)
32         SkipNow()
33         Skipf(format string, args ...any)
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.
40 type otherContext struct {
41         Context
42 }
43
44 const (
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.
51 func 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
61 func 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
76 func 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
91 func 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
130 func contains(m map[canceler]struct{}, key canceler) bool {
131         _, ret := m[key]
132         return ret
133 }
134
135 func 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
212 func 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
272 func 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
287 func 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
312 func 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
331 func 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
346 type key1 int
347 type key2 int
348
349 var k1 = key1(1)
350 var k2 = key2(1) // same int as k1, different type
351 var k3 = key2(3) // same type as k2, different int
352
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)
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
401 func 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
470 func 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
524 func 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
544 func XTestLayersCancel(t testingT) {
545         testLayers(t, time.Now().UnixNano(), false)
546 }
547
548 func XTestLayersTimeout(t testingT) {
549         testLayers(t, time.Now().UnixNano(), true)
550 }
551
552 func testLayers(t testingT, seed int64, testTimeout bool) {
553         t.Parallel()
554
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...)
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
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)
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
653 func XTestWithCancelCanceledParent(t testingT) {
654         parent, pcancel := WithCancelCause(Background())
655         cause := fmt.Errorf("Because!")
656         pcancel(cause)
657
658         c, _ := WithCancel(parent)
659         select {
660         case <-c.Done():
661         default:
662                 t.Errorf("child not done immediately upon construction")
663         }
664         if got, want := c.Err(), Canceled; got != want {
665                 t.Errorf("child not canceled; got = %v, want = %v", got, want)
666         }
667         if got, want := Cause(c), cause; got != want {
668                 t.Errorf("child has wrong cause; got = %v, want = %v", got, want)
669         }
670 }
671
672 func XTestWithValueChecksKey(t testingT) {
673         panicVal := recoveredValue(func() { WithValue(Background(), []byte("foo"), "bar") })
674         if panicVal == nil {
675                 t.Error("expected panic")
676         }
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)
680         }
681 }
682
683 func XTestInvalidDerivedFail(t testingT) {
684         panicVal := recoveredValue(func() { WithCancel(nil) })
685         if panicVal == nil {
686                 t.Error("expected panic")
687         }
688         panicVal = recoveredValue(func() { WithDeadline(nil, time.Now().Add(shortDuration)) })
689         if panicVal == nil {
690                 t.Error("expected panic")
691         }
692         panicVal = recoveredValue(func() { WithValue(nil, "foo", "bar") })
693         if panicVal == nil {
694                 t.Error("expected panic")
695         }
696 }
697
698 func recoveredValue(fn func()) (v any) {
699         defer func() { v = recover() }()
700         fn()
701         return
702 }
703
704 func XTestDeadlineExceededSupportsTimeout(t testingT) {
705         i, ok := DeadlineExceeded.(interface {
706                 Timeout() bool
707         })
708         if !ok {
709                 t.Fatal("DeadlineExceeded does not support Timeout interface")
710         }
711         if !i.Timeout() {
712                 t.Fatal("wrong value for timeout")
713         }
714 }
715
716 type myCtx struct {
717         Context
718 }
719
720 type myDoneCtx struct {
721         Context
722 }
723
724 func (d *myDoneCtx) Done() <-chan struct{} {
725         c := make(chan struct{})
726         return c
727 }
728
729 func XTestCustomContextGoroutines(t testingT) {
730         g := goroutines.Load()
731         checkNoGoroutine := func() {
732                 t.Helper()
733                 now := goroutines.Load()
734                 if now != g {
735                         t.Fatalf("%d goroutines created", now-g)
736                 }
737         }
738         checkCreatedGoroutine := func() {
739                 t.Helper()
740                 now := goroutines.Load()
741                 if now != g+1 {
742                         t.Fatalf("%d goroutines created, want 1", now-g)
743                 }
744                 g = now
745         }
746
747         _, cancel0 := WithCancel(&myDoneCtx{Background()})
748         cancel0()
749         checkCreatedGoroutine()
750
751         _, cancel0 = WithTimeout(&myDoneCtx{Background()}, veryLongDuration)
752         cancel0()
753         checkCreatedGoroutine()
754
755         checkNoGoroutine()
756         defer checkNoGoroutine()
757
758         ctx1, cancel1 := WithCancel(Background())
759         defer cancel1()
760         checkNoGoroutine()
761
762         ctx2 := &myCtx{ctx1}
763         ctx3, cancel3 := WithCancel(ctx2)
764         defer cancel3()
765         checkNoGoroutine()
766
767         _, cancel3b := WithCancel(&myDoneCtx{ctx2})
768         defer cancel3b()
769         checkCreatedGoroutine() // ctx1 is not providing Done, must not be used
770
771         ctx4, cancel4 := WithTimeout(ctx3, veryLongDuration)
772         defer cancel4()
773         checkNoGoroutine()
774
775         ctx5, cancel5 := WithCancel(ctx4)
776         defer cancel5()
777         checkNoGoroutine()
778
779         cancel5()
780         checkNoGoroutine()
781
782         _, cancel6 := WithTimeout(ctx5, veryLongDuration)
783         defer cancel6()
784         checkNoGoroutine()
785
786         // Check applied to canceled context.
787         cancel6()
788         cancel1()
789         _, cancel7 := WithCancel(ctx5)
790         defer cancel7()
791         checkNoGoroutine()
792 }
793
794 func XTestCause(t testingT) {
795         var (
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")
801         )
802         for _, test := range []struct {
803                 name  string
804                 ctx   Context
805                 err   error
806                 cause error
807         }{
808                 {
809                         name:  "Background",
810                         ctx:   Background(),
811                         err:   nil,
812                         cause: nil,
813                 },
814                 {
815                         name:  "TODO",
816                         ctx:   TODO(),
817                         err:   nil,
818                         cause: nil,
819                 },
820                 {
821                         name: "WithCancel",
822                         ctx: func() Context {
823                                 ctx, cancel := WithCancel(Background())
824                                 cancel()
825                                 return ctx
826                         }(),
827                         err:   Canceled,
828                         cause: Canceled,
829                 },
830                 {
831                         name: "WithCancelCause",
832                         ctx: func() Context {
833                                 ctx, cancel := WithCancelCause(Background())
834                                 cancel(parentCause)
835                                 return ctx
836                         }(),
837                         err:   Canceled,
838                         cause: parentCause,
839                 },
840                 {
841                         name: "WithCancelCause nil",
842                         ctx: func() Context {
843                                 ctx, cancel := WithCancelCause(Background())
844                                 cancel(nil)
845                                 return ctx
846                         }(),
847                         err:   Canceled,
848                         cause: Canceled,
849                 },
850                 {
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)
857                                 return ctx
858                         }(),
859                         err:   Canceled,
860                         cause: parentCause,
861                 },
862                 {
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)
869                                 return ctx
870                         }(),
871                         err:   Canceled,
872                         cause: childCause,
873                 },
874                 {
875                         name: "WithCancelCause: parent cause before nil",
876                         ctx: func() Context {
877                                 ctx, cancelParent := WithCancelCause(Background())
878                                 ctx, cancelChild := WithCancel(ctx)
879                                 cancelParent(parentCause)
880                                 cancelChild()
881                                 return ctx
882                         }(),
883                         err:   Canceled,
884                         cause: parentCause,
885                 },
886                 {
887                         name: "WithCancelCause: parent cause after nil",
888                         ctx: func() Context {
889                                 ctx, cancelParent := WithCancelCause(Background())
890                                 ctx, cancelChild := WithCancel(ctx)
891                                 cancelChild()
892                                 cancelParent(parentCause)
893                                 return ctx
894                         }(),
895                         err:   Canceled,
896                         cause: Canceled,
897                 },
898                 {
899                         name: "WithCancelCause: child cause after nil",
900                         ctx: func() Context {
901                                 ctx, cancelParent := WithCancel(Background())
902                                 ctx, cancelChild := WithCancelCause(ctx)
903                                 cancelParent()
904                                 cancelChild(childCause)
905                                 return ctx
906                         }(),
907                         err:   Canceled,
908                         cause: Canceled,
909                 },
910                 {
911                         name: "WithCancelCause: child cause before nil",
912                         ctx: func() Context {
913                                 ctx, cancelParent := WithCancel(Background())
914                                 ctx, cancelChild := WithCancelCause(ctx)
915                                 cancelChild(childCause)
916                                 cancelParent()
917                                 return ctx
918                         }(),
919                         err:   Canceled,
920                         cause: childCause,
921                 },
922                 {
923                         name: "WithTimeout",
924                         ctx: func() Context {
925                                 ctx, cancel := WithTimeout(Background(), 0)
926                                 cancel()
927                                 return ctx
928                         }(),
929                         err:   DeadlineExceeded,
930                         cause: DeadlineExceeded,
931                 },
932                 {
933                         name: "WithTimeout canceled",
934                         ctx: func() Context {
935                                 ctx, cancel := WithTimeout(Background(), forever)
936                                 cancel()
937                                 return ctx
938                         }(),
939                         err:   Canceled,
940                         cause: Canceled,
941                 },
942                 {
943                         name: "WithTimeoutCause",
944                         ctx: func() Context {
945                                 ctx, cancel := WithTimeoutCause(Background(), 0, tooSlow)
946                                 cancel()
947                                 return ctx
948                         }(),
949                         err:   DeadlineExceeded,
950                         cause: tooSlow,
951                 },
952                 {
953                         name: "WithTimeoutCause canceled",
954                         ctx: func() Context {
955                                 ctx, cancel := WithTimeoutCause(Background(), forever, tooSlow)
956                                 cancel()
957                                 return ctx
958                         }(),
959                         err:   Canceled,
960                         cause: Canceled,
961                 },
962                 {
963                         name: "WithTimeoutCause stacked",
964                         ctx: func() Context {
965                                 ctx, cancel := WithCancelCause(Background())
966                                 ctx, _ = WithTimeoutCause(ctx, 0, tooSlow)
967                                 cancel(finishedEarly)
968                                 return ctx
969                         }(),
970                         err:   DeadlineExceeded,
971                         cause: tooSlow,
972                 },
973                 {
974                         name: "WithTimeoutCause stacked canceled",
975                         ctx: func() Context {
976                                 ctx, cancel := WithCancelCause(Background())
977                                 ctx, _ = WithTimeoutCause(ctx, forever, tooSlow)
978                                 cancel(finishedEarly)
979                                 return ctx
980                         }(),
981                         err:   Canceled,
982                         cause: finishedEarly,
983                 },
984                 {
985                         name: "WithoutCancel",
986                         ctx: func() Context {
987                                 return WithoutCancel(Background())
988                         }(),
989                         err:   nil,
990                         cause: nil,
991                 },
992                 {
993                         name: "WithoutCancel canceled",
994                         ctx: func() Context {
995                                 ctx, cancel := WithCancelCause(Background())
996                                 ctx = WithoutCancel(ctx)
997                                 cancel(finishedEarly)
998                                 return ctx
999                         }(),
1000                         err:   nil,
1001                         cause: nil,
1002                 },
1003                 {
1004                         name: "WithoutCancel timeout",
1005                         ctx: func() Context {
1006                                 ctx, cancel := WithTimeoutCause(Background(), 0, tooSlow)
1007                                 ctx = WithoutCancel(ctx)
1008                                 cancel()
1009                                 return ctx
1010                         }(),
1011                         err:   nil,
1012                         cause: nil,
1013                 },
1014         } {
1015                 if got, want := test.ctx.Err(), test.err; want != got {
1016                         t.Errorf("%s: ctx.Err() = %v want %v", test.name, got, want)
1017                 }
1018                 if got, want := Cause(test.ctx), test.cause; want != got {
1019                         t.Errorf("%s: Cause(ctx) = %v want %v", test.name, got, want)
1020                 }
1021         }
1022 }
1023
1024 func XTestCauseRace(t testingT) {
1025         cause := errors.New("TestCauseRace")
1026         ctx, cancel := WithCancelCause(Background())
1027         go func() {
1028                 cancel(cause)
1029         }()
1030         for {
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 {
1034                         if err != cause {
1035                                 t.Errorf("Cause returned %v, want %v", err, cause)
1036                         }
1037                         break
1038                 }
1039                 runtime.Gosched()
1040         }
1041 }
1042
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)
1049         }
1050         if done := ctx.Done(); done != nil {
1051                 t.Errorf("ctx.Deadline() = %v want nil", done)
1052         }
1053         if err := ctx.Err(); err != nil {
1054                 t.Errorf("ctx.Err() = %v want nil", err)
1055         }
1056         if v := ctx.Value(key); v != value {
1057                 t.Errorf("ctx.Value(%q) = %q want %q", key, v, value)
1058         }
1059 }