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