Matteo Scandolo | a428586 | 2020-12-01 18:10:10 -0800 | [diff] [blame] | 1 | /* |
| 2 | Copyright 2014 The Kubernetes Authors. |
| 3 | |
| 4 | Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | you may not use this file except in compliance with the License. |
| 6 | You may obtain a copy of the License at |
| 7 | |
| 8 | http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | |
| 10 | Unless required by applicable law or agreed to in writing, software |
| 11 | distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | See the License for the specific language governing permissions and |
| 14 | limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | package clock |
| 18 | |
| 19 | import ( |
| 20 | "sync" |
| 21 | "time" |
| 22 | ) |
| 23 | |
| 24 | // PassiveClock allows for injecting fake or real clocks into code |
| 25 | // that needs to read the current time but does not support scheduling |
| 26 | // activity in the future. |
| 27 | type PassiveClock interface { |
| 28 | Now() time.Time |
| 29 | Since(time.Time) time.Duration |
| 30 | } |
| 31 | |
| 32 | // Clock allows for injecting fake or real clocks into code that |
| 33 | // needs to do arbitrary things based on time. |
| 34 | type Clock interface { |
| 35 | PassiveClock |
| 36 | After(time.Duration) <-chan time.Time |
| 37 | NewTimer(time.Duration) Timer |
| 38 | Sleep(time.Duration) |
| 39 | NewTicker(time.Duration) Ticker |
| 40 | } |
| 41 | |
| 42 | // RealClock really calls time.Now() |
| 43 | type RealClock struct{} |
| 44 | |
| 45 | // Now returns the current time. |
| 46 | func (RealClock) Now() time.Time { |
| 47 | return time.Now() |
| 48 | } |
| 49 | |
| 50 | // Since returns time since the specified timestamp. |
| 51 | func (RealClock) Since(ts time.Time) time.Duration { |
| 52 | return time.Since(ts) |
| 53 | } |
| 54 | |
| 55 | // After is the same as time.After(d). |
| 56 | func (RealClock) After(d time.Duration) <-chan time.Time { |
| 57 | return time.After(d) |
| 58 | } |
| 59 | |
| 60 | // NewTimer returns a new Timer. |
| 61 | func (RealClock) NewTimer(d time.Duration) Timer { |
| 62 | return &realTimer{ |
| 63 | timer: time.NewTimer(d), |
| 64 | } |
| 65 | } |
| 66 | |
| 67 | // NewTicker returns a new Ticker. |
| 68 | func (RealClock) NewTicker(d time.Duration) Ticker { |
| 69 | return &realTicker{ |
| 70 | ticker: time.NewTicker(d), |
| 71 | } |
| 72 | } |
| 73 | |
| 74 | // Sleep pauses the RealClock for duration d. |
| 75 | func (RealClock) Sleep(d time.Duration) { |
| 76 | time.Sleep(d) |
| 77 | } |
| 78 | |
| 79 | // FakePassiveClock implements PassiveClock, but returns an arbitrary time. |
| 80 | type FakePassiveClock struct { |
| 81 | lock sync.RWMutex |
| 82 | time time.Time |
| 83 | } |
| 84 | |
| 85 | // FakeClock implements Clock, but returns an arbitrary time. |
| 86 | type FakeClock struct { |
| 87 | FakePassiveClock |
| 88 | |
| 89 | // waiters are waiting for the fake time to pass their specified time |
| 90 | waiters []fakeClockWaiter |
| 91 | } |
| 92 | |
| 93 | type fakeClockWaiter struct { |
| 94 | targetTime time.Time |
| 95 | stepInterval time.Duration |
| 96 | skipIfBlocked bool |
| 97 | destChan chan time.Time |
| 98 | } |
| 99 | |
| 100 | // NewFakePassiveClock returns a new FakePassiveClock. |
| 101 | func NewFakePassiveClock(t time.Time) *FakePassiveClock { |
| 102 | return &FakePassiveClock{ |
| 103 | time: t, |
| 104 | } |
| 105 | } |
| 106 | |
| 107 | // NewFakeClock returns a new FakeClock |
| 108 | func NewFakeClock(t time.Time) *FakeClock { |
| 109 | return &FakeClock{ |
| 110 | FakePassiveClock: *NewFakePassiveClock(t), |
| 111 | } |
| 112 | } |
| 113 | |
| 114 | // Now returns f's time. |
| 115 | func (f *FakePassiveClock) Now() time.Time { |
| 116 | f.lock.RLock() |
| 117 | defer f.lock.RUnlock() |
| 118 | return f.time |
| 119 | } |
| 120 | |
| 121 | // Since returns time since the time in f. |
| 122 | func (f *FakePassiveClock) Since(ts time.Time) time.Duration { |
| 123 | f.lock.RLock() |
| 124 | defer f.lock.RUnlock() |
| 125 | return f.time.Sub(ts) |
| 126 | } |
| 127 | |
| 128 | // SetTime sets the time on the FakePassiveClock. |
| 129 | func (f *FakePassiveClock) SetTime(t time.Time) { |
| 130 | f.lock.Lock() |
| 131 | defer f.lock.Unlock() |
| 132 | f.time = t |
| 133 | } |
| 134 | |
| 135 | // After is the Fake version of time.After(d). |
| 136 | func (f *FakeClock) After(d time.Duration) <-chan time.Time { |
| 137 | f.lock.Lock() |
| 138 | defer f.lock.Unlock() |
| 139 | stopTime := f.time.Add(d) |
| 140 | ch := make(chan time.Time, 1) // Don't block! |
| 141 | f.waiters = append(f.waiters, fakeClockWaiter{ |
| 142 | targetTime: stopTime, |
| 143 | destChan: ch, |
| 144 | }) |
| 145 | return ch |
| 146 | } |
| 147 | |
| 148 | // NewTimer is the Fake version of time.NewTimer(d). |
| 149 | func (f *FakeClock) NewTimer(d time.Duration) Timer { |
| 150 | f.lock.Lock() |
| 151 | defer f.lock.Unlock() |
| 152 | stopTime := f.time.Add(d) |
| 153 | ch := make(chan time.Time, 1) // Don't block! |
| 154 | timer := &fakeTimer{ |
| 155 | fakeClock: f, |
| 156 | waiter: fakeClockWaiter{ |
| 157 | targetTime: stopTime, |
| 158 | destChan: ch, |
| 159 | }, |
| 160 | } |
| 161 | f.waiters = append(f.waiters, timer.waiter) |
| 162 | return timer |
| 163 | } |
| 164 | |
| 165 | // NewTicker returns a new Ticker. |
| 166 | func (f *FakeClock) NewTicker(d time.Duration) Ticker { |
| 167 | f.lock.Lock() |
| 168 | defer f.lock.Unlock() |
| 169 | tickTime := f.time.Add(d) |
| 170 | ch := make(chan time.Time, 1) // hold one tick |
| 171 | f.waiters = append(f.waiters, fakeClockWaiter{ |
| 172 | targetTime: tickTime, |
| 173 | stepInterval: d, |
| 174 | skipIfBlocked: true, |
| 175 | destChan: ch, |
| 176 | }) |
| 177 | |
| 178 | return &fakeTicker{ |
| 179 | c: ch, |
| 180 | } |
| 181 | } |
| 182 | |
| 183 | // Step moves clock by Duration, notifies anyone that's called After, Tick, or NewTimer |
| 184 | func (f *FakeClock) Step(d time.Duration) { |
| 185 | f.lock.Lock() |
| 186 | defer f.lock.Unlock() |
| 187 | f.setTimeLocked(f.time.Add(d)) |
| 188 | } |
| 189 | |
| 190 | // SetTime sets the time on a FakeClock. |
| 191 | func (f *FakeClock) SetTime(t time.Time) { |
| 192 | f.lock.Lock() |
| 193 | defer f.lock.Unlock() |
| 194 | f.setTimeLocked(t) |
| 195 | } |
| 196 | |
| 197 | // Actually changes the time and checks any waiters. f must be write-locked. |
| 198 | func (f *FakeClock) setTimeLocked(t time.Time) { |
| 199 | f.time = t |
| 200 | newWaiters := make([]fakeClockWaiter, 0, len(f.waiters)) |
| 201 | for i := range f.waiters { |
| 202 | w := &f.waiters[i] |
| 203 | if !w.targetTime.After(t) { |
| 204 | |
| 205 | if w.skipIfBlocked { |
| 206 | select { |
| 207 | case w.destChan <- t: |
| 208 | default: |
| 209 | } |
| 210 | } else { |
| 211 | w.destChan <- t |
| 212 | } |
| 213 | |
| 214 | if w.stepInterval > 0 { |
| 215 | for !w.targetTime.After(t) { |
| 216 | w.targetTime = w.targetTime.Add(w.stepInterval) |
| 217 | } |
| 218 | newWaiters = append(newWaiters, *w) |
| 219 | } |
| 220 | |
| 221 | } else { |
| 222 | newWaiters = append(newWaiters, f.waiters[i]) |
| 223 | } |
| 224 | } |
| 225 | f.waiters = newWaiters |
| 226 | } |
| 227 | |
| 228 | // HasWaiters returns true if After has been called on f but not yet satisfied (so you can |
| 229 | // write race-free tests). |
| 230 | func (f *FakeClock) HasWaiters() bool { |
| 231 | f.lock.RLock() |
| 232 | defer f.lock.RUnlock() |
| 233 | return len(f.waiters) > 0 |
| 234 | } |
| 235 | |
| 236 | // Sleep pauses the FakeClock for duration d. |
| 237 | func (f *FakeClock) Sleep(d time.Duration) { |
| 238 | f.Step(d) |
| 239 | } |
| 240 | |
| 241 | // IntervalClock implements Clock, but each invocation of Now steps the clock forward the specified duration |
| 242 | type IntervalClock struct { |
| 243 | Time time.Time |
| 244 | Duration time.Duration |
| 245 | } |
| 246 | |
| 247 | // Now returns i's time. |
| 248 | func (i *IntervalClock) Now() time.Time { |
| 249 | i.Time = i.Time.Add(i.Duration) |
| 250 | return i.Time |
| 251 | } |
| 252 | |
| 253 | // Since returns time since the time in i. |
| 254 | func (i *IntervalClock) Since(ts time.Time) time.Duration { |
| 255 | return i.Time.Sub(ts) |
| 256 | } |
| 257 | |
| 258 | // After is currently unimplemented, will panic. |
| 259 | // TODO: make interval clock use FakeClock so this can be implemented. |
| 260 | func (*IntervalClock) After(d time.Duration) <-chan time.Time { |
| 261 | panic("IntervalClock doesn't implement After") |
| 262 | } |
| 263 | |
| 264 | // NewTimer is currently unimplemented, will panic. |
| 265 | // TODO: make interval clock use FakeClock so this can be implemented. |
| 266 | func (*IntervalClock) NewTimer(d time.Duration) Timer { |
| 267 | panic("IntervalClock doesn't implement NewTimer") |
| 268 | } |
| 269 | |
| 270 | // NewTicker is currently unimplemented, will panic. |
| 271 | // TODO: make interval clock use FakeClock so this can be implemented. |
| 272 | func (*IntervalClock) NewTicker(d time.Duration) Ticker { |
| 273 | panic("IntervalClock doesn't implement NewTicker") |
| 274 | } |
| 275 | |
| 276 | // Sleep is currently unimplemented; will panic. |
| 277 | func (*IntervalClock) Sleep(d time.Duration) { |
| 278 | panic("IntervalClock doesn't implement Sleep") |
| 279 | } |
| 280 | |
| 281 | // Timer allows for injecting fake or real timers into code that |
| 282 | // needs to do arbitrary things based on time. |
| 283 | type Timer interface { |
| 284 | C() <-chan time.Time |
| 285 | Stop() bool |
| 286 | Reset(d time.Duration) bool |
| 287 | } |
| 288 | |
| 289 | // realTimer is backed by an actual time.Timer. |
| 290 | type realTimer struct { |
| 291 | timer *time.Timer |
| 292 | } |
| 293 | |
| 294 | // C returns the underlying timer's channel. |
| 295 | func (r *realTimer) C() <-chan time.Time { |
| 296 | return r.timer.C |
| 297 | } |
| 298 | |
| 299 | // Stop calls Stop() on the underlying timer. |
| 300 | func (r *realTimer) Stop() bool { |
| 301 | return r.timer.Stop() |
| 302 | } |
| 303 | |
| 304 | // Reset calls Reset() on the underlying timer. |
| 305 | func (r *realTimer) Reset(d time.Duration) bool { |
| 306 | return r.timer.Reset(d) |
| 307 | } |
| 308 | |
| 309 | // fakeTimer implements Timer based on a FakeClock. |
| 310 | type fakeTimer struct { |
| 311 | fakeClock *FakeClock |
| 312 | waiter fakeClockWaiter |
| 313 | } |
| 314 | |
| 315 | // C returns the channel that notifies when this timer has fired. |
| 316 | func (f *fakeTimer) C() <-chan time.Time { |
| 317 | return f.waiter.destChan |
| 318 | } |
| 319 | |
| 320 | // Stop conditionally stops the timer. If the timer has neither fired |
| 321 | // nor been stopped then this call stops the timer and returns true, |
| 322 | // otherwise this call returns false. This is like time.Timer::Stop. |
| 323 | func (f *fakeTimer) Stop() bool { |
| 324 | f.fakeClock.lock.Lock() |
| 325 | defer f.fakeClock.lock.Unlock() |
| 326 | // The timer has already fired or been stopped, unless it is found |
| 327 | // among the clock's waiters. |
| 328 | stopped := false |
| 329 | oldWaiters := f.fakeClock.waiters |
| 330 | newWaiters := make([]fakeClockWaiter, 0, len(oldWaiters)) |
| 331 | seekChan := f.waiter.destChan |
| 332 | for i := range oldWaiters { |
| 333 | // Identify the timer's fakeClockWaiter by the identity of the |
| 334 | // destination channel, nothing else is necessarily unique and |
| 335 | // constant since the timer's creation. |
| 336 | if oldWaiters[i].destChan == seekChan { |
| 337 | stopped = true |
| 338 | } else { |
| 339 | newWaiters = append(newWaiters, oldWaiters[i]) |
| 340 | } |
| 341 | } |
| 342 | |
| 343 | f.fakeClock.waiters = newWaiters |
| 344 | |
| 345 | return stopped |
| 346 | } |
| 347 | |
| 348 | // Reset conditionally updates the firing time of the timer. If the |
| 349 | // timer has neither fired nor been stopped then this call resets the |
| 350 | // timer to the fake clock's "now" + d and returns true, otherwise |
| 351 | // this call returns false. This is like time.Timer::Reset. |
| 352 | func (f *fakeTimer) Reset(d time.Duration) bool { |
| 353 | f.fakeClock.lock.Lock() |
| 354 | defer f.fakeClock.lock.Unlock() |
| 355 | waiters := f.fakeClock.waiters |
| 356 | seekChan := f.waiter.destChan |
| 357 | for i := range waiters { |
| 358 | if waiters[i].destChan == seekChan { |
| 359 | waiters[i].targetTime = f.fakeClock.time.Add(d) |
| 360 | return true |
| 361 | } |
| 362 | } |
| 363 | return false |
| 364 | } |
| 365 | |
| 366 | // Ticker defines the Ticker interface |
| 367 | type Ticker interface { |
| 368 | C() <-chan time.Time |
| 369 | Stop() |
| 370 | } |
| 371 | |
| 372 | type realTicker struct { |
| 373 | ticker *time.Ticker |
| 374 | } |
| 375 | |
| 376 | func (t *realTicker) C() <-chan time.Time { |
| 377 | return t.ticker.C |
| 378 | } |
| 379 | |
| 380 | func (t *realTicker) Stop() { |
| 381 | t.ticker.Stop() |
| 382 | } |
| 383 | |
| 384 | type fakeTicker struct { |
| 385 | c <-chan time.Time |
| 386 | } |
| 387 | |
| 388 | func (t *fakeTicker) C() <-chan time.Time { |
| 389 | return t.c |
| 390 | } |
| 391 | |
| 392 | func (t *fakeTicker) Stop() { |
| 393 | } |