Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(184)

Side by Side Diff: common/clock/testclock/testtimer_test.go

Issue 1679023005: Add Context cancellation to clock. (Closed) Base URL: https://github.com/luci/luci-go@master
Patch Set: Actually upload the patch. Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « common/clock/testclock/testtimer.go ('k') | common/clock/timer.go » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 testclock 5 package testclock
6 6
7 import ( 7 import (
8 "fmt"
9 "runtime"
10 "strings"
11 "sync"
8 "testing" 12 "testing"
9 "time" 13 "time"
10 14
11 "github.com/luci/luci-go/common/clock" 15 "github.com/luci/luci-go/common/clock"
16 "golang.org/x/net/context"
17
12 . "github.com/smartystreets/goconvey/convey" 18 . "github.com/smartystreets/goconvey/convey"
13 ) 19 )
14 20
21 // trashTimer is a useless implementation of clock.Timer specifically designed
22 // to exist and not be a test timer type.
23 type trashTimer struct {
24 clock.Timer
25 }
26
15 func TestTestTimer(t *testing.T) { 27 func TestTestTimer(t *testing.T) {
16 t.Parallel() 28 t.Parallel()
17 29
18 Convey(`A testing clock instance`, t, func() { 30 Convey(`A testing clock instance`, t, func() {
19 » » now := time.Date(2015, 01, 01, 00, 00, 00, 00, time.UTC) 31 » » ctx, cancelFunc := context.WithCancel(context.Background())
20 » » c := New(now) 32 » » defer cancelFunc()
33
34 » » now := TestTimeLocal
35 » » clk := New(now)
21 36
22 Convey(`A timer instance`, func() { 37 Convey(`A timer instance`, func() {
23 » » » t := c.NewTimer() 38 » » » t := clk.NewTimer(ctx)
24 39
25 Convey(`Should have a non-nil C.`, func() { 40 Convey(`Should have a non-nil C.`, func() {
26 » » » » So(t.GetC(), ShouldBeNil) 41 » » » » So(t.GetC(), ShouldNotBeNil)
27 }) 42 })
28 43
29 Convey(`When activated`, func() { 44 Convey(`When activated`, func() {
30 So(t.Reset(1*time.Second), ShouldBeFalse) 45 So(t.Reset(1*time.Second), ShouldBeFalse)
31 46
32 Convey(`When reset, should return active.`, func () { 47 Convey(`When reset, should return active.`, func () {
33 So(t.Reset(1*time.Hour), ShouldBeTrue) 48 So(t.Reset(1*time.Hour), ShouldBeTrue)
34 So(t.GetC(), ShouldNotBeNil) 49 So(t.GetC(), ShouldNotBeNil)
35 }) 50 })
36 51
37 Convey(`When stopped, should return active.`, fu nc() { 52 Convey(`When stopped, should return active.`, fu nc() {
38 So(t.Stop(), ShouldBeTrue) 53 So(t.Stop(), ShouldBeTrue)
39 » » » » » So(t.GetC(), ShouldBeNil) 54 » » » » » So(t.GetC(), ShouldNotBeNil)
40 55
41 Convey(`And when stopped again, should r eturn inactive.`, func() { 56 Convey(`And when stopped again, should r eturn inactive.`, func() {
42 So(t.Stop(), ShouldBeFalse) 57 So(t.Stop(), ShouldBeFalse)
43 » » » » » » So(t.GetC(), ShouldBeNil) 58 » » » » » » So(t.GetC(), ShouldNotBeNil)
44 }) 59 })
45 }) 60 })
46 61
47 Convey(`When stopped after expiring, should not have a signal.`, func() { 62 Convey(`When stopped after expiring, should not have a signal.`, func() {
48 » » » » » c.Add(1 * time.Second) 63 » » » » » clk.Add(1 * time.Second)
49 So(t.Stop(), ShouldBeTrue) 64 So(t.Stop(), ShouldBeTrue)
50 65
51 var signalled bool 66 var signalled bool
52 select { 67 select {
53 case <-t.GetC(): 68 case <-t.GetC():
54 signalled = true 69 signalled = true
55 default: 70 default:
56 break 71 break
57 } 72 }
58 So(signalled, ShouldBeFalse) 73 So(signalled, ShouldBeFalse)
59 }) 74 })
60 }) 75 })
61 76
62 Convey(`Should successfully signal.`, func() { 77 Convey(`Should successfully signal.`, func() {
63 So(t.Reset(1*time.Second), ShouldBeFalse) 78 So(t.Reset(1*time.Second), ShouldBeFalse)
64 » » » » c.Add(1 * time.Second) 79 » » » » clk.Add(1 * time.Second)
65 80
66 » » » » So(t.GetC(), ShouldNotBeNil) 81 » » » » So(<-t.GetC(), ShouldResemble, clock.TimerResult {Time: now.Add(1 * time.Second)})
67 » » » » So(<-t.GetC(), ShouldResemble, now.Add(1*time.Se cond)) 82 » » » })
83
84 » » » Convey(`Should signal immediately if the timer is in the past.`, func() {
85 » » » » So(t.Reset(-1*time.Second), ShouldBeFalse)
86 » » » » So(<-t.GetC(), ShouldResemble, clock.TimerResult {Time: now})
87 » » » })
88
89 » » » Convey(`Will trigger immediately if the Context is cance led when reset.`, func() {
90 » » » » cancelFunc()
91
92 » » » » // Works for the first timer?
93 » » » » So(t.Reset(time.Hour), ShouldBeFalse)
94 » » » » So((<-t.GetC()).Err, ShouldEqual, context.Cancel ed)
95
96 » » » » // Works for the second timer?
97 » » » » So(t.Reset(time.Hour), ShouldBeFalse)
98 » » » » So((<-t.GetC()).Err, ShouldEqual, context.Cancel ed)
99 » » » })
100
101 » » » Convey(`Will trigger when the Context is canceled.`, fun c() {
102 » » » » clk.SetTimerCallback(func(time.Duration, clock.T imer) {
103 » » » » » cancelFunc()
104 » » » » })
105
106 » » » » // Works for the first timer?
107 » » » » So(t.Reset(time.Hour), ShouldBeFalse)
108 » » » » So((<-t.GetC()).Err, ShouldEqual, context.Cancel ed)
109
110 » » » » // Works for the second timer?
111 » » » » So(t.Reset(time.Hour), ShouldBeFalse)
112 » » » » So((<-t.GetC()).Err, ShouldEqual, context.Cancel ed)
113 » » » })
114
115 » » » Convey(`Will use the same channel when reset.`, func() {
116 » » » » timerC := t.GetC()
117 » » » » t.Reset(time.Second)
118 » » » » clk.Add(time.Second)
119 » » » » So(<-timerC, ShouldResemble, clock.TimerResult{T ime: now.Add(1 * time.Second)})
120 » » » })
121
122 » » » Convey(`Will not signal the timer channel if stopped.`, func() {
123 » » » » t.Reset(time.Second)
124 » » » » t.Stop()
125 » » » » clk.Add(time.Second)
126
127 » » » » runtime.Gosched()
128
129 » » » » triggered := false
130 » » » » select {
131 » » » » case <-t.GetC():
132 » » » » » triggered = true
133 » » » » default:
134 » » » » » break
135 » » » » }
136 » » » » So(triggered, ShouldBeFalse)
137 » » » })
138
139 » » » Convey(`Can set and retrieve timer tags.`, func() {
140 » » » » var tagMu sync.Mutex
141 » » » » tagMap := map[string]struct{}{}
142
143 » » » » // On the last timer callback, advance time past the timer threshold.
144 » » » » timers := make([]clock.Timer, 10)
145 » » » » count := 0
146 » » » » clk.SetTimerCallback(func(_ time.Duration, t clo ck.Timer) {
147 » » » » » tagMu.Lock()
148 » » » » » defer tagMu.Unlock()
149
150 » » » » » tagMap[strings.Join(GetTags(t), "")] = s truct{}{}
151 » » » » » count++
152 » » » » » if count == len(timers) {
153 » » » » » » clk.Add(time.Second)
154 » » » » » }
155 » » » » })
156
157 » » » » for i := range timers {
158 » » » » » t := clk.NewTimer(clock.Tag(ctx, fmt.Spr intf("%d", i)))
159 » » » » » t.Reset(time.Second)
160 » » » » » timers[i] = t
161 » » » » }
162
163 » » » » // Wait until all timers have expired.
164 » » » » for _, t := range timers {
165 » » » » » <-t.GetC()
166 » » » » }
167
168 » » » » // Did we see all of their tags?
169 » » » » for i := range timers {
170 » » » » » _, ok := tagMap[fmt.Sprintf("%d", i)]
171 » » » » » So(ok, ShouldBeTrue)
172 » » » » }
173 » » » })
174
175 » » » Convey(`A non-test timer has a nil tag.`, func() {
176 » » » » t := trashTimer{}
177 » » » » So(GetTags(t), ShouldBeNil)
68 }) 178 })
69 }) 179 })
70 180
71 » » Convey(`Multiple goroutines using the timer...`, func() { 181 » » Convey(`Multiple goroutines using timers...`, func() {
72 // Mark when timers are started, so we can ensure that o ur signalling 182 // Mark when timers are started, so we can ensure that o ur signalling
73 // happens after the timers have been instantiated. 183 // happens after the timers have been instantiated.
74 timerStartedC := make(chan bool) 184 timerStartedC := make(chan bool)
75 » » » c.SetTimerCallback(func(_ time.Duration, _ clock.Timer) { 185 » » » clk.SetTimerCallback(func(_ time.Duration, _ clock.Timer ) {
76 timerStartedC <- true 186 timerStartedC <- true
77 }) 187 })
78 188
79 » » » resultC := make(chan time.Time) 189 » » » resultC := make(chan clock.TimerResult)
80 for i := time.Duration(0); i < 5; i++ { 190 for i := time.Duration(0); i < 5; i++ {
81 go func(d time.Duration) { 191 go func(d time.Duration) {
82 » » » » » timer := c.NewTimer() 192 » » » » » timer := clk.NewTimer(ctx)
83 timer.Reset(d) 193 timer.Reset(d)
84 resultC <- <-timer.GetC() 194 resultC <- <-timer.GetC()
85 }(i * time.Second) 195 }(i * time.Second)
86 <-timerStartedC 196 <-timerStartedC
87 } 197 }
88 198
89 moreResults := func() bool { 199 moreResults := func() bool {
90 select { 200 select {
91 case <-resultC: 201 case <-resultC:
92 return true 202 return true
93 default: 203 default:
94 return false 204 return false
95 } 205 }
96 } 206 }
97 207
98 // Advance the clock to +2s. Three timers should signal. 208 // Advance the clock to +2s. Three timers should signal.
99 » » » c.Set(now.Add(2 * time.Second)) 209 » » » clk.Set(now.Add(2 * time.Second))
100 <-resultC 210 <-resultC
101 <-resultC 211 <-resultC
102 <-resultC 212 <-resultC
103 So(moreResults(), ShouldBeFalse) 213 So(moreResults(), ShouldBeFalse)
104 214
105 // Advance clock to +3s. One timer should signal. 215 // Advance clock to +3s. One timer should signal.
106 » » » c.Set(now.Add(3 * time.Second)) 216 » » » clk.Set(now.Add(3 * time.Second))
107 <-resultC 217 <-resultC
108 So(moreResults(), ShouldBeFalse) 218 So(moreResults(), ShouldBeFalse)
109 219
110 // Advance clock to +10s. One final timer should signal. 220 // Advance clock to +10s. One final timer should signal.
111 » » » c.Set(now.Add(10 * time.Second)) 221 » » » clk.Set(now.Add(10 * time.Second))
112 <-resultC 222 <-resultC
113 So(moreResults(), ShouldBeFalse) 223 So(moreResults(), ShouldBeFalse)
114 }) 224 })
115 }) 225 })
116 } 226 }
227
228 func TestTimerTags(t *testing.T) {
229 t.Parallel()
230
231 Convey(`A context with tags {"A", "B"}`, t, func() {
232 c := clock.Tag(clock.Tag(context.Background(), "A"), "B")
233
234 Convey(`Has tags, {"A", "B"}`, func() {
235 So(clock.Tags(c), ShouldResemble, []string{"A", "B"})
236 })
237
238 Convey(`Will be retained by a testclock.Timer.`, func() {
239 tc := New(TestTimeUTC)
240 t := tc.NewTimer(c)
241
242 So(GetTags(t), ShouldResemble, []string{"A", "B"})
243
244 Convey(`The timer tests positive for tags {"A", "B"}`, f unc() {
245 So(HasTags(t, "A", "B"), ShouldBeTrue)
246 })
247
248 Convey(`The timer tests negative for tags {"A"}, {"B"}, and {"A", "C"}`, func() {
249 So(HasTags(t, "A"), ShouldBeFalse)
250 So(HasTags(t, "B"), ShouldBeFalse)
251 So(HasTags(t, "A", "C"), ShouldBeFalse)
252 })
253 })
254
255 Convey(`A non-test timer tests negative for {"A"} and {"A", "B"} .`, func() {
256 t := &trashTimer{}
257
258 So(HasTags(t, "A"), ShouldBeFalse)
259 So(HasTags(t, "A", "B"), ShouldBeFalse)
260 })
261 })
262 }
OLDNEW
« no previous file with comments | « common/clock/testclock/testtimer.go ('k') | common/clock/timer.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698