blob: 6cf13d83d10131bb028dd3ec11add6b006af73f7 [file] [log] [blame]
Matteo Scandoloa4285862020-12-01 18:10:10 -08001/*
2Copyright 2014 The Kubernetes Authors.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17package clock
18
19import (
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.
27type 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.
34type 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()
43type RealClock struct{}
44
45// Now returns the current time.
46func (RealClock) Now() time.Time {
47 return time.Now()
48}
49
50// Since returns time since the specified timestamp.
51func (RealClock) Since(ts time.Time) time.Duration {
52 return time.Since(ts)
53}
54
55// After is the same as time.After(d).
56func (RealClock) After(d time.Duration) <-chan time.Time {
57 return time.After(d)
58}
59
60// NewTimer returns a new Timer.
61func (RealClock) NewTimer(d time.Duration) Timer {
62 return &realTimer{
63 timer: time.NewTimer(d),
64 }
65}
66
67// NewTicker returns a new Ticker.
68func (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.
75func (RealClock) Sleep(d time.Duration) {
76 time.Sleep(d)
77}
78
79// FakePassiveClock implements PassiveClock, but returns an arbitrary time.
80type FakePassiveClock struct {
81 lock sync.RWMutex
82 time time.Time
83}
84
85// FakeClock implements Clock, but returns an arbitrary time.
86type FakeClock struct {
87 FakePassiveClock
88
89 // waiters are waiting for the fake time to pass their specified time
90 waiters []fakeClockWaiter
91}
92
93type 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.
101func NewFakePassiveClock(t time.Time) *FakePassiveClock {
102 return &FakePassiveClock{
103 time: t,
104 }
105}
106
107// NewFakeClock returns a new FakeClock
108func NewFakeClock(t time.Time) *FakeClock {
109 return &FakeClock{
110 FakePassiveClock: *NewFakePassiveClock(t),
111 }
112}
113
114// Now returns f's time.
115func (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.
122func (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.
129func (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).
136func (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).
149func (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.
166func (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
184func (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.
191func (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.
198func (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).
230func (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.
237func (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
242type IntervalClock struct {
243 Time time.Time
244 Duration time.Duration
245}
246
247// Now returns i's time.
248func (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.
254func (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.
260func (*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.
266func (*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.
272func (*IntervalClock) NewTicker(d time.Duration) Ticker {
273 panic("IntervalClock doesn't implement NewTicker")
274}
275
276// Sleep is currently unimplemented; will panic.
277func (*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.
283type 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.
290type realTimer struct {
291 timer *time.Timer
292}
293
294// C returns the underlying timer's channel.
295func (r *realTimer) C() <-chan time.Time {
296 return r.timer.C
297}
298
299// Stop calls Stop() on the underlying timer.
300func (r *realTimer) Stop() bool {
301 return r.timer.Stop()
302}
303
304// Reset calls Reset() on the underlying timer.
305func (r *realTimer) Reset(d time.Duration) bool {
306 return r.timer.Reset(d)
307}
308
309// fakeTimer implements Timer based on a FakeClock.
310type fakeTimer struct {
311 fakeClock *FakeClock
312 waiter fakeClockWaiter
313}
314
315// C returns the channel that notifies when this timer has fired.
316func (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.
323func (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.
352func (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
367type Ticker interface {
368 C() <-chan time.Time
369 Stop()
370}
371
372type realTicker struct {
373 ticker *time.Ticker
374}
375
376func (t *realTicker) C() <-chan time.Time {
377 return t.ticker.C
378}
379
380func (t *realTicker) Stop() {
381 t.ticker.Stop()
382}
383
384type fakeTicker struct {
385 c <-chan time.Time
386}
387
388func (t *fakeTicker) C() <-chan time.Time {
389 return t.c
390}
391
392func (t *fakeTicker) Stop() {
393}