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

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: More test coverage, cleanup, consolidation. 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
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 "strings"
10 "sync"
8 "testing" 11 "testing"
9 "time" 12 "time"
10 13
11 "github.com/luci/luci-go/common/clock" 14 "github.com/luci/luci-go/common/clock"
15 "golang.org/x/net/context"
16
12 . "github.com/smartystreets/goconvey/convey" 17 . "github.com/smartystreets/goconvey/convey"
13 ) 18 )
14 19
15 func TestTestTimer(t *testing.T) { 20 func TestTestTimer(t *testing.T) {
16 t.Parallel() 21 t.Parallel()
17 22
18 Convey(`A testing clock instance`, t, func() { 23 Convey(`A testing clock instance`, t, func() {
19 » » now := time.Date(2015, 01, 01, 00, 00, 00, 00, time.UTC) 24 » » ctx, cancelFunc := context.WithCancel(context.Background())
20 » » c := New(now) 25 » » defer cancelFunc()
26
27 » » now := TestTimeLocal
28 » » clk := New(now)
21 29
22 Convey(`A timer instance`, func() { 30 Convey(`A timer instance`, func() {
23 » » » t := c.NewTimer() 31 » » » t := clk.NewTimer(ctx)
24 32
25 Convey(`Should have a non-nil C.`, func() { 33 Convey(`Should have a non-nil C.`, func() {
26 » » » » So(t.GetC(), ShouldBeNil) 34 » » » » So(t.GetC(), ShouldNotBeNil)
27 }) 35 })
28 36
29 Convey(`When activated`, func() { 37 Convey(`When activated`, func() {
30 So(t.Reset(1*time.Second), ShouldBeFalse) 38 So(t.Reset(1*time.Second), ShouldBeFalse)
31 39
32 Convey(`When reset, should return active.`, func () { 40 Convey(`When reset, should return active.`, func () {
33 So(t.Reset(1*time.Hour), ShouldBeTrue) 41 So(t.Reset(1*time.Hour), ShouldBeTrue)
34 So(t.GetC(), ShouldNotBeNil) 42 So(t.GetC(), ShouldNotBeNil)
35 }) 43 })
36 44
37 Convey(`When stopped, should return active.`, fu nc() { 45 Convey(`When stopped, should return active.`, fu nc() {
38 So(t.Stop(), ShouldBeTrue) 46 So(t.Stop(), ShouldBeTrue)
39 » » » » » So(t.GetC(), ShouldBeNil) 47 » » » » » So(t.GetC(), ShouldNotBeNil)
40 48
41 Convey(`And when stopped again, should r eturn inactive.`, func() { 49 Convey(`And when stopped again, should r eturn inactive.`, func() {
42 So(t.Stop(), ShouldBeFalse) 50 So(t.Stop(), ShouldBeFalse)
43 » » » » » » So(t.GetC(), ShouldBeNil) 51 » » » » » » So(t.GetC(), ShouldNotBeNil)
44 }) 52 })
45 }) 53 })
46 54
47 Convey(`When stopped after expiring, should not have a signal.`, func() { 55 Convey(`When stopped after expiring, should not have a signal.`, func() {
48 » » » » » c.Add(1 * time.Second) 56 » » » » » clk.Add(1 * time.Second)
49 So(t.Stop(), ShouldBeTrue) 57 So(t.Stop(), ShouldBeTrue)
50 58
51 var signalled bool 59 var signalled bool
52 select { 60 select {
53 case <-t.GetC(): 61 case <-t.GetC():
54 signalled = true 62 signalled = true
55 default: 63 default:
56 break 64 break
57 } 65 }
58 So(signalled, ShouldBeFalse) 66 So(signalled, ShouldBeFalse)
59 }) 67 })
60 }) 68 })
61 69
62 Convey(`Should successfully signal.`, func() { 70 Convey(`Should successfully signal.`, func() {
63 So(t.Reset(1*time.Second), ShouldBeFalse) 71 So(t.Reset(1*time.Second), ShouldBeFalse)
64 » » » » c.Add(1 * time.Second) 72 » » » » clk.Add(1 * time.Second)
65 73
66 » » » » So(t.GetC(), ShouldNotBeNil) 74 » » » » So(<-t.GetC(), ShouldResemble, clock.TimerResult {Time: now.Add(1 * time.Second)})
67 » » » » So(<-t.GetC(), ShouldResemble, now.Add(1*time.Se cond)) 75 » » » })
76
77 » » » Convey(`Should signal immediately if the timer is in the past.`, func() {
78 » » » » So(t.Reset(-1*time.Second), ShouldBeFalse)
79 » » » » So(<-t.GetC(), ShouldResemble, clock.TimerResult {Time: now})
80 » » » })
81
82 » » » Convey(`Will trigger immediately if the Context is cance led when reset.`, func() {
83 » » » » cancelFunc()
84
85 » » » » // Works for the first timer?
86 » » » » So(t.Reset(time.Hour), ShouldBeFalse)
87 » » » » So((<-t.GetC()).Err, ShouldEqual, context.Cancel ed)
88
89 » » » » // Works for the second timer?
90 » » » » So(t.Reset(time.Hour), ShouldBeFalse)
91 » » » » So((<-t.GetC()).Err, ShouldEqual, context.Cancel ed)
92 » » » })
93
94 » » » Convey(`Will trigger when the Context is canceled.`, fun c() {
95 » » » » clk.SetTimerCallback(func(time.Duration, clock.T imer) {
96 » » » » » cancelFunc()
97 » » » » })
98
99 » » » » // Works for the first timer?
100 » » » » So(t.Reset(time.Hour), ShouldBeFalse)
101 » » » » So((<-t.GetC()).Err, ShouldEqual, context.Cancel ed)
102
103 » » » » // Works for the second timer?
104 » » » » So(t.Reset(time.Hour), ShouldBeFalse)
105 » » » » So((<-t.GetC()).Err, ShouldEqual, context.Cancel ed)
106 » » » })
107
108 » » » Convey(`Can set and retrieve timer tags.`, func() {
109 » » » » var tagMu sync.Mutex
110 » » » » tagMap := map[string]struct{}{}
111
112 » » » » // On the last timer callback, advance time past the timer threshold.
113 » » » » timers := make([]clock.Timer, 10)
114 » » » » count := 0
115 » » » » clk.SetTimerCallback(func(_ time.Duration, t clo ck.Timer) {
116 » » » » » tagMu.Lock()
117 » » » » » defer tagMu.Unlock()
118
119 » » » » » tagMap[strings.Join(GetTags(t), "")] = s truct{}{}
120 » » » » » count++
121 » » » » » if count == len(timers) {
122 » » » » » » clk.Add(time.Second)
123 » » » » » }
124 » » » » })
125
126 » » » » for i := range timers {
127 » » » » » t := clk.NewTimer(clock.Tag(ctx, fmt.Spr intf("%d", i)))
128 » » » » » t.Reset(time.Second)
129 » » » » » timers[i] = t
130 » » » » }
131
132 » » » » // Wait until all timers have expired.
133 » » » » for _, t := range timers {
134 » » » » » <-t.GetC()
135 » » » » }
136
137 » » » » // Did we see all of their tags?
138 » » » » for i := range timers {
139 » » » » » _, ok := tagMap[fmt.Sprintf("%d", i)]
140 » » » » » So(ok, ShouldBeTrue)
141 » » » » }
142 » » » })
143
144 » » » Convey(`A non-test timer has a nil tag.`, func() {
145 » » » » t := trashTimer{}
146 » » » » So(GetTags(t), ShouldBeNil)
iannucci 2016/02/10 22:30:28 add test for block on channel and concurrent Stop(
dnj (Google) 2016/02/11 01:26:55 Done.
68 }) 147 })
69 }) 148 })
70 149
71 » » Convey(`Multiple goroutines using the timer...`, func() { 150 » » Convey(`Multiple goroutines using timers...`, func() {
72 // Mark when timers are started, so we can ensure that o ur signalling 151 // Mark when timers are started, so we can ensure that o ur signalling
73 // happens after the timers have been instantiated. 152 // happens after the timers have been instantiated.
74 timerStartedC := make(chan bool) 153 timerStartedC := make(chan bool)
75 » » » c.SetTimerCallback(func(_ time.Duration, _ clock.Timer) { 154 » » » clk.SetTimerCallback(func(_ time.Duration, _ clock.Timer ) {
76 timerStartedC <- true 155 timerStartedC <- true
77 }) 156 })
78 157
79 » » » resultC := make(chan time.Time) 158 » » » resultC := make(chan clock.TimerResult)
80 for i := time.Duration(0); i < 5; i++ { 159 for i := time.Duration(0); i < 5; i++ {
81 go func(d time.Duration) { 160 go func(d time.Duration) {
82 » » » » » timer := c.NewTimer() 161 » » » » » timer := clk.NewTimer(ctx)
83 timer.Reset(d) 162 timer.Reset(d)
84 resultC <- <-timer.GetC() 163 resultC <- <-timer.GetC()
85 }(i * time.Second) 164 }(i * time.Second)
86 <-timerStartedC 165 <-timerStartedC
87 } 166 }
88 167
89 moreResults := func() bool { 168 moreResults := func() bool {
90 select { 169 select {
91 case <-resultC: 170 case <-resultC:
92 return true 171 return true
93 default: 172 default:
94 return false 173 return false
95 } 174 }
96 } 175 }
97 176
98 // Advance the clock to +2s. Three timers should signal. 177 // Advance the clock to +2s. Three timers should signal.
99 » » » c.Set(now.Add(2 * time.Second)) 178 » » » clk.Set(now.Add(2 * time.Second))
100 <-resultC 179 <-resultC
101 <-resultC 180 <-resultC
102 <-resultC 181 <-resultC
103 So(moreResults(), ShouldBeFalse) 182 So(moreResults(), ShouldBeFalse)
104 183
105 // Advance clock to +3s. One timer should signal. 184 // Advance clock to +3s. One timer should signal.
106 » » » c.Set(now.Add(3 * time.Second)) 185 » » » clk.Set(now.Add(3 * time.Second))
107 <-resultC 186 <-resultC
108 So(moreResults(), ShouldBeFalse) 187 So(moreResults(), ShouldBeFalse)
109 188
110 // Advance clock to +10s. One final timer should signal. 189 // Advance clock to +10s. One final timer should signal.
111 » » » c.Set(now.Add(10 * time.Second)) 190 » » » clk.Set(now.Add(10 * time.Second))
112 <-resultC 191 <-resultC
113 So(moreResults(), ShouldBeFalse) 192 So(moreResults(), ShouldBeFalse)
114 }) 193 })
115 }) 194 })
116 } 195 }
196
197 func TestTimerTags(t *testing.T) {
198 t.Parallel()
199
200 Convey(`A context with flags {"A", "B"}`, t, func() {
iannucci 2016/02/10 22:30:28 s/flags/tags
dnj (Google) 2016/02/11 01:26:55 Done.
201 c := clock.Tag(clock.Tag(context.Background(), "A"), "B")
202
203 Convey(`Has tags, {"A", "B"}`, func() {
204 So(clock.Tags(c), ShouldResemble, []string{"A", "B"})
205 })
206
207 Convey(`Will be retained by a testclock.Timer.`, func() {
208 tc := New(TestTimeUTC)
209 t := tc.NewTimer(c)
210
211 So(GetTags(t), ShouldResemble, []string{"A", "B"})
212
213 Convey(`The timer tests positive for tags {"A", "B"}`, f unc() {
214 So(HasTags(t, "A", "B"), ShouldBeTrue)
215 })
216
217 Convey(`The timer tests negative for tags {}, {"A"}, {"B "}, and {"A", "C"}`, func() {
218 So(HasTags(t), ShouldBeFalse)
219 So(HasTags(t, "A"), ShouldBeFalse)
220 So(HasTags(t, "B"), ShouldBeFalse)
221 So(HasTags(t, "A", "C"), ShouldBeFalse)
222 })
223 })
224
225 Convey(`A non-test timer tests negative for {"A", "B"} and posit ive for {}.`, func() {
226 clk := clock.GetSystemClock()
227 t := clk.NewTimer(c)
228
229 So(HasTags(t), ShouldBeTrue)
230 So(HasTags(t, "A", "B"), ShouldBeFalse)
231 })
232 })
233 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698