OLD | NEW |
---|---|
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 package clock | 5 package clock |
6 | 6 |
7 import ( | 7 import ( |
8 "testing" | 8 "testing" |
9 "time" | 9 "time" |
10 | 10 |
11 . "github.com/smartystreets/goconvey/convey" | 11 . "github.com/smartystreets/goconvey/convey" |
12 "golang.org/x/net/context" | 12 "golang.org/x/net/context" |
13 ) | 13 ) |
14 | 14 |
15 // A test blocking operation. | 15 // manualClock is a partial Clock implementation that allows us to release |
16 func blockingOperation(ctx context.Context, releaseC chan struct{}) (bool, error ) { | 16 // blocking calls. |
17 » select { | 17 type manualClock struct { |
dnj (Google)
2016/02/10 03:19:03
This test used to lean on system "time" clock. Sin
| |
18 » case <-ctx.Done(): | 18 » Clock |
19 » » return false, ctx.Err() | |
20 | 19 |
21 » case <-releaseC: | 20 » now time.Time |
22 » » return true, nil | 21 » timeoutCallback func(time.Duration) bool |
23 » } | 22 » testFinishedC chan struct{} |
23 } | |
24 | |
25 func (mc *manualClock) Now() time.Time { | |
26 » return mc.now | |
27 } | |
28 | |
29 func (mc *manualClock) After(ctx context.Context, d time.Duration) <-chan AfterR esult { | |
30 » resultC := make(chan AfterResult) | |
31 » go func() { | |
32 » » ar := AfterResult{} | |
33 » » defer func() { | |
34 » » » resultC <- ar | |
35 » » }() | |
36 | |
37 » » // If we are instructed to immediately timeout, do so. | |
38 » » if cb := mc.timeoutCallback; cb != nil && cb(d) { | |
39 » » » return | |
40 » » } | |
41 | |
42 » » select { | |
43 » » case <-ctx.Done(): | |
44 » » » ar.Err = ctx.Err() | |
45 » » case <-mc.testFinishedC: | |
46 » » » break | |
47 » » } | |
48 » }() | |
49 | |
50 » return resultC | |
51 } | |
52 | |
53 func wait(c context.Context) error { | |
54 » <-c.Done() | |
55 » return c.Err() | |
24 } | 56 } |
25 | 57 |
26 func TestClockContext(t *testing.T) { | 58 func TestClockContext(t *testing.T) { |
27 t.Parallel() | 59 t.Parallel() |
28 | 60 |
29 » Convey(`A context with a deadline wrapping a cancellable parent`, t, fun c() { | 61 » Convey(`A manual testing clock`, t, func() { |
30 » » now := time.Now() | 62 » » mc := manualClock{ |
31 » » cctx, pcf := context.WithCancel(context.Background()) | 63 » » » now: time.Date(2016, 1, 1, 0, 0, 0, 0, time.Lo cal), |
32 » » ctx, cf := WithTimeout(cctx, 10*time.Millisecond) | 64 » » » testFinishedC: make(chan struct{}), |
33 » » releaseC := make(chan struct{}) | 65 » » } |
66 » » defer close(mc.testFinishedC) | |
34 | 67 |
35 » » Convey(`Successfully reports its deadline.`, func() { | 68 » » Convey(`A context with a deadline wrapping a cancellable parent` , func() { |
36 » » » deadline, ok := ctx.Deadline() | 69 » » » cctx, pcf := context.WithCancel(Set(context.Background() , &mc)) |
37 » » » So(ok, ShouldBeTrue) | 70 » » » ctx, cf := WithTimeout(cctx, 10*time.Millisecond) |
38 » » » So(deadline.After(now), ShouldBeTrue) | 71 |
72 » » » Convey(`Successfully reports its deadline.`, func() { | |
73 » » » » deadline, ok := ctx.Deadline() | |
74 » » » » So(ok, ShouldBeTrue) | |
75 » » » » So(deadline.After(mc.now), ShouldBeTrue) | |
76 » » » }) | |
77 | |
78 » » » Convey(`Will successfully time out.`, func() { | |
79 » » » » mc.timeoutCallback = func(time.Duration) bool { | |
80 » » » » » return true | |
81 » » » » } | |
82 » » » » So(wait(ctx), ShouldEqual, context.DeadlineExcee ded) | |
83 » » » }) | |
84 | |
85 » » » Convey(`Will successfully cancel with its cancel func.`, func() { | |
86 » » » » go func() { | |
87 » » » » » cf() | |
88 » » » » }() | |
89 » » » » So(wait(ctx), ShouldEqual, context.Canceled) | |
90 » » » }) | |
91 | |
92 » » » Convey(`Will successfully cancel if the parent is cancel ed.`, func() { | |
93 » » » » go func() { | |
94 » » » » » pcf() | |
95 » » » » }() | |
96 » » » » So(wait(ctx), ShouldEqual, context.Canceled) | |
97 » » » }) | |
39 }) | 98 }) |
40 | 99 |
41 » » Convey(`Will successfully time out.`, func() { | 100 » » Convey(`A context with a deadline wrapping a parent with a short er deadline`, func() { |
42 » » » released, err := blockingOperation(ctx, releaseC) | 101 » » » cctx, _ := context.WithTimeout(context.Background(), 10* time.Millisecond) |
43 » » » So(released, ShouldBeFalse) | 102 » » » ctx, cf := WithTimeout(cctx, 1*time.Hour) |
44 » » » So(err, ShouldEqual, context.DeadlineExceeded) | 103 |
104 » » » Convey(`Will successfully time out.`, func() { | |
105 » » » » mc.timeoutCallback = func(d time.Duration) bool { | |
106 » » » » » return d == 10*time.Millisecond | |
107 » » » » } | |
108 | |
109 » » » » So(wait(ctx), ShouldEqual, context.DeadlineExcee ded) | |
110 » » » }) | |
111 | |
112 » » » Convey(`Will successfully cancel with its cancel func.`, func() { | |
113 » » » » go func() { | |
114 » » » » » cf() | |
115 » » » » }() | |
116 » » » » So(wait(ctx), ShouldEqual, context.Canceled) | |
117 » » » }) | |
45 }) | 118 }) |
46 | 119 |
47 » » Convey(`Will successfully cancel with its cancel func.`, func() { | 120 » » Convey(`A context with a deadline in the past`, func() { |
48 » » » go func() { | 121 » » » ctx, _ := WithDeadline(context.Background(), mc.now.Add( -time.Second)) |
49 » » » » cf() | |
50 » » » }() | |
51 » » » released, err := blockingOperation(ctx, releaseC) | |
52 » » » So(released, ShouldBeFalse) | |
53 » » » So(err, ShouldEqual, context.Canceled) | |
54 » » }) | |
55 | 122 |
56 » » Convey(`Will successfully cancel if the parent is cancelled.`, f unc() { | 123 » » » Convey(`Will time out immediately.`, func() { |
57 » » » go func() { | 124 » » » » So(wait(ctx), ShouldEqual, context.DeadlineExcee ded) |
58 » » » » pcf() | 125 » » » }) |
59 » » » }() | |
60 » » » released, err := blockingOperation(ctx, releaseC) | |
61 » » » So(released, ShouldBeFalse) | |
62 » » » So(err, ShouldEqual, context.Canceled) | |
63 » » }) | |
64 | |
65 » » Convey(`Will release before the deadline.`, func() { | |
66 » » » go func() { | |
67 » » » » close(releaseC) | |
68 » » » }() | |
69 » » » released, err := blockingOperation(ctx, releaseC) | |
70 » » » So(released, ShouldBeTrue) | |
71 » » » So(err, ShouldBeNil) | |
72 » » }) | |
73 » }) | |
74 | |
75 » Convey(`A context with a deadline wrapping a parent with a shorter deadl ine`, t, func() { | |
76 » » cctx, _ := context.WithTimeout(context.Background(), 10*time.Mil lisecond) | |
77 » » ctx, cf := WithTimeout(cctx, 1*time.Hour) | |
78 » » releaseC := make(chan struct{}) | |
79 | |
80 » » Convey(`Will successfully time out.`, func() { | |
81 » » » released, err := blockingOperation(ctx, releaseC) | |
82 » » » So(released, ShouldBeFalse) | |
83 » » » So(err, ShouldEqual, context.DeadlineExceeded) | |
84 » » }) | |
85 | |
86 » » Convey(`Will successfully cancel with its cancel func.`, func() { | |
87 » » » go func() { | |
88 » » » » cf() | |
89 » » » }() | |
90 » » » released, err := blockingOperation(ctx, releaseC) | |
91 » » » So(released, ShouldBeFalse) | |
92 » » » So(err, ShouldEqual, context.Canceled) | |
93 » » }) | |
94 » }) | |
95 | |
96 » Convey(`A context with a deadline in the past`, t, func() { | |
97 » » ctx, _ := WithDeadline(context.Background(), time.Unix(0, 0)) | |
98 » » releaseC := make(chan struct{}) | |
99 | |
100 » » Convey(`Will time out immediately.`, func() { | |
101 » » » go func() { | |
102 » » » » defer close(releaseC) | |
103 » » » » time.Sleep(50 * time.Millisecond) | |
104 » » » }() | |
105 » » » released, err := blockingOperation(ctx, releaseC) | |
106 » » » So(released, ShouldBeFalse) | |
107 » » » So(err, ShouldEqual, context.DeadlineExceeded) | |
108 }) | 126 }) |
109 }) | 127 }) |
110 } | 128 } |
OLD | NEW |