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