github.com/mattn/go@v0.0.0-20171011075504-07f7db3ea99f/src/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  	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  }