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