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