├── LICENSE ├── README.md ├── clock.go └── clock_test.go /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Ben Johnson 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | clock [![Build Status](https://drone.io/github.com/benbjohnson/clock/status.png)](https://drone.io/github.com/benbjohnson/clock/latest) [![Coverage Status](https://coveralls.io/repos/benbjohnson/clock/badge.png?branch=master)](https://coveralls.io/r/benbjohnson/clock?branch=master) [![GoDoc](https://godoc.org/github.com/benbjohnson/clock?status.png)](https://godoc.org/github.com/benbjohnson/clock) ![Project status](http://img.shields.io/status/experimental.png?color=red) 2 | ===== 3 | 4 | Clock is a small library for mocking time in Go. It provides an interface 5 | around the standard library's [`time`][time] package so that the application 6 | can use the realtime clock while tests can use the mock clock. 7 | 8 | [time]: http://golang.org/pkg/time/ 9 | 10 | 11 | ## Usage 12 | 13 | ### Realtime Clock 14 | 15 | Your application can maintain a `Clock` variable that will allow realtime and 16 | mock clocks to be interchangable. For example, if you had an `Application` type: 17 | 18 | ```go 19 | import "github.com/benbjohnson/clock" 20 | 21 | type Application struct { 22 | Clock clock.Clock 23 | } 24 | ``` 25 | 26 | You could initialize it to use the realtime clock like this: 27 | 28 | ```go 29 | var app Application 30 | app.Clock = clock.New() 31 | ... 32 | ``` 33 | 34 | Then all timers and time-related functionality should be performed from the 35 | `Clock` variable. 36 | 37 | 38 | ### Mocking time 39 | 40 | In your tests, you will want to use a `Mock` clock: 41 | 42 | ```go 43 | import ( 44 | "testing" 45 | 46 | "github.com/benbjohnson/clock" 47 | ) 48 | 49 | func TestApplication_DoSomething(t *testing.T) { 50 | mock := clock.NewMock() 51 | app := Application{Clock: mock} 52 | ... 53 | } 54 | ``` 55 | 56 | Now that you've initialized your application to use the mock clock, you can 57 | adjust the time programmatically. The mock clock always starts from the Unix 58 | epoch (midnight, Jan 1, 1970 UTC). 59 | 60 | 61 | ### Controlling time 62 | 63 | The mock clock provides the same functions that the standard library's `time` 64 | package provides. For example, to find the current time, you use the `Now()` 65 | function: 66 | 67 | ```go 68 | mock := clock.NewMock() 69 | 70 | // Find the current time. 71 | mock.Now().UTC() // 1970-01-01 00:00:00 +0000 UTC 72 | 73 | // Move the clock forward. 74 | mock.Add(2 * time.Hour) 75 | 76 | // Check the time again. It's 2 hours later! 77 | mock.Now().UTC() // 1970-01-01 02:00:00 +0000 UTC 78 | ``` 79 | 80 | Timers and Tickers are also controlled by this same mock clock. They will only 81 | execute when the clock is moved forward: 82 | 83 | ``` 84 | mock := clock.NewMock() 85 | count := 0 86 | 87 | // Kick off a timer to increment every 1 mock second. 88 | go func() { 89 | ticker := clock.Ticker(1 * time.Second) 90 | for { 91 | <-ticker.C 92 | count++ 93 | } 94 | }() 95 | runtime.Gosched() 96 | 97 | // Move the clock forward 10 second. 98 | mock.Add(10 * time.Second) 99 | 100 | // This prints 10. 101 | fmt.Println(count) 102 | ``` 103 | 104 | 105 | -------------------------------------------------------------------------------- /clock.go: -------------------------------------------------------------------------------- 1 | package clock 2 | 3 | import ( 4 | "runtime" 5 | "sort" 6 | "sync" 7 | "time" 8 | ) 9 | 10 | // Clock represents an interface to the functions in the standard library time 11 | // package. Two implementations are available in the clock package. The first 12 | // is a real-time clock which simply wraps the time package's functions. The 13 | // second is a mock clock which will only make forward progress when 14 | // programmatically adjusted. 15 | type Clock interface { 16 | After(d time.Duration) <-chan time.Time 17 | AfterFunc(d time.Duration, f func()) *Timer 18 | Now() time.Time 19 | Sleep(d time.Duration) 20 | Tick(d time.Duration) <-chan time.Time 21 | Ticker(d time.Duration) *Ticker 22 | Timer(d time.Duration) *Timer 23 | } 24 | 25 | // New returns an instance of a real-time clock. 26 | func New() Clock { 27 | return &clock{} 28 | } 29 | 30 | // clock implements a real-time clock by simply wrapping the time package functions. 31 | type clock struct{} 32 | 33 | func (c *clock) After(d time.Duration) <-chan time.Time { return time.After(d) } 34 | 35 | func (c *clock) AfterFunc(d time.Duration, f func()) *Timer { 36 | return &Timer{timer: time.AfterFunc(d, f)} 37 | } 38 | 39 | func (c *clock) Now() time.Time { return time.Now() } 40 | 41 | func (c *clock) Sleep(d time.Duration) { time.Sleep(d) } 42 | 43 | func (c *clock) Tick(d time.Duration) <-chan time.Time { return time.Tick(d) } 44 | 45 | func (c *clock) Ticker(d time.Duration) *Ticker { 46 | t := time.NewTicker(d) 47 | return &Ticker{C: t.C, ticker: t} 48 | } 49 | 50 | func (c *clock) Timer(d time.Duration) *Timer { 51 | t := time.NewTimer(d) 52 | return &Timer{C: t.C, timer: t} 53 | } 54 | 55 | // Mock represents a mock clock that only moves forward programmically. 56 | // It can be preferable to a real-time clock when testing time-based functionality. 57 | type Mock struct { 58 | mu sync.Mutex 59 | now time.Time // current time 60 | timers clockTimers // tickers & timers 61 | 62 | calls Calls 63 | waiting []waiting 64 | callsMutex sync.Mutex 65 | } 66 | 67 | // NewMock returns an instance of a mock clock. 68 | // The current time of the mock clock on initialization is the Unix epoch. 69 | func NewMock() *Mock { 70 | return &Mock{now: time.Unix(0, 0)} 71 | } 72 | 73 | // Add moves the current time of the mock clock forward by the duration. 74 | // This should only be called from a single goroutine at a time. 75 | func (m *Mock) Add(d time.Duration) { 76 | // Calculate the final current time. 77 | t := m.now.Add(d) 78 | 79 | // Continue to execute timers until there are no more before the new time. 80 | for { 81 | if !m.runNextTimer(t) { 82 | break 83 | } 84 | } 85 | 86 | // Ensure that we end with the new time. 87 | m.mu.Lock() 88 | m.now = t 89 | m.mu.Unlock() 90 | 91 | // Give a small buffer to make sure the other goroutines get handled. 92 | gosched() 93 | } 94 | 95 | // runNextTimer executes the next timer in chronological order and moves the 96 | // current time to the timer's next tick time. The next time is not executed if 97 | // it's next time if after the max time. Returns true if a timer is executed. 98 | func (m *Mock) runNextTimer(max time.Time) bool { 99 | m.mu.Lock() 100 | 101 | // Sort timers by time. 102 | sort.Sort(m.timers) 103 | 104 | // If we have no more timers then exit. 105 | if len(m.timers) == 0 { 106 | m.mu.Unlock() 107 | return false 108 | } 109 | 110 | // Retrieve next timer. Exit if next tick is after new time. 111 | t := m.timers[0] 112 | if t.Next().After(max) { 113 | m.mu.Unlock() 114 | return false 115 | } 116 | 117 | // Move "now" forward and unlock clock. 118 | m.now = t.Next() 119 | m.mu.Unlock() 120 | 121 | // Execute timer. 122 | t.Tick(m.now) 123 | return true 124 | } 125 | 126 | // After waits for the duration to elapse and then sends the current time on the returned channel. 127 | func (m *Mock) After(d time.Duration) <-chan time.Time { 128 | defer m.inc(&m.calls.After) 129 | return m.Timer(d).C 130 | } 131 | 132 | // AfterFunc waits for the duration to elapse and then executes a function. 133 | // A Timer is returned that can be stopped. 134 | func (m *Mock) AfterFunc(d time.Duration, f func()) *Timer { 135 | defer m.inc(&m.calls.AfterFunc) 136 | t := m.Timer(d) 137 | t.C = nil 138 | t.fn = f 139 | return t 140 | } 141 | 142 | // Now returns the current wall time on the mock clock. 143 | func (m *Mock) Now() time.Time { 144 | defer m.inc(&m.calls.Now) 145 | m.mu.Lock() 146 | defer m.mu.Unlock() 147 | return m.now 148 | } 149 | 150 | // Sleep pauses the goroutine for the given duration on the mock clock. 151 | // The clock must be moved forward in a separate goroutine. 152 | func (m *Mock) Sleep(d time.Duration) { 153 | defer m.inc(&m.calls.Sleep) 154 | <-m.After(d) 155 | } 156 | 157 | // Tick is a convenience function for Ticker(). 158 | // It will return a ticker channel that cannot be stopped. 159 | func (m *Mock) Tick(d time.Duration) <-chan time.Time { 160 | defer m.inc(&m.calls.Tick) 161 | return m.Ticker(d).C 162 | } 163 | 164 | // Ticker creates a new instance of Ticker. 165 | func (m *Mock) Ticker(d time.Duration) *Ticker { 166 | defer m.inc(&m.calls.Ticker) 167 | m.mu.Lock() 168 | defer m.mu.Unlock() 169 | ch := make(chan time.Time) 170 | t := &Ticker{ 171 | C: ch, 172 | c: ch, 173 | mock: m, 174 | d: d, 175 | next: m.now.Add(d), 176 | } 177 | m.timers = append(m.timers, (*internalTicker)(t)) 178 | return t 179 | } 180 | 181 | // Timer creates a new instance of Timer. 182 | func (m *Mock) Timer(d time.Duration) *Timer { 183 | defer m.inc(&m.calls.Timer) 184 | m.mu.Lock() 185 | defer m.mu.Unlock() 186 | ch := make(chan time.Time) 187 | t := &Timer{ 188 | C: ch, 189 | c: ch, 190 | mock: m, 191 | next: m.now.Add(d), 192 | } 193 | m.timers = append(m.timers, (*internalTimer)(t)) 194 | return t 195 | } 196 | 197 | func (m *Mock) removeClockTimer(t clockTimer) { 198 | m.mu.Lock() 199 | defer m.mu.Unlock() 200 | for i, timer := range m.timers { 201 | if timer == t { 202 | copy(m.timers[i:], m.timers[i+1:]) 203 | m.timers[len(m.timers)-1] = nil 204 | m.timers = m.timers[:len(m.timers)-1] 205 | break 206 | } 207 | } 208 | sort.Sort(m.timers) 209 | } 210 | 211 | func (m *Mock) inc(addr *uint32) { 212 | m.callsMutex.Lock() 213 | defer m.callsMutex.Unlock() 214 | *addr++ 215 | var newWaiting []waiting 216 | for _, w := range m.waiting { 217 | if m.calls.atLeast(w.expected) { 218 | close(w.done) 219 | continue 220 | } 221 | newWaiting = append(newWaiting, w) 222 | } 223 | m.waiting = newWaiting 224 | } 225 | 226 | // Wait waits for at least the relevant calls before returning. The expected 227 | // Calls are always over the lifetime of the Mock. Values in the Calls struct 228 | // are used as the minimum number of calls, this allows you to wait for only 229 | // the calls you care about. 230 | func (m *Mock) Wait(s Calls) { 231 | m.callsMutex.Lock() 232 | if m.calls.atLeast(s) { 233 | m.callsMutex.Unlock() 234 | return 235 | } 236 | done := make(chan struct{}) 237 | m.waiting = append(m.waiting, waiting{expected: s, done: done}) 238 | m.callsMutex.Unlock() 239 | <-done 240 | } 241 | 242 | // clockTimer represents an object with an associated start time. 243 | type clockTimer interface { 244 | Next() time.Time 245 | Tick(time.Time) 246 | } 247 | 248 | // clockTimers represents a list of sortable timers. 249 | type clockTimers []clockTimer 250 | 251 | func (a clockTimers) Len() int { return len(a) } 252 | func (a clockTimers) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 253 | func (a clockTimers) Less(i, j int) bool { return a[i].Next().Before(a[j].Next()) } 254 | 255 | // Timer represents a single event. 256 | // The current time will be sent on C, unless the timer was created by AfterFunc. 257 | type Timer struct { 258 | C <-chan time.Time 259 | c chan time.Time 260 | timer *time.Timer // realtime impl, if set 261 | next time.Time // next tick time 262 | mock *Mock // mock clock, if set 263 | fn func() // AfterFunc function, if set 264 | } 265 | 266 | // Stop turns off the ticker. 267 | func (t *Timer) Stop() { 268 | if t.timer != nil { 269 | t.timer.Stop() 270 | } else { 271 | t.mock.removeClockTimer((*internalTimer)(t)) 272 | } 273 | } 274 | 275 | type internalTimer Timer 276 | 277 | func (t *internalTimer) Next() time.Time { return t.next } 278 | func (t *internalTimer) Tick(now time.Time) { 279 | if t.fn != nil { 280 | t.fn() 281 | } else { 282 | t.c <- now 283 | } 284 | t.mock.removeClockTimer((*internalTimer)(t)) 285 | gosched() 286 | } 287 | 288 | // Ticker holds a channel that receives "ticks" at regular intervals. 289 | type Ticker struct { 290 | C <-chan time.Time 291 | c chan time.Time 292 | ticker *time.Ticker // realtime impl, if set 293 | next time.Time // next tick time 294 | mock *Mock // mock clock, if set 295 | d time.Duration // time between ticks 296 | } 297 | 298 | // Stop turns off the ticker. 299 | func (t *Ticker) Stop() { 300 | if t.ticker != nil { 301 | t.ticker.Stop() 302 | } else { 303 | t.mock.removeClockTimer((*internalTicker)(t)) 304 | } 305 | } 306 | 307 | type internalTicker Ticker 308 | 309 | func (t *internalTicker) Next() time.Time { return t.next } 310 | func (t *internalTicker) Tick(now time.Time) { 311 | select { 312 | case t.c <- now: 313 | case <-time.After(1 * time.Millisecond): 314 | } 315 | t.next = now.Add(t.d) 316 | gosched() 317 | } 318 | 319 | // Sleep momentarily so that other goroutines can process. 320 | func gosched() { runtime.Gosched() } 321 | 322 | // Calls keeps track of the count of calls for each of the methods on the Clock 323 | // interface. 324 | type Calls struct { 325 | After uint32 326 | AfterFunc uint32 327 | Now uint32 328 | Sleep uint32 329 | Tick uint32 330 | Ticker uint32 331 | Timer uint32 332 | } 333 | 334 | // atLeast returns true if at least the number of calls in o have been made. 335 | func (c Calls) atLeast(o Calls) bool { 336 | if c.After < o.After { 337 | return false 338 | } 339 | if c.AfterFunc < o.AfterFunc { 340 | return false 341 | } 342 | if c.Now < o.Now { 343 | return false 344 | } 345 | if c.Sleep < o.Sleep { 346 | return false 347 | } 348 | if c.Tick < o.Tick { 349 | return false 350 | } 351 | if c.Ticker < o.Ticker { 352 | return false 353 | } 354 | if c.Timer < o.Timer { 355 | return false 356 | } 357 | return true 358 | } 359 | 360 | type waiting struct { 361 | expected Calls 362 | done chan struct{} 363 | } 364 | -------------------------------------------------------------------------------- /clock_test.go: -------------------------------------------------------------------------------- 1 | package clock_test 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "runtime" 7 | "sync" 8 | "sync/atomic" 9 | "testing" 10 | "time" 11 | 12 | "github.com/facebookgo/clock" 13 | ) 14 | 15 | // Ensure that the clock's After channel sends at the correct time. 16 | func TestClock_After(t *testing.T) { 17 | var ok bool 18 | go func() { 19 | time.Sleep(10 * time.Millisecond) 20 | ok = true 21 | }() 22 | go func() { 23 | time.Sleep(30 * time.Millisecond) 24 | t.Fatal("too late") 25 | }() 26 | gosched() 27 | 28 | <-clock.New().After(20 * time.Millisecond) 29 | if !ok { 30 | t.Fatal("too early") 31 | } 32 | } 33 | 34 | // Ensure that the clock's AfterFunc executes at the correct time. 35 | func TestClock_AfterFunc(t *testing.T) { 36 | var ok bool 37 | go func() { 38 | time.Sleep(10 * time.Millisecond) 39 | ok = true 40 | }() 41 | go func() { 42 | time.Sleep(30 * time.Millisecond) 43 | t.Fatal("too late") 44 | }() 45 | gosched() 46 | 47 | var wg sync.WaitGroup 48 | wg.Add(1) 49 | clock.New().AfterFunc(20*time.Millisecond, func() { 50 | wg.Done() 51 | }) 52 | wg.Wait() 53 | if !ok { 54 | t.Fatal("too early") 55 | } 56 | } 57 | 58 | // Ensure that the clock's time matches the standary library. 59 | func TestClock_Now(t *testing.T) { 60 | a := time.Now().Round(time.Second) 61 | b := clock.New().Now().Round(time.Second) 62 | if !a.Equal(b) { 63 | t.Errorf("not equal: %s != %s", a, b) 64 | } 65 | } 66 | 67 | // Ensure that the clock sleeps for the appropriate amount of time. 68 | func TestClock_Sleep(t *testing.T) { 69 | var ok bool 70 | go func() { 71 | time.Sleep(10 * time.Millisecond) 72 | ok = true 73 | }() 74 | go func() { 75 | time.Sleep(30 * time.Millisecond) 76 | t.Fatal("too late") 77 | }() 78 | gosched() 79 | 80 | clock.New().Sleep(20 * time.Millisecond) 81 | if !ok { 82 | t.Fatal("too early") 83 | } 84 | } 85 | 86 | // Ensure that the clock ticks correctly. 87 | func TestClock_Tick(t *testing.T) { 88 | var ok bool 89 | go func() { 90 | time.Sleep(10 * time.Millisecond) 91 | ok = true 92 | }() 93 | go func() { 94 | time.Sleep(50 * time.Millisecond) 95 | t.Fatal("too late") 96 | }() 97 | gosched() 98 | 99 | c := clock.New().Tick(20 * time.Millisecond) 100 | <-c 101 | <-c 102 | if !ok { 103 | t.Fatal("too early") 104 | } 105 | } 106 | 107 | // Ensure that the clock's ticker ticks correctly. 108 | func TestClock_Ticker(t *testing.T) { 109 | var ok bool 110 | go func() { 111 | time.Sleep(100 * time.Millisecond) 112 | ok = true 113 | }() 114 | go func() { 115 | time.Sleep(200 * time.Millisecond) 116 | t.Fatal("too late") 117 | }() 118 | gosched() 119 | 120 | ticker := clock.New().Ticker(50 * time.Millisecond) 121 | <-ticker.C 122 | <-ticker.C 123 | if !ok { 124 | t.Fatal("too early") 125 | } 126 | } 127 | 128 | // Ensure that the clock's ticker can stop correctly. 129 | func TestClock_Ticker_Stp(t *testing.T) { 130 | var ok bool 131 | go func() { 132 | time.Sleep(10 * time.Millisecond) 133 | ok = true 134 | }() 135 | gosched() 136 | 137 | ticker := clock.New().Ticker(20 * time.Millisecond) 138 | <-ticker.C 139 | ticker.Stop() 140 | select { 141 | case <-ticker.C: 142 | t.Fatal("unexpected send") 143 | case <-time.After(30 * time.Millisecond): 144 | } 145 | } 146 | 147 | // Ensure that the clock's timer waits correctly. 148 | func TestClock_Timer(t *testing.T) { 149 | var ok bool 150 | go func() { 151 | time.Sleep(10 * time.Millisecond) 152 | ok = true 153 | }() 154 | go func() { 155 | time.Sleep(30 * time.Millisecond) 156 | t.Fatal("too late") 157 | }() 158 | gosched() 159 | 160 | timer := clock.New().Timer(20 * time.Millisecond) 161 | <-timer.C 162 | if !ok { 163 | t.Fatal("too early") 164 | } 165 | } 166 | 167 | // Ensure that the clock's timer can be stopped. 168 | func TestClock_Timer_Stop(t *testing.T) { 169 | var ok bool 170 | go func() { 171 | time.Sleep(10 * time.Millisecond) 172 | ok = true 173 | }() 174 | 175 | timer := clock.New().Timer(20 * time.Millisecond) 176 | timer.Stop() 177 | select { 178 | case <-timer.C: 179 | t.Fatal("unexpected send") 180 | case <-time.After(30 * time.Millisecond): 181 | } 182 | } 183 | 184 | // Ensure that the mock's After channel sends at the correct time. 185 | func TestMock_After(t *testing.T) { 186 | var ok int32 187 | clock := clock.NewMock() 188 | 189 | // Create a channel to execute after 10 mock seconds. 190 | ch := clock.After(10 * time.Second) 191 | go func(ch <-chan time.Time) { 192 | <-ch 193 | atomic.StoreInt32(&ok, 1) 194 | }(ch) 195 | 196 | // Move clock forward to just before the time. 197 | clock.Add(9 * time.Second) 198 | if atomic.LoadInt32(&ok) == 1 { 199 | t.Fatal("too early") 200 | } 201 | 202 | // Move clock forward to the after channel's time. 203 | clock.Add(1 * time.Second) 204 | if atomic.LoadInt32(&ok) == 0 { 205 | t.Fatal("too late") 206 | } 207 | } 208 | 209 | // Ensure that the mock's AfterFunc executes at the correct time. 210 | func TestMock_AfterFunc(t *testing.T) { 211 | var ok int32 212 | clock := clock.NewMock() 213 | 214 | // Execute function after duration. 215 | clock.AfterFunc(10*time.Second, func() { 216 | atomic.StoreInt32(&ok, 1) 217 | }) 218 | 219 | // Move clock forward to just before the time. 220 | clock.Add(9 * time.Second) 221 | if atomic.LoadInt32(&ok) == 1 { 222 | t.Fatal("too early") 223 | } 224 | 225 | // Move clock forward to the after channel's time. 226 | clock.Add(1 * time.Second) 227 | if atomic.LoadInt32(&ok) == 0 { 228 | t.Fatal("too late") 229 | } 230 | } 231 | 232 | // Ensure that the mock's AfterFunc doesn't execute if stopped. 233 | func TestMock_AfterFunc_Stop(t *testing.T) { 234 | // Execute function after duration. 235 | clock := clock.NewMock() 236 | timer := clock.AfterFunc(10*time.Second, func() { 237 | t.Fatal("unexpected function execution") 238 | }) 239 | gosched() 240 | 241 | // Stop timer & move clock forward. 242 | timer.Stop() 243 | clock.Add(10 * time.Second) 244 | gosched() 245 | } 246 | 247 | // Ensure that the mock's current time can be changed. 248 | func TestMock_Now(t *testing.T) { 249 | clock := clock.NewMock() 250 | if now := clock.Now(); !now.Equal(time.Unix(0, 0)) { 251 | t.Fatalf("expected epoch, got: ", now) 252 | } 253 | 254 | // Add 10 seconds and check the time. 255 | clock.Add(10 * time.Second) 256 | if now := clock.Now(); !now.Equal(time.Unix(10, 0)) { 257 | t.Fatalf("expected epoch, got: ", now) 258 | } 259 | } 260 | 261 | // Ensure that the mock can sleep for the correct time. 262 | func TestMock_Sleep(t *testing.T) { 263 | var ok int32 264 | clock := clock.NewMock() 265 | 266 | // Create a channel to execute after 10 mock seconds. 267 | go func() { 268 | clock.Sleep(10 * time.Second) 269 | atomic.StoreInt32(&ok, 1) 270 | }() 271 | gosched() 272 | 273 | // Move clock forward to just before the sleep duration. 274 | clock.Add(9 * time.Second) 275 | if atomic.LoadInt32(&ok) == 1 { 276 | t.Fatal("too early") 277 | } 278 | 279 | // Move clock forward to the after the sleep duration. 280 | clock.Add(1 * time.Second) 281 | if atomic.LoadInt32(&ok) == 0 { 282 | t.Fatal("too late") 283 | } 284 | } 285 | 286 | // Ensure that the mock's Tick channel sends at the correct time. 287 | func TestMock_Tick(t *testing.T) { 288 | var n int32 289 | clock := clock.NewMock() 290 | 291 | // Create a channel to increment every 10 seconds. 292 | go func() { 293 | tick := clock.Tick(10 * time.Second) 294 | for { 295 | <-tick 296 | atomic.AddInt32(&n, 1) 297 | } 298 | }() 299 | gosched() 300 | 301 | // Move clock forward to just before the first tick. 302 | clock.Add(9 * time.Second) 303 | if atomic.LoadInt32(&n) != 0 { 304 | t.Fatalf("expected 0, got %d", n) 305 | } 306 | 307 | // Move clock forward to the start of the first tick. 308 | clock.Add(1 * time.Second) 309 | if atomic.LoadInt32(&n) != 1 { 310 | t.Fatalf("expected 1, got %d", n) 311 | } 312 | 313 | // Move clock forward over several ticks. 314 | clock.Add(30 * time.Second) 315 | if atomic.LoadInt32(&n) != 4 { 316 | t.Fatalf("expected 4, got %d", n) 317 | } 318 | } 319 | 320 | // Ensure that the mock's Ticker channel sends at the correct time. 321 | func TestMock_Ticker(t *testing.T) { 322 | var n int32 323 | clock := clock.NewMock() 324 | 325 | // Create a channel to increment every microsecond. 326 | go func() { 327 | ticker := clock.Ticker(1 * time.Microsecond) 328 | for { 329 | <-ticker.C 330 | atomic.AddInt32(&n, 1) 331 | } 332 | }() 333 | gosched() 334 | 335 | // Move clock forward. 336 | clock.Add(10 * time.Microsecond) 337 | if atomic.LoadInt32(&n) != 10 { 338 | t.Fatalf("unexpected: %d", n) 339 | } 340 | } 341 | 342 | // Ensure that the mock's Ticker channel won't block if not read from. 343 | func TestMock_Ticker_Overflow(t *testing.T) { 344 | clock := clock.NewMock() 345 | ticker := clock.Ticker(1 * time.Microsecond) 346 | clock.Add(10 * time.Microsecond) 347 | ticker.Stop() 348 | } 349 | 350 | // Ensure that the mock's Ticker can be stopped. 351 | func TestMock_Ticker_Stop(t *testing.T) { 352 | var n int32 353 | clock := clock.NewMock() 354 | 355 | // Create a channel to increment every second. 356 | ticker := clock.Ticker(1 * time.Second) 357 | go func() { 358 | for { 359 | <-ticker.C 360 | atomic.AddInt32(&n, 1) 361 | } 362 | }() 363 | gosched() 364 | 365 | // Move clock forward. 366 | clock.Add(5 * time.Second) 367 | if atomic.LoadInt32(&n) != 5 { 368 | t.Fatalf("expected 5, got: %d", n) 369 | } 370 | 371 | ticker.Stop() 372 | 373 | // Move clock forward again. 374 | clock.Add(5 * time.Second) 375 | if atomic.LoadInt32(&n) != 5 { 376 | t.Fatalf("still expected 5, got: %d", n) 377 | } 378 | } 379 | 380 | // Ensure that multiple tickers can be used together. 381 | func TestMock_Ticker_Multi(t *testing.T) { 382 | var n int32 383 | clock := clock.NewMock() 384 | 385 | go func() { 386 | a := clock.Ticker(1 * time.Microsecond) 387 | b := clock.Ticker(3 * time.Microsecond) 388 | 389 | for { 390 | select { 391 | case <-a.C: 392 | atomic.AddInt32(&n, 1) 393 | case <-b.C: 394 | atomic.AddInt32(&n, 100) 395 | } 396 | } 397 | }() 398 | gosched() 399 | 400 | // Move clock forward. 401 | clock.Add(10 * time.Microsecond) 402 | gosched() 403 | if atomic.LoadInt32(&n) != 310 { 404 | t.Fatalf("unexpected: %d", n) 405 | } 406 | } 407 | 408 | func ExampleMock_After() { 409 | // Create a new mock clock. 410 | clock := clock.NewMock() 411 | count := 0 412 | 413 | // Create a channel to execute after 10 mock seconds. 414 | go func() { 415 | <-clock.After(10 * time.Second) 416 | count = 100 417 | }() 418 | runtime.Gosched() 419 | 420 | // Print the starting value. 421 | fmt.Printf("%s: %d\n", clock.Now().UTC(), count) 422 | 423 | // Move the clock forward 5 seconds and print the value again. 424 | clock.Add(5 * time.Second) 425 | fmt.Printf("%s: %d\n", clock.Now().UTC(), count) 426 | 427 | // Move the clock forward 5 seconds to the tick time and check the value. 428 | clock.Add(5 * time.Second) 429 | fmt.Printf("%s: %d\n", clock.Now().UTC(), count) 430 | 431 | // Output: 432 | // 1970-01-01 00:00:00 +0000 UTC: 0 433 | // 1970-01-01 00:00:05 +0000 UTC: 0 434 | // 1970-01-01 00:00:10 +0000 UTC: 100 435 | } 436 | 437 | func ExampleMock_AfterFunc() { 438 | // Create a new mock clock. 439 | clock := clock.NewMock() 440 | count := 0 441 | 442 | // Execute a function after 10 mock seconds. 443 | clock.AfterFunc(10*time.Second, func() { 444 | count = 100 445 | }) 446 | runtime.Gosched() 447 | 448 | // Print the starting value. 449 | fmt.Printf("%s: %d\n", clock.Now().UTC(), count) 450 | 451 | // Move the clock forward 10 seconds and print the new value. 452 | clock.Add(10 * time.Second) 453 | fmt.Printf("%s: %d\n", clock.Now().UTC(), count) 454 | 455 | // Output: 456 | // 1970-01-01 00:00:00 +0000 UTC: 0 457 | // 1970-01-01 00:00:10 +0000 UTC: 100 458 | } 459 | 460 | func ExampleMock_Sleep() { 461 | // Create a new mock clock. 462 | clock := clock.NewMock() 463 | count := 0 464 | 465 | // Execute a function after 10 mock seconds. 466 | go func() { 467 | clock.Sleep(10 * time.Second) 468 | count = 100 469 | }() 470 | runtime.Gosched() 471 | 472 | // Print the starting value. 473 | fmt.Printf("%s: %d\n", clock.Now().UTC(), count) 474 | 475 | // Move the clock forward 10 seconds and print the new value. 476 | clock.Add(10 * time.Second) 477 | fmt.Printf("%s: %d\n", clock.Now().UTC(), count) 478 | 479 | // Output: 480 | // 1970-01-01 00:00:00 +0000 UTC: 0 481 | // 1970-01-01 00:00:10 +0000 UTC: 100 482 | } 483 | 484 | func ExampleMock_Ticker() { 485 | // Create a new mock clock. 486 | clock := clock.NewMock() 487 | count := 0 488 | 489 | // Increment count every mock second. 490 | go func() { 491 | ticker := clock.Ticker(1 * time.Second) 492 | for { 493 | <-ticker.C 494 | count++ 495 | } 496 | }() 497 | runtime.Gosched() 498 | 499 | // Move the clock forward 10 seconds and print the new value. 500 | clock.Add(10 * time.Second) 501 | fmt.Printf("Count is %d after 10 seconds\n", count) 502 | 503 | // Move the clock forward 5 more seconds and print the new value. 504 | clock.Add(5 * time.Second) 505 | fmt.Printf("Count is %d after 15 seconds\n", count) 506 | 507 | // Output: 508 | // Count is 10 after 10 seconds 509 | // Count is 15 after 15 seconds 510 | } 511 | 512 | func ExampleMock_Timer() { 513 | // Create a new mock clock. 514 | clock := clock.NewMock() 515 | count := 0 516 | 517 | // Increment count after a mock second. 518 | go func() { 519 | timer := clock.Timer(1 * time.Second) 520 | <-timer.C 521 | count++ 522 | }() 523 | runtime.Gosched() 524 | 525 | // Move the clock forward 10 seconds and print the new value. 526 | clock.Add(10 * time.Second) 527 | fmt.Printf("Count is %d after 10 seconds\n", count) 528 | 529 | // Output: 530 | // Count is 1 after 10 seconds 531 | } 532 | 533 | func warn(v ...interface{}) { fmt.Fprintln(os.Stderr, v...) } 534 | func warnf(msg string, v ...interface{}) { fmt.Fprintf(os.Stderr, msg+"\n", v...) } 535 | 536 | func gosched() { time.Sleep(1 * time.Millisecond) } 537 | --------------------------------------------------------------------------------