github.com/kubernetes/utils@v0.0.0-20190308190857-21c4ce38f2a7/clock/testing/fake_clock.go (about) 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 testing 18 19 import ( 20 "sync" 21 "time" 22 23 "k8s.io/utils/clock" 24 ) 25 26 var ( 27 _ = clock.Clock(&FakeClock{}) 28 _ = clock.Clock(&IntervalClock{}) 29 ) 30 31 // FakeClock implements clock.Clock, but returns an arbitrary time. 32 type FakeClock struct { 33 lock sync.RWMutex 34 time time.Time 35 36 // waiters are waiting for the fake time to pass their specified time 37 waiters []*fakeClockWaiter 38 } 39 40 type fakeClockWaiter struct { 41 targetTime time.Time 42 stepInterval time.Duration 43 skipIfBlocked bool 44 destChan chan time.Time 45 fired bool 46 } 47 48 // NewFakeClock constructs a fake clock set to the provided time. 49 func NewFakeClock(t time.Time) *FakeClock { 50 return &FakeClock{ 51 time: t, 52 } 53 } 54 55 // Now returns f's time. 56 func (f *FakeClock) Now() time.Time { 57 f.lock.RLock() 58 defer f.lock.RUnlock() 59 return f.time 60 } 61 62 // Since returns time since the time in f. 63 func (f *FakeClock) Since(ts time.Time) time.Duration { 64 f.lock.RLock() 65 defer f.lock.RUnlock() 66 return f.time.Sub(ts) 67 } 68 69 // After is the fake version of time.After(d). 70 func (f *FakeClock) After(d time.Duration) <-chan time.Time { 71 f.lock.Lock() 72 defer f.lock.Unlock() 73 stopTime := f.time.Add(d) 74 ch := make(chan time.Time, 1) // Don't block! 75 f.waiters = append(f.waiters, &fakeClockWaiter{ 76 targetTime: stopTime, 77 destChan: ch, 78 }) 79 return ch 80 } 81 82 // NewTimer constructs a fake timer, akin to time.NewTimer(d). 83 func (f *FakeClock) NewTimer(d time.Duration) clock.Timer { 84 f.lock.Lock() 85 defer f.lock.Unlock() 86 stopTime := f.time.Add(d) 87 ch := make(chan time.Time, 1) // Don't block! 88 timer := &fakeTimer{ 89 fakeClock: f, 90 waiter: fakeClockWaiter{ 91 targetTime: stopTime, 92 destChan: ch, 93 }, 94 } 95 f.waiters = append(f.waiters, &timer.waiter) 96 return timer 97 } 98 99 // Tick constructs a fake ticker, akin to time.Tick 100 func (f *FakeClock) Tick(d time.Duration) <-chan time.Time { 101 if d <= 0 { 102 return nil 103 } 104 f.lock.Lock() 105 defer f.lock.Unlock() 106 tickTime := f.time.Add(d) 107 ch := make(chan time.Time, 1) // hold one tick 108 f.waiters = append(f.waiters, &fakeClockWaiter{ 109 targetTime: tickTime, 110 stepInterval: d, 111 skipIfBlocked: true, 112 destChan: ch, 113 }) 114 115 return ch 116 } 117 118 // Step moves the clock by Duration and notifies anyone that's called After, 119 // Tick, or NewTimer. 120 func (f *FakeClock) Step(d time.Duration) { 121 f.lock.Lock() 122 defer f.lock.Unlock() 123 f.setTimeLocked(f.time.Add(d)) 124 } 125 126 // SetTime sets the time. 127 func (f *FakeClock) SetTime(t time.Time) { 128 f.lock.Lock() 129 defer f.lock.Unlock() 130 f.setTimeLocked(t) 131 } 132 133 // Actually changes the time and checks any waiters. f must be write-locked. 134 func (f *FakeClock) setTimeLocked(t time.Time) { 135 f.time = t 136 newWaiters := make([]*fakeClockWaiter, 0, len(f.waiters)) 137 for i := range f.waiters { 138 w := f.waiters[i] 139 if !w.targetTime.After(t) { 140 141 if w.skipIfBlocked { 142 select { 143 case w.destChan <- t: 144 w.fired = true 145 default: 146 } 147 } else { 148 w.destChan <- t 149 w.fired = true 150 } 151 152 if w.stepInterval > 0 { 153 for !w.targetTime.After(t) { 154 w.targetTime = w.targetTime.Add(w.stepInterval) 155 } 156 newWaiters = append(newWaiters, w) 157 } 158 159 } else { 160 newWaiters = append(newWaiters, f.waiters[i]) 161 } 162 } 163 f.waiters = newWaiters 164 } 165 166 // HasWaiters returns true if After has been called on f but not yet satisfied (so you can 167 // write race-free tests). 168 func (f *FakeClock) HasWaiters() bool { 169 f.lock.RLock() 170 defer f.lock.RUnlock() 171 return len(f.waiters) > 0 172 } 173 174 // Sleep is akin to time.Sleep 175 func (f *FakeClock) Sleep(d time.Duration) { 176 f.Step(d) 177 } 178 179 // IntervalClock implements clock.Clock, but each invocation of Now steps the clock forward the specified duration 180 type IntervalClock struct { 181 Time time.Time 182 Duration time.Duration 183 } 184 185 // Now returns i's time. 186 func (i *IntervalClock) Now() time.Time { 187 i.Time = i.Time.Add(i.Duration) 188 return i.Time 189 } 190 191 // Since returns time since the time in i. 192 func (i *IntervalClock) Since(ts time.Time) time.Duration { 193 return i.Time.Sub(ts) 194 } 195 196 // After is unimplemented, will panic. 197 // TODO: make interval clock use FakeClock so this can be implemented. 198 func (*IntervalClock) After(d time.Duration) <-chan time.Time { 199 panic("IntervalClock doesn't implement After") 200 } 201 202 // NewTimer is unimplemented, will panic. 203 // TODO: make interval clock use FakeClock so this can be implemented. 204 func (*IntervalClock) NewTimer(d time.Duration) clock.Timer { 205 panic("IntervalClock doesn't implement NewTimer") 206 } 207 208 // Tick is unimplemented, will panic. 209 // TODO: make interval clock use FakeClock so this can be implemented. 210 func (*IntervalClock) Tick(d time.Duration) <-chan time.Time { 211 panic("IntervalClock doesn't implement Tick") 212 } 213 214 // Sleep is unimplemented, will panic. 215 func (*IntervalClock) Sleep(d time.Duration) { 216 panic("IntervalClock doesn't implement Sleep") 217 } 218 219 var _ = clock.Timer(&fakeTimer{}) 220 221 // fakeTimer implements clock.Timer based on a FakeClock. 222 type fakeTimer struct { 223 fakeClock *FakeClock 224 waiter fakeClockWaiter 225 } 226 227 // C returns the channel that notifies when this timer has fired. 228 func (f *fakeTimer) C() <-chan time.Time { 229 return f.waiter.destChan 230 } 231 232 // Stop stops the timer and returns true if the timer has not yet fired, or false otherwise. 233 func (f *fakeTimer) Stop() bool { 234 f.fakeClock.lock.Lock() 235 defer f.fakeClock.lock.Unlock() 236 237 newWaiters := make([]*fakeClockWaiter, 0, len(f.fakeClock.waiters)) 238 for i := range f.fakeClock.waiters { 239 w := f.fakeClock.waiters[i] 240 if w != &f.waiter { 241 newWaiters = append(newWaiters, w) 242 } 243 } 244 245 f.fakeClock.waiters = newWaiters 246 247 return !f.waiter.fired 248 } 249 250 // Reset resets the timer to the fake clock's "now" + d. It returns true if the timer has not yet 251 // fired, or false otherwise. 252 func (f *fakeTimer) Reset(d time.Duration) bool { 253 f.fakeClock.lock.Lock() 254 defer f.fakeClock.lock.Unlock() 255 256 active := !f.waiter.fired 257 258 f.waiter.fired = false 259 f.waiter.targetTime = f.fakeClock.time.Add(d) 260 261 var isWaiting bool 262 for i := range f.fakeClock.waiters { 263 w := f.fakeClock.waiters[i] 264 if w == &f.waiter { 265 isWaiting = true 266 break 267 } 268 } 269 if !isWaiting { 270 f.fakeClock.waiters = append(f.fakeClock.waiters, &f.waiter) 271 } 272 273 return active 274 }