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