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