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 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 } | |
OLD | NEW |