Black Lives Matter. Support the Equal Justice Initiative.

Source file src/context/context_test.go

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

View as plain text