github.com/mailgun/holster/v4@v4.20.0/clock/clock.go (about) 1 // Package clock provides the same functions as the system package time. In 2 // production it forwards all calls to the system time package, but in tests 3 // the time can be frozen by calling Freeze function and from that point it has 4 // to be advanced manually with Advance function making all scheduled calls 5 // deterministic. 6 // 7 // The functions provided by the package have the same parameters and return 8 // values as their system counterparts with a few exceptions. Where either 9 // *time.Timer or *time.Ticker is returned by a system function, the clock 10 // package counterpart returns clock.Timer or clock.Ticker interface 11 // respectively. The interfaces provide API as respective structs except C is 12 // not a channel, but a function that returns <-chan time.Time. 13 package clock 14 15 import ( 16 "time" 17 ) 18 19 var ( 20 realtime = &systemTime{} 21 ) 22 23 // Freeze after this function is called all time related functions start 24 // generate deterministic timers that are triggered by Advance function. It is 25 // supposed to be used in tests only. Returns an Unfreezer so it can be a 26 // one-liner in tests: defer clock.Freeze(clock.Now()).Unfreeze() 27 func Freeze(now time.Time) Unfreezer { 28 setProvider(&frozenTime{frozenAt: now, now: now}) 29 return Unfreezer{} 30 } 31 32 type Unfreezer struct{} 33 34 func (u Unfreezer) Unfreeze() { 35 Unfreeze() 36 } 37 38 // Unfreeze reverses effect of Freeze. 39 func Unfreeze() { 40 setProvider(realtime) 41 } 42 43 // Realtime returns a clock provider wrapping the SDK's time package. It is 44 // supposed to be used in tests when time is frozen to schedule test timeouts. 45 func Realtime() Clock { 46 return realtime 47 } 48 49 // Advance makes the deterministic time move forward by the specified duration, 50 // firing timers along the way in the natural order. It returns how much time 51 // has passed since it was frozen. So you can assert on the return value in 52 // tests to make it explicit where you stand on the deterministic timescale. 53 func Advance(d time.Duration) time.Duration { 54 ft, ok := getProvider().(*frozenTime) 55 if !ok { 56 panic("Freeze time first!") 57 } 58 ft.advance(d) 59 return Now().Sub(ft.frozenAt) 60 } 61 62 // Wait4Scheduled blocks until either there are n or more scheduled events, or 63 // the timeout elapses. It returns true if the wait condition has been met 64 // before the timeout expired, false otherwise. 65 func Wait4Scheduled(count int, timeout time.Duration) bool { 66 return getProvider().Wait4Scheduled(count, timeout) 67 } 68 69 // Now see time.Now. 70 func Now() time.Time { 71 return getProvider().Now() 72 } 73 74 // Sleep see time.Sleep. 75 func Sleep(d time.Duration) { 76 getProvider().Sleep(d) 77 } 78 79 // After see time.After. 80 func After(d time.Duration) <-chan time.Time { 81 return getProvider().After(d) 82 } 83 84 // NewTimer see time.NewTimer. 85 func NewTimer(d time.Duration) Timer { 86 return getProvider().NewTimer(d) 87 } 88 89 // AfterFunc see time.AfterFunc. 90 func AfterFunc(d time.Duration, f func()) Timer { 91 return getProvider().AfterFunc(d, f) 92 } 93 94 // NewTicker see time.Ticker. 95 func NewTicker(d time.Duration) Ticker { 96 return getProvider().NewTicker(d) 97 } 98 99 // Tick see time.Tick. 100 func Tick(d time.Duration) <-chan time.Time { 101 return getProvider().Tick(d) 102 }