You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

583 lines
15 KiB

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