github.com/twelsh-aw/go/src@v0.0.0-20230516233729-a56fe86a7c81/context/x_test.go (about)

     1  // Copyright 2016 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_test
     6  
     7  import (
     8  	. "context"
     9  	"errors"
    10  	"fmt"
    11  	"math/rand"
    12  	"runtime"
    13  	"strings"
    14  	"sync"
    15  	"testing"
    16  	"time"
    17  )
    18  
    19  // Each XTestFoo in context_test.go must be called from a TestFoo here to run.
    20  func TestParentFinishesChild(t *testing.T) {
    21  	XTestParentFinishesChild(t) // uses unexported context types
    22  }
    23  func TestChildFinishesFirst(t *testing.T) {
    24  	XTestChildFinishesFirst(t) // uses unexported context types
    25  }
    26  func TestCancelRemoves(t *testing.T) {
    27  	XTestCancelRemoves(t) // uses unexported context types
    28  }
    29  func TestCustomContextGoroutines(t *testing.T) {
    30  	XTestCustomContextGoroutines(t) // reads the context.goroutines counter
    31  }
    32  
    33  // The following are regular tests in package context_test.
    34  
    35  // otherContext is a Context that's not one of the types defined in context.go.
    36  // This lets us test code paths that differ based on the underlying type of the
    37  // Context.
    38  type otherContext struct {
    39  	Context
    40  }
    41  
    42  const (
    43  	shortDuration    = 1 * time.Millisecond // a reasonable duration to block in a test
    44  	veryLongDuration = 1000 * time.Hour     // an arbitrary upper bound on the test's running time
    45  )
    46  
    47  // quiescent returns an arbitrary duration by which the program should have
    48  // completed any remaining work and reached a steady (idle) state.
    49  func quiescent(t *testing.T) time.Duration {
    50  	deadline, ok := t.Deadline()
    51  	if !ok {
    52  		return 5 * time.Second
    53  	}
    54  
    55  	const arbitraryCleanupMargin = 1 * time.Second
    56  	return time.Until(deadline) - arbitraryCleanupMargin
    57  }
    58  func TestBackground(t *testing.T) {
    59  	c := Background()
    60  	if c == nil {
    61  		t.Fatalf("Background returned nil")
    62  	}
    63  	select {
    64  	case x := <-c.Done():
    65  		t.Errorf("<-c.Done() == %v want nothing (it should block)", x)
    66  	default:
    67  	}
    68  	if got, want := fmt.Sprint(c), "context.Background"; got != want {
    69  		t.Errorf("Background().String() = %q want %q", got, want)
    70  	}
    71  }
    72  
    73  func TestTODO(t *testing.T) {
    74  	c := TODO()
    75  	if c == nil {
    76  		t.Fatalf("TODO returned nil")
    77  	}
    78  	select {
    79  	case x := <-c.Done():
    80  		t.Errorf("<-c.Done() == %v want nothing (it should block)", x)
    81  	default:
    82  	}
    83  	if got, want := fmt.Sprint(c), "context.TODO"; got != want {
    84  		t.Errorf("TODO().String() = %q want %q", got, want)
    85  	}
    86  }
    87  
    88  func TestWithCancel(t *testing.T) {
    89  	c1, cancel := WithCancel(Background())
    90  
    91  	if got, want := fmt.Sprint(c1), "context.Background.WithCancel"; got != want {
    92  		t.Errorf("c1.String() = %q want %q", got, want)
    93  	}
    94  
    95  	o := otherContext{c1}
    96  	c2, _ := WithCancel(o)
    97  	contexts := []Context{c1, o, c2}
    98  
    99  	for i, c := range contexts {
   100  		if d := c.Done(); d == nil {
   101  			t.Errorf("c[%d].Done() == %v want non-nil", i, d)
   102  		}
   103  		if e := c.Err(); e != nil {
   104  			t.Errorf("c[%d].Err() == %v want nil", i, e)
   105  		}
   106  
   107  		select {
   108  		case x := <-c.Done():
   109  			t.Errorf("<-c.Done() == %v want nothing (it should block)", x)
   110  		default:
   111  		}
   112  	}
   113  
   114  	cancel() // Should propagate synchronously.
   115  	for i, c := range contexts {
   116  		select {
   117  		case <-c.Done():
   118  		default:
   119  			t.Errorf("<-c[%d].Done() blocked, but shouldn't have", i)
   120  		}
   121  		if e := c.Err(); e != Canceled {
   122  			t.Errorf("c[%d].Err() == %v want %v", i, e, Canceled)
   123  		}
   124  	}
   125  }
   126  
   127  func testDeadline(c Context, name string, t *testing.T) {
   128  	t.Helper()
   129  	d := quiescent(t)
   130  	timer := time.NewTimer(d)
   131  	defer timer.Stop()
   132  	select {
   133  	case <-timer.C:
   134  		t.Fatalf("%s: context not timed out after %v", name, d)
   135  	case <-c.Done():
   136  	}
   137  	if e := c.Err(); e != DeadlineExceeded {
   138  		t.Errorf("%s: c.Err() == %v; want %v", name, e, DeadlineExceeded)
   139  	}
   140  }
   141  
   142  func TestDeadline(t *testing.T) {
   143  	t.Parallel()
   144  
   145  	c, _ := WithDeadline(Background(), time.Now().Add(shortDuration))
   146  	if got, prefix := fmt.Sprint(c), "context.Background.WithDeadline("; !strings.HasPrefix(got, prefix) {
   147  		t.Errorf("c.String() = %q want prefix %q", got, prefix)
   148  	}
   149  	testDeadline(c, "WithDeadline", t)
   150  
   151  	c, _ = WithDeadline(Background(), time.Now().Add(shortDuration))
   152  	o := otherContext{c}
   153  	testDeadline(o, "WithDeadline+otherContext", t)
   154  
   155  	c, _ = WithDeadline(Background(), time.Now().Add(shortDuration))
   156  	o = otherContext{c}
   157  	c, _ = WithDeadline(o, time.Now().Add(veryLongDuration))
   158  	testDeadline(c, "WithDeadline+otherContext+WithDeadline", t)
   159  
   160  	c, _ = WithDeadline(Background(), time.Now().Add(-shortDuration))
   161  	testDeadline(c, "WithDeadline+inthepast", t)
   162  
   163  	c, _ = WithDeadline(Background(), time.Now())
   164  	testDeadline(c, "WithDeadline+now", t)
   165  }
   166  
   167  func TestTimeout(t *testing.T) {
   168  	t.Parallel()
   169  
   170  	c, _ := WithTimeout(Background(), shortDuration)
   171  	if got, prefix := fmt.Sprint(c), "context.Background.WithDeadline("; !strings.HasPrefix(got, prefix) {
   172  		t.Errorf("c.String() = %q want prefix %q", got, prefix)
   173  	}
   174  	testDeadline(c, "WithTimeout", t)
   175  
   176  	c, _ = WithTimeout(Background(), shortDuration)
   177  	o := otherContext{c}
   178  	testDeadline(o, "WithTimeout+otherContext", t)
   179  
   180  	c, _ = WithTimeout(Background(), shortDuration)
   181  	o = otherContext{c}
   182  	c, _ = WithTimeout(o, veryLongDuration)
   183  	testDeadline(c, "WithTimeout+otherContext+WithTimeout", t)
   184  }
   185  
   186  func TestCanceledTimeout(t *testing.T) {
   187  	c, _ := WithTimeout(Background(), time.Second)
   188  	o := otherContext{c}
   189  	c, cancel := WithTimeout(o, veryLongDuration)
   190  	cancel() // Should propagate synchronously.
   191  	select {
   192  	case <-c.Done():
   193  	default:
   194  		t.Errorf("<-c.Done() blocked, but shouldn't have")
   195  	}
   196  	if e := c.Err(); e != Canceled {
   197  		t.Errorf("c.Err() == %v want %v", e, Canceled)
   198  	}
   199  }
   200  
   201  type key1 int
   202  type key2 int
   203  
   204  var k1 = key1(1)
   205  var k2 = key2(1) // same int as k1, different type
   206  var k3 = key2(3) // same type as k2, different int
   207  
   208  func TestValues(t *testing.T) {
   209  	check := func(c Context, nm, v1, v2, v3 string) {
   210  		if v, ok := c.Value(k1).(string); ok == (len(v1) == 0) || v != v1 {
   211  			t.Errorf(`%s.Value(k1).(string) = %q, %t want %q, %t`, nm, v, ok, v1, len(v1) != 0)
   212  		}
   213  		if v, ok := c.Value(k2).(string); ok == (len(v2) == 0) || v != v2 {
   214  			t.Errorf(`%s.Value(k2).(string) = %q, %t want %q, %t`, nm, v, ok, v2, len(v2) != 0)
   215  		}
   216  		if v, ok := c.Value(k3).(string); ok == (len(v3) == 0) || v != v3 {
   217  			t.Errorf(`%s.Value(k3).(string) = %q, %t want %q, %t`, nm, v, ok, v3, len(v3) != 0)
   218  		}
   219  	}
   220  
   221  	c0 := Background()
   222  	check(c0, "c0", "", "", "")
   223  
   224  	c1 := WithValue(Background(), k1, "c1k1")
   225  	check(c1, "c1", "c1k1", "", "")
   226  
   227  	if got, want := fmt.Sprint(c1), `context.Background.WithValue(type context_test.key1, val c1k1)`; got != want {
   228  		t.Errorf("c.String() = %q want %q", got, want)
   229  	}
   230  
   231  	c2 := WithValue(c1, k2, "c2k2")
   232  	check(c2, "c2", "c1k1", "c2k2", "")
   233  
   234  	c3 := WithValue(c2, k3, "c3k3")
   235  	check(c3, "c2", "c1k1", "c2k2", "c3k3")
   236  
   237  	c4 := WithValue(c3, k1, nil)
   238  	check(c4, "c4", "", "c2k2", "c3k3")
   239  
   240  	o0 := otherContext{Background()}
   241  	check(o0, "o0", "", "", "")
   242  
   243  	o1 := otherContext{WithValue(Background(), k1, "c1k1")}
   244  	check(o1, "o1", "c1k1", "", "")
   245  
   246  	o2 := WithValue(o1, k2, "o2k2")
   247  	check(o2, "o2", "c1k1", "o2k2", "")
   248  
   249  	o3 := otherContext{c4}
   250  	check(o3, "o3", "", "c2k2", "c3k3")
   251  
   252  	o4 := WithValue(o3, k3, nil)
   253  	check(o4, "o4", "", "c2k2", "")
   254  }
   255  
   256  func TestAllocs(t *testing.T) {
   257  	bg := Background()
   258  	for _, test := range []struct {
   259  		desc       string
   260  		f          func()
   261  		limit      float64
   262  		gccgoLimit float64
   263  	}{
   264  		{
   265  			desc:       "Background()",
   266  			f:          func() { Background() },
   267  			limit:      0,
   268  			gccgoLimit: 0,
   269  		},
   270  		{
   271  			desc: fmt.Sprintf("WithValue(bg, %v, nil)", k1),
   272  			f: func() {
   273  				c := WithValue(bg, k1, nil)
   274  				c.Value(k1)
   275  			},
   276  			limit:      3,
   277  			gccgoLimit: 3,
   278  		},
   279  		{
   280  			desc: "WithTimeout(bg, 1*time.Nanosecond)",
   281  			f: func() {
   282  				c, _ := WithTimeout(bg, 1*time.Nanosecond)
   283  				<-c.Done()
   284  			},
   285  			limit:      12,
   286  			gccgoLimit: 15,
   287  		},
   288  		{
   289  			desc: "WithCancel(bg)",
   290  			f: func() {
   291  				c, cancel := WithCancel(bg)
   292  				cancel()
   293  				<-c.Done()
   294  			},
   295  			limit:      5,
   296  			gccgoLimit: 8,
   297  		},
   298  		{
   299  			desc: "WithTimeout(bg, 5*time.Millisecond)",
   300  			f: func() {
   301  				c, cancel := WithTimeout(bg, 5*time.Millisecond)
   302  				cancel()
   303  				<-c.Done()
   304  			},
   305  			limit:      8,
   306  			gccgoLimit: 25,
   307  		},
   308  	} {
   309  		limit := test.limit
   310  		if runtime.Compiler == "gccgo" {
   311  			// gccgo does not yet do escape analysis.
   312  			// TODO(iant): Remove this when gccgo does do escape analysis.
   313  			limit = test.gccgoLimit
   314  		}
   315  		numRuns := 100
   316  		if testing.Short() {
   317  			numRuns = 10
   318  		}
   319  		if n := testing.AllocsPerRun(numRuns, test.f); n > limit {
   320  			t.Errorf("%s allocs = %f want %d", test.desc, n, int(limit))
   321  		}
   322  	}
   323  }
   324  
   325  func TestSimultaneousCancels(t *testing.T) {
   326  	root, cancel := WithCancel(Background())
   327  	m := map[Context]CancelFunc{root: cancel}
   328  	q := []Context{root}
   329  	// Create a tree of contexts.
   330  	for len(q) != 0 && len(m) < 100 {
   331  		parent := q[0]
   332  		q = q[1:]
   333  		for i := 0; i < 4; i++ {
   334  			ctx, cancel := WithCancel(parent)
   335  			m[ctx] = cancel
   336  			q = append(q, ctx)
   337  		}
   338  	}
   339  	// Start all the cancels in a random order.
   340  	var wg sync.WaitGroup
   341  	wg.Add(len(m))
   342  	for _, cancel := range m {
   343  		go func(cancel CancelFunc) {
   344  			cancel()
   345  			wg.Done()
   346  		}(cancel)
   347  	}
   348  
   349  	d := quiescent(t)
   350  	stuck := make(chan struct{})
   351  	timer := time.AfterFunc(d, func() { close(stuck) })
   352  	defer timer.Stop()
   353  
   354  	// Wait on all the contexts in a random order.
   355  	for ctx := range m {
   356  		select {
   357  		case <-ctx.Done():
   358  		case <-stuck:
   359  			buf := make([]byte, 10<<10)
   360  			n := runtime.Stack(buf, true)
   361  			t.Fatalf("timed out after %v waiting for <-ctx.Done(); stacks:\n%s", d, buf[:n])
   362  		}
   363  	}
   364  	// Wait for all the cancel functions to return.
   365  	done := make(chan struct{})
   366  	go func() {
   367  		wg.Wait()
   368  		close(done)
   369  	}()
   370  	select {
   371  	case <-done:
   372  	case <-stuck:
   373  		buf := make([]byte, 10<<10)
   374  		n := runtime.Stack(buf, true)
   375  		t.Fatalf("timed out after %v waiting for cancel functions; stacks:\n%s", d, buf[:n])
   376  	}
   377  }
   378  
   379  func TestInterlockedCancels(t *testing.T) {
   380  	parent, cancelParent := WithCancel(Background())
   381  	child, cancelChild := WithCancel(parent)
   382  	go func() {
   383  		<-parent.Done()
   384  		cancelChild()
   385  	}()
   386  	cancelParent()
   387  	d := quiescent(t)
   388  	timer := time.NewTimer(d)
   389  	defer timer.Stop()
   390  	select {
   391  	case <-child.Done():
   392  	case <-timer.C:
   393  		buf := make([]byte, 10<<10)
   394  		n := runtime.Stack(buf, true)
   395  		t.Fatalf("timed out after %v waiting for child.Done(); stacks:\n%s", d, buf[:n])
   396  	}
   397  }
   398  
   399  func TestLayersCancel(t *testing.T) {
   400  	testLayers(t, time.Now().UnixNano(), false)
   401  }
   402  
   403  func TestLayersTimeout(t *testing.T) {
   404  	testLayers(t, time.Now().UnixNano(), true)
   405  }
   406  
   407  func testLayers(t *testing.T, seed int64, testTimeout bool) {
   408  	t.Parallel()
   409  
   410  	r := rand.New(rand.NewSource(seed))
   411  	errorf := func(format string, a ...any) {
   412  		t.Errorf(fmt.Sprintf("seed=%d: %s", seed, format), a...)
   413  	}
   414  	const (
   415  		minLayers = 30
   416  	)
   417  	type value int
   418  	var (
   419  		vals      []*value
   420  		cancels   []CancelFunc
   421  		numTimers int
   422  		ctx       = Background()
   423  	)
   424  	for i := 0; i < minLayers || numTimers == 0 || len(cancels) == 0 || len(vals) == 0; i++ {
   425  		switch r.Intn(3) {
   426  		case 0:
   427  			v := new(value)
   428  			ctx = WithValue(ctx, v, v)
   429  			vals = append(vals, v)
   430  		case 1:
   431  			var cancel CancelFunc
   432  			ctx, cancel = WithCancel(ctx)
   433  			cancels = append(cancels, cancel)
   434  		case 2:
   435  			var cancel CancelFunc
   436  			d := veryLongDuration
   437  			if testTimeout {
   438  				d = shortDuration
   439  			}
   440  			ctx, cancel = WithTimeout(ctx, d)
   441  			cancels = append(cancels, cancel)
   442  			numTimers++
   443  		}
   444  	}
   445  	checkValues := func(when string) {
   446  		for _, key := range vals {
   447  			if val := ctx.Value(key).(*value); key != val {
   448  				errorf("%s: ctx.Value(%p) = %p want %p", when, key, val, key)
   449  			}
   450  		}
   451  	}
   452  	if !testTimeout {
   453  		select {
   454  		case <-ctx.Done():
   455  			errorf("ctx should not be canceled yet")
   456  		default:
   457  		}
   458  	}
   459  	if s, prefix := fmt.Sprint(ctx), "context.Background."; !strings.HasPrefix(s, prefix) {
   460  		t.Errorf("ctx.String() = %q want prefix %q", s, prefix)
   461  	}
   462  	t.Log(ctx)
   463  	checkValues("before cancel")
   464  	if testTimeout {
   465  		d := quiescent(t)
   466  		timer := time.NewTimer(d)
   467  		defer timer.Stop()
   468  		select {
   469  		case <-ctx.Done():
   470  		case <-timer.C:
   471  			errorf("ctx should have timed out after %v", d)
   472  		}
   473  		checkValues("after timeout")
   474  	} else {
   475  		cancel := cancels[r.Intn(len(cancels))]
   476  		cancel()
   477  		select {
   478  		case <-ctx.Done():
   479  		default:
   480  			errorf("ctx should be canceled")
   481  		}
   482  		checkValues("after cancel")
   483  	}
   484  }
   485  
   486  func TestWithCancelCanceledParent(t *testing.T) {
   487  	parent, pcancel := WithCancelCause(Background())
   488  	cause := fmt.Errorf("Because!")
   489  	pcancel(cause)
   490  
   491  	c, _ := WithCancel(parent)
   492  	select {
   493  	case <-c.Done():
   494  	default:
   495  		t.Errorf("child not done immediately upon construction")
   496  	}
   497  	if got, want := c.Err(), Canceled; got != want {
   498  		t.Errorf("child not canceled; got = %v, want = %v", got, want)
   499  	}
   500  	if got, want := Cause(c), cause; got != want {
   501  		t.Errorf("child has wrong cause; got = %v, want = %v", got, want)
   502  	}
   503  }
   504  
   505  func TestWithCancelSimultaneouslyCanceledParent(t *testing.T) {
   506  	// Cancel the parent goroutine concurrently with creating a child.
   507  	for i := 0; i < 100; i++ {
   508  		parent, pcancel := WithCancelCause(Background())
   509  		cause := fmt.Errorf("Because!")
   510  		go pcancel(cause)
   511  
   512  		c, _ := WithCancel(parent)
   513  		<-c.Done()
   514  		if got, want := c.Err(), Canceled; got != want {
   515  			t.Errorf("child not canceled; got = %v, want = %v", got, want)
   516  		}
   517  		if got, want := Cause(c), cause; got != want {
   518  			t.Errorf("child has wrong cause; got = %v, want = %v", got, want)
   519  		}
   520  	}
   521  }
   522  
   523  func TestWithValueChecksKey(t *testing.T) {
   524  	panicVal := recoveredValue(func() { _ = WithValue(Background(), []byte("foo"), "bar") })
   525  	if panicVal == nil {
   526  		t.Error("expected panic")
   527  	}
   528  	panicVal = recoveredValue(func() { _ = WithValue(Background(), nil, "bar") })
   529  	if got, want := fmt.Sprint(panicVal), "nil key"; got != want {
   530  		t.Errorf("panic = %q; want %q", got, want)
   531  	}
   532  }
   533  
   534  func TestInvalidDerivedFail(t *testing.T) {
   535  	panicVal := recoveredValue(func() { _, _ = WithCancel(nil) })
   536  	if panicVal == nil {
   537  		t.Error("expected panic")
   538  	}
   539  	panicVal = recoveredValue(func() { _, _ = WithDeadline(nil, time.Now().Add(shortDuration)) })
   540  	if panicVal == nil {
   541  		t.Error("expected panic")
   542  	}
   543  	panicVal = recoveredValue(func() { _ = WithValue(nil, "foo", "bar") })
   544  	if panicVal == nil {
   545  		t.Error("expected panic")
   546  	}
   547  }
   548  
   549  func recoveredValue(fn func()) (v any) {
   550  	defer func() { v = recover() }()
   551  	fn()
   552  	return
   553  }
   554  
   555  func TestDeadlineExceededSupportsTimeout(t *testing.T) {
   556  	i, ok := DeadlineExceeded.(interface {
   557  		Timeout() bool
   558  	})
   559  	if !ok {
   560  		t.Fatal("DeadlineExceeded does not support Timeout interface")
   561  	}
   562  	if !i.Timeout() {
   563  		t.Fatal("wrong value for timeout")
   564  	}
   565  }
   566  func TestCause(t *testing.T) {
   567  	var (
   568  		forever       = 1e6 * time.Second
   569  		parentCause   = fmt.Errorf("parentCause")
   570  		childCause    = fmt.Errorf("childCause")
   571  		tooSlow       = fmt.Errorf("tooSlow")
   572  		finishedEarly = fmt.Errorf("finishedEarly")
   573  	)
   574  	for _, test := range []struct {
   575  		name  string
   576  		ctx   func() Context
   577  		err   error
   578  		cause error
   579  	}{
   580  		{
   581  			name:  "Background",
   582  			ctx:   Background,
   583  			err:   nil,
   584  			cause: nil,
   585  		},
   586  		{
   587  			name:  "TODO",
   588  			ctx:   TODO,
   589  			err:   nil,
   590  			cause: nil,
   591  		},
   592  		{
   593  			name: "WithCancel",
   594  			ctx: func() Context {
   595  				ctx, cancel := WithCancel(Background())
   596  				cancel()
   597  				return ctx
   598  			},
   599  			err:   Canceled,
   600  			cause: Canceled,
   601  		},
   602  		{
   603  			name: "WithCancelCause",
   604  			ctx: func() Context {
   605  				ctx, cancel := WithCancelCause(Background())
   606  				cancel(parentCause)
   607  				return ctx
   608  			},
   609  			err:   Canceled,
   610  			cause: parentCause,
   611  		},
   612  		{
   613  			name: "WithCancelCause nil",
   614  			ctx: func() Context {
   615  				ctx, cancel := WithCancelCause(Background())
   616  				cancel(nil)
   617  				return ctx
   618  			},
   619  			err:   Canceled,
   620  			cause: Canceled,
   621  		},
   622  		{
   623  			name: "WithCancelCause: parent cause before child",
   624  			ctx: func() Context {
   625  				ctx, cancelParent := WithCancelCause(Background())
   626  				ctx, cancelChild := WithCancelCause(ctx)
   627  				cancelParent(parentCause)
   628  				cancelChild(childCause)
   629  				return ctx
   630  			},
   631  			err:   Canceled,
   632  			cause: parentCause,
   633  		},
   634  		{
   635  			name: "WithCancelCause: parent cause after child",
   636  			ctx: func() Context {
   637  				ctx, cancelParent := WithCancelCause(Background())
   638  				ctx, cancelChild := WithCancelCause(ctx)
   639  				cancelChild(childCause)
   640  				cancelParent(parentCause)
   641  				return ctx
   642  			},
   643  			err:   Canceled,
   644  			cause: childCause,
   645  		},
   646  		{
   647  			name: "WithCancelCause: parent cause before nil",
   648  			ctx: func() Context {
   649  				ctx, cancelParent := WithCancelCause(Background())
   650  				ctx, cancelChild := WithCancel(ctx)
   651  				cancelParent(parentCause)
   652  				cancelChild()
   653  				return ctx
   654  			},
   655  			err:   Canceled,
   656  			cause: parentCause,
   657  		},
   658  		{
   659  			name: "WithCancelCause: parent cause after nil",
   660  			ctx: func() Context {
   661  				ctx, cancelParent := WithCancelCause(Background())
   662  				ctx, cancelChild := WithCancel(ctx)
   663  				cancelChild()
   664  				cancelParent(parentCause)
   665  				return ctx
   666  			},
   667  			err:   Canceled,
   668  			cause: Canceled,
   669  		},
   670  		{
   671  			name: "WithCancelCause: child cause after nil",
   672  			ctx: func() Context {
   673  				ctx, cancelParent := WithCancel(Background())
   674  				ctx, cancelChild := WithCancelCause(ctx)
   675  				cancelParent()
   676  				cancelChild(childCause)
   677  				return ctx
   678  			},
   679  			err:   Canceled,
   680  			cause: Canceled,
   681  		},
   682  		{
   683  			name: "WithCancelCause: child cause before nil",
   684  			ctx: func() Context {
   685  				ctx, cancelParent := WithCancel(Background())
   686  				ctx, cancelChild := WithCancelCause(ctx)
   687  				cancelChild(childCause)
   688  				cancelParent()
   689  				return ctx
   690  			},
   691  			err:   Canceled,
   692  			cause: childCause,
   693  		},
   694  		{
   695  			name: "WithTimeout",
   696  			ctx: func() Context {
   697  				ctx, cancel := WithTimeout(Background(), 0)
   698  				cancel()
   699  				return ctx
   700  			},
   701  			err:   DeadlineExceeded,
   702  			cause: DeadlineExceeded,
   703  		},
   704  		{
   705  			name: "WithTimeout canceled",
   706  			ctx: func() Context {
   707  				ctx, cancel := WithTimeout(Background(), forever)
   708  				cancel()
   709  				return ctx
   710  			},
   711  			err:   Canceled,
   712  			cause: Canceled,
   713  		},
   714  		{
   715  			name: "WithTimeoutCause",
   716  			ctx: func() Context {
   717  				ctx, cancel := WithTimeoutCause(Background(), 0, tooSlow)
   718  				cancel()
   719  				return ctx
   720  			},
   721  			err:   DeadlineExceeded,
   722  			cause: tooSlow,
   723  		},
   724  		{
   725  			name: "WithTimeoutCause canceled",
   726  			ctx: func() Context {
   727  				ctx, cancel := WithTimeoutCause(Background(), forever, tooSlow)
   728  				cancel()
   729  				return ctx
   730  			},
   731  			err:   Canceled,
   732  			cause: Canceled,
   733  		},
   734  		{
   735  			name: "WithTimeoutCause stacked",
   736  			ctx: func() Context {
   737  				ctx, cancel := WithCancelCause(Background())
   738  				ctx, _ = WithTimeoutCause(ctx, 0, tooSlow)
   739  				cancel(finishedEarly)
   740  				return ctx
   741  			},
   742  			err:   DeadlineExceeded,
   743  			cause: tooSlow,
   744  		},
   745  		{
   746  			name: "WithTimeoutCause stacked canceled",
   747  			ctx: func() Context {
   748  				ctx, cancel := WithCancelCause(Background())
   749  				ctx, _ = WithTimeoutCause(ctx, forever, tooSlow)
   750  				cancel(finishedEarly)
   751  				return ctx
   752  			},
   753  			err:   Canceled,
   754  			cause: finishedEarly,
   755  		},
   756  		{
   757  			name: "WithoutCancel",
   758  			ctx: func() Context {
   759  				return WithoutCancel(Background())
   760  			},
   761  			err:   nil,
   762  			cause: nil,
   763  		},
   764  		{
   765  			name: "WithoutCancel canceled",
   766  			ctx: func() Context {
   767  				ctx, cancel := WithCancelCause(Background())
   768  				ctx = WithoutCancel(ctx)
   769  				cancel(finishedEarly)
   770  				return ctx
   771  			},
   772  			err:   nil,
   773  			cause: nil,
   774  		},
   775  		{
   776  			name: "WithoutCancel timeout",
   777  			ctx: func() Context {
   778  				ctx, cancel := WithTimeoutCause(Background(), 0, tooSlow)
   779  				ctx = WithoutCancel(ctx)
   780  				cancel()
   781  				return ctx
   782  			},
   783  			err:   nil,
   784  			cause: nil,
   785  		},
   786  	} {
   787  		test := test
   788  		t.Run(test.name, func(t *testing.T) {
   789  			t.Parallel()
   790  			ctx := test.ctx()
   791  			if got, want := ctx.Err(), test.err; want != got {
   792  				t.Errorf("ctx.Err() = %v want %v", got, want)
   793  			}
   794  			if got, want := Cause(ctx), test.cause; want != got {
   795  				t.Errorf("Cause(ctx) = %v want %v", got, want)
   796  			}
   797  		})
   798  	}
   799  }
   800  
   801  func TestCauseRace(t *testing.T) {
   802  	cause := errors.New("TestCauseRace")
   803  	ctx, cancel := WithCancelCause(Background())
   804  	go func() {
   805  		cancel(cause)
   806  	}()
   807  	for {
   808  		// Poll Cause, rather than waiting for Done, to test that
   809  		// access to the underlying cause is synchronized properly.
   810  		if err := Cause(ctx); err != nil {
   811  			if err != cause {
   812  				t.Errorf("Cause returned %v, want %v", err, cause)
   813  			}
   814  			break
   815  		}
   816  		runtime.Gosched()
   817  	}
   818  }
   819  
   820  func TestWithoutCancel(t *testing.T) {
   821  	key, value := "key", "value"
   822  	ctx := WithValue(Background(), key, value)
   823  	ctx = WithoutCancel(ctx)
   824  	if d, ok := ctx.Deadline(); !d.IsZero() || ok != false {
   825  		t.Errorf("ctx.Deadline() = %v, %v want zero, false", d, ok)
   826  	}
   827  	if done := ctx.Done(); done != nil {
   828  		t.Errorf("ctx.Deadline() = %v want nil", done)
   829  	}
   830  	if err := ctx.Err(); err != nil {
   831  		t.Errorf("ctx.Err() = %v want nil", err)
   832  	}
   833  	if v := ctx.Value(key); v != value {
   834  		t.Errorf("ctx.Value(%q) = %q want %q", key, v, value)
   835  	}
   836  }
   837  
   838  type customDoneContext struct {
   839  	Context
   840  	donec chan struct{}
   841  }
   842  
   843  func (c *customDoneContext) Done() <-chan struct{} {
   844  	return c.donec
   845  }
   846  
   847  func TestCustomContextPropagation(t *testing.T) {
   848  	cause := errors.New("TestCustomContextPropagation")
   849  	donec := make(chan struct{})
   850  	ctx1, cancel1 := WithCancelCause(Background())
   851  	ctx2 := &customDoneContext{
   852  		Context: ctx1,
   853  		donec:   donec,
   854  	}
   855  	ctx3, cancel3 := WithCancel(ctx2)
   856  	defer cancel3()
   857  
   858  	cancel1(cause)
   859  	close(donec)
   860  
   861  	<-ctx3.Done()
   862  	if got, want := ctx3.Err(), Canceled; got != want {
   863  		t.Errorf("child not canceled; got = %v, want = %v", got, want)
   864  	}
   865  	if got, want := Cause(ctx3), cause; got != want {
   866  		t.Errorf("child has wrong cause; got = %v, want = %v", got, want)
   867  	}
   868  }
   869  
   870  func TestAfterFuncCalledAfterCancel(t *testing.T) {
   871  	ctx, cancel := WithCancel(Background())
   872  	donec := make(chan struct{})
   873  	stop := AfterFunc(ctx, func() {
   874  		close(donec)
   875  	})
   876  	select {
   877  	case <-donec:
   878  		t.Fatalf("AfterFunc called before context is done")
   879  	case <-time.After(shortDuration):
   880  	}
   881  	cancel()
   882  	select {
   883  	case <-donec:
   884  	case <-time.After(veryLongDuration):
   885  		t.Fatalf("AfterFunc not called after context is canceled")
   886  	}
   887  	if stop() {
   888  		t.Fatalf("stop() = true, want false")
   889  	}
   890  }
   891  
   892  func TestAfterFuncCalledAfterTimeout(t *testing.T) {
   893  	ctx, cancel := WithTimeout(Background(), shortDuration)
   894  	defer cancel()
   895  	donec := make(chan struct{})
   896  	AfterFunc(ctx, func() {
   897  		close(donec)
   898  	})
   899  	select {
   900  	case <-donec:
   901  	case <-time.After(veryLongDuration):
   902  		t.Fatalf("AfterFunc not called after context is canceled")
   903  	}
   904  }
   905  
   906  func TestAfterFuncCalledImmediately(t *testing.T) {
   907  	ctx, cancel := WithCancel(Background())
   908  	cancel()
   909  	donec := make(chan struct{})
   910  	AfterFunc(ctx, func() {
   911  		close(donec)
   912  	})
   913  	select {
   914  	case <-donec:
   915  	case <-time.After(veryLongDuration):
   916  		t.Fatalf("AfterFunc not called for already-canceled context")
   917  	}
   918  }
   919  
   920  func TestAfterFuncNotCalledAfterStop(t *testing.T) {
   921  	ctx, cancel := WithCancel(Background())
   922  	donec := make(chan struct{})
   923  	stop := AfterFunc(ctx, func() {
   924  		close(donec)
   925  	})
   926  	if !stop() {
   927  		t.Fatalf("stop() = false, want true")
   928  	}
   929  	cancel()
   930  	select {
   931  	case <-donec:
   932  		t.Fatalf("AfterFunc called for already-canceled context")
   933  	case <-time.After(shortDuration):
   934  	}
   935  	if stop() {
   936  		t.Fatalf("stop() = true, want false")
   937  	}
   938  }
   939  
   940  // This test verifies that cancelling a context does not block waiting for AfterFuncs to finish.
   941  func TestAfterFuncCalledAsynchronously(t *testing.T) {
   942  	ctx, cancel := WithCancel(Background())
   943  	donec := make(chan struct{})
   944  	stop := AfterFunc(ctx, func() {
   945  		// The channel send blocks until donec is read from.
   946  		donec <- struct{}{}
   947  	})
   948  	defer stop()
   949  	cancel()
   950  	// After cancel returns, read from donec and unblock the AfterFunc.
   951  	select {
   952  	case <-donec:
   953  	case <-time.After(veryLongDuration):
   954  		t.Fatalf("AfterFunc not called after context is canceled")
   955  	}
   956  }