Chromium Code Reviews| 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 |