github.com/rogpeppe/clock@v0.0.0-20190514195947-2896927a307a/testclock/clock.go (about) 1 // Copyright 2015-2018 Canonical Ltd. 2 // Licensed under the LGPLv3, see LICENCE file for details. 3 4 package testclock 5 6 import ( 7 "fmt" 8 "runtime/debug" 9 "sort" 10 "sync" 11 "time" 12 13 "github.com/rogpeppe/clock" 14 ) 15 16 // timer implements a mock clock.Timer for testing purposes. 17 type timer struct { 18 deadline time.Time 19 clock *Clock 20 c chan time.Time 21 // trigger is called when the timer expires. It is 22 // called with the clock mutex held and will not block. 23 trigger func() 24 stack []byte 25 } 26 27 // Reset is part of the clock.Timer interface. 28 func (t *timer) Reset(d time.Duration) bool { 29 return t.clock.reset(t, d) 30 } 31 32 // Stop is part of the clock.Timer interface. 33 func (t *timer) Stop() bool { 34 return t.clock.stop(t) 35 } 36 37 // Chan is part of the clock.Timer interface. 38 func (t *timer) Chan() <-chan time.Time { 39 return t.c 40 } 41 42 // Clock implements a mock clock.Clock for testing purposes. 43 type Clock struct { 44 mu sync.Mutex 45 log func(string) 46 now time.Time 47 waiting []*timer // timers waiting to fire, sorted by deadline. 48 notifyAlarms chan struct{} 49 } 50 51 // NewClock returns a new clock set to the supplied time. If your SUT needs to 52 // call After, AfterFunc, NewTimer or Timer.Reset more than 10000 times: (1) 53 // you have probably written a bad test; and (2) you'll need to read from the 54 // Alarms chan to keep the buffer clear. 55 func NewClock(now time.Time) *Clock { 56 return &Clock{ 57 log: func(string) {}, 58 now: now, 59 notifyAlarms: make(chan struct{}, 10000), 60 } 61 } 62 63 // SetLog sets the log function that's called if something that probably 64 // shouldn't happen occurs. 65 func (clock *Clock) SetLog(log func(msg string)) { 66 clock.log = log 67 } 68 69 // Now is part of the clock.Clock interface. 70 func (clock *Clock) Now() time.Time { 71 clock.mu.Lock() 72 defer clock.mu.Unlock() 73 return clock.now 74 } 75 76 // After is part of the clock.Clock interface. 77 func (clock *Clock) After(d time.Duration) <-chan time.Time { 78 return clock.NewTimer(d).Chan() 79 } 80 81 func (clock *Clock) NewTimer(d time.Duration) clock.Timer { 82 c := make(chan time.Time, 1) 83 return clock.addAlarm(d, c, func() { 84 c <- clock.now 85 }) 86 } 87 88 // AfterFunc is part of the clock.Clock interface. 89 func (clock *Clock) AfterFunc(d time.Duration, f func()) clock.Timer { 90 return clock.addAlarm(d, nil, func() { 91 go f() 92 }) 93 } 94 95 func (clock *Clock) addAlarm(d time.Duration, c chan time.Time, trigger func()) *timer { 96 defer clock.notifyAlarm() 97 clock.mu.Lock() 98 defer clock.mu.Unlock() 99 t := &timer{ 100 c: c, 101 deadline: clock.now.Add(d), 102 clock: clock, 103 trigger: trigger, 104 stack: debug.Stack(), 105 } 106 clock.addTimer(t) 107 clock.triggerAll() 108 return t 109 } 110 111 // Advance advances the result of Now by the supplied duration, and sends 112 // the "current" time on all alarms which are no longer "in the future". 113 func (clock *Clock) Advance(d time.Duration) { 114 clock.mu.Lock() 115 defer clock.mu.Unlock() 116 clock.now = clock.now.Add(d) 117 if len(clock.waiting) == 0 { 118 clock.log("advancing a clock that has nothing waiting: cf. https://github.com/juju/juju/wiki/Intermittent-failures") 119 } 120 clock.triggerAll() 121 } 122 123 // WaitAdvance functions the same as Advance, but only if there is n timers in 124 // clock.waiting. This came about while fixing lp:1607044 intermittent 125 // failures. It turns out that testing.Clock.Advance might advance the time 126 // and trigger notifications before triggers are set. So we wait a limited time 127 // 'w' for 'n' timers to show up in clock.waiting, and if they do we advance 128 // 'd'. 129 func (clock *Clock) WaitAdvance(d, w time.Duration, n int) error { 130 pause := w / 10 131 if pause > 10*time.Millisecond { 132 pause = 10 * time.Millisecond 133 } 134 finalTimeout := time.After(w) 135 next := time.After(0) 136 for { 137 select { 138 case <-finalTimeout: 139 if clock.hasNWaiters(n) { 140 clock.Advance(d) 141 return nil 142 } 143 clock.mu.Lock() 144 got := len(clock.waiting) 145 var stacks string 146 for _, t := range clock.waiting { 147 stacks += fmt.Sprintf("timer deadline: %v\n%s", t.deadline, string(t.stack)) 148 } 149 clock.mu.Unlock() 150 return fmt.Errorf( 151 "got %d timers added after waiting %s: wanted %d, stacks:\n%s", 152 got, w.String(), n, stacks) 153 case <-next: 154 if clock.hasNWaiters(n) { 155 clock.Advance(d) 156 return nil 157 } 158 next = time.After(pause) 159 } 160 } 161 } 162 163 // hasNWaiters checks if the clock currently has 'n' timers waiting to fire. 164 func (clock *Clock) hasNWaiters(n int) bool { 165 clock.mu.Lock() 166 hasWaiters := len(clock.waiting) == n 167 clock.mu.Unlock() 168 return hasWaiters 169 } 170 171 // Alarms returns a channel on which you can read one value for every call to 172 // After and AfterFunc; and for every successful Timer.Reset backed by this 173 // Clock. It might not be elegant but it's necessary when testing time logic 174 // that runs on a goroutine other than that of the test. 175 func (clock *Clock) Alarms() <-chan struct{} { 176 return clock.notifyAlarms 177 } 178 179 // triggerAll triggers any alarms that are currently due and removes them 180 // from clock.waiting. 181 func (clock *Clock) triggerAll() { 182 triggered := 0 183 for _, t := range clock.waiting { 184 if clock.now.Before(t.deadline) { 185 break 186 } 187 t.trigger() 188 triggered++ 189 } 190 clock.waiting = clock.waiting[triggered:] 191 } 192 193 // reset is the underlying implementation of clock.Timer.Reset, which may be 194 // called by any Timer backed by this Clock. 195 func (clock *Clock) reset(t *timer, d time.Duration) bool { 196 defer clock.notifyAlarm() 197 clock.mu.Lock() 198 defer clock.mu.Unlock() 199 200 found := false 201 for _, wt := range clock.waiting { 202 if wt == t { 203 found = true 204 } 205 } 206 if !found { 207 clock.waiting = append(clock.waiting, t) 208 } 209 t.deadline = clock.now.Add(d) 210 sort.Sort(byDeadline(clock.waiting)) 211 if d <= 0 { 212 // If duration is <= 0, that means we should be triggering the 213 // Timer right away, as "now" has already occured. 214 clock.triggerAll() 215 } 216 return found 217 } 218 219 // stop is the underlying implementation of clock.Timer.Reset, which may be 220 // called by any Timer backed by this Clock. 221 func (clock *Clock) stop(t *timer) bool { 222 clock.mu.Lock() 223 defer clock.mu.Unlock() 224 225 for i, wt := range clock.waiting { 226 if wt == t { 227 clock.waiting = removeFromSlice(clock.waiting, i) 228 return true 229 } 230 } 231 return false 232 } 233 234 // addTimer adds an alarm at time t. 235 func (clock *Clock) addTimer(t *timer) { 236 clock.waiting = append(clock.waiting, t) 237 sort.Sort(byDeadline(clock.waiting)) 238 } 239 240 // notifyAlarm sends a value on the channel exposed by Alarms(). 241 func (clock *Clock) notifyAlarm() { 242 select { 243 case clock.notifyAlarms <- struct{}{}: 244 default: 245 panic("alarm notification buffer full") 246 } 247 } 248 249 // byDeadline is used to sort alarms by time. 250 type byDeadline []*timer 251 252 func (a byDeadline) Len() int { return len(a) } 253 func (a byDeadline) Less(i, j int) bool { return a[i].deadline.Before(a[j].deadline) } 254 func (a byDeadline) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 255 256 // removeFromSlice removes item at the specified index from the slice. 257 func removeFromSlice(sl []*timer, index int) []*timer { 258 return append(sl[:index], sl[index+1:]...) 259 } 260 261 // AutoAdvancingClock wraps a clock.Clock, calling the Advance 262 // function whenever After or AfterFunc are called. 263 type AutoAdvancingClock struct { 264 clock.Clock 265 Advance func(time.Duration) 266 } 267 268 func (c *AutoAdvancingClock) After(d time.Duration) <-chan time.Time { 269 ch := c.Clock.After(d) 270 c.Advance(d) 271 return ch 272 } 273 274 func (c *AutoAdvancingClock) AfterFunc(d time.Duration, f func()) clock.Timer { 275 t := c.Clock.AfterFunc(d, f) 276 c.Advance(d) 277 return t 278 }