clock.go 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. package clock
  2. import (
  3. "sort"
  4. "sync"
  5. "time"
  6. )
  7. // Clock represents an interface to the functions in the standard library time
  8. // package. Two implementations are available in the clock package. The first
  9. // is a real-time clock which simply wraps the time package's functions. The
  10. // second is a mock clock which will only make forward progress when
  11. // programmatically adjusted.
  12. type Clock interface {
  13. After(d time.Duration) <-chan time.Time
  14. AfterFunc(d time.Duration, f func()) *Timer
  15. Now() time.Time
  16. Since(t time.Time) time.Duration
  17. Sleep(d time.Duration)
  18. Tick(d time.Duration) <-chan time.Time
  19. Ticker(d time.Duration) *Ticker
  20. Timer(d time.Duration) *Timer
  21. }
  22. // New returns an instance of a real-time clock.
  23. func New() Clock {
  24. return &clock{}
  25. }
  26. // clock implements a real-time clock by simply wrapping the time package functions.
  27. type clock struct{}
  28. func (c *clock) After(d time.Duration) <-chan time.Time { return time.After(d) }
  29. func (c *clock) AfterFunc(d time.Duration, f func()) *Timer {
  30. return &Timer{timer: time.AfterFunc(d, f)}
  31. }
  32. func (c *clock) Now() time.Time { return time.Now() }
  33. func (c *clock) Since(t time.Time) time.Duration { return time.Since(t) }
  34. func (c *clock) Sleep(d time.Duration) { time.Sleep(d) }
  35. func (c *clock) Tick(d time.Duration) <-chan time.Time { return time.Tick(d) }
  36. func (c *clock) Ticker(d time.Duration) *Ticker {
  37. t := time.NewTicker(d)
  38. return &Ticker{C: t.C, ticker: t}
  39. }
  40. func (c *clock) Timer(d time.Duration) *Timer {
  41. t := time.NewTimer(d)
  42. return &Timer{C: t.C, timer: t}
  43. }
  44. // Mock represents a mock clock that only moves forward programmically.
  45. // It can be preferable to a real-time clock when testing time-based functionality.
  46. type Mock struct {
  47. mu sync.Mutex
  48. now time.Time // current time
  49. timers clockTimers // tickers & timers
  50. }
  51. // NewMock returns an instance of a mock clock.
  52. // The current time of the mock clock on initialization is the Unix epoch.
  53. func NewMock() *Mock {
  54. return &Mock{now: time.Unix(0, 0)}
  55. }
  56. // Add moves the current time of the mock clock forward by the duration.
  57. // This should only be called from a single goroutine at a time.
  58. func (m *Mock) Add(d time.Duration) {
  59. // Calculate the final current time.
  60. t := m.now.Add(d)
  61. // Continue to execute timers until there are no more before the new time.
  62. for {
  63. if !m.runNextTimer(t) {
  64. break
  65. }
  66. }
  67. // Ensure that we end with the new time.
  68. m.mu.Lock()
  69. m.now = t
  70. m.mu.Unlock()
  71. // Give a small buffer to make sure the other goroutines get handled.
  72. gosched()
  73. }
  74. // Set sets the current time of the mock clock to a specific one.
  75. // This should only be called from a single goroutine at a time.
  76. func (m *Mock) Set(t time.Time) {
  77. // Continue to execute timers until there are no more before the new time.
  78. for {
  79. if !m.runNextTimer(t) {
  80. break
  81. }
  82. }
  83. // Ensure that we end with the new time.
  84. m.mu.Lock()
  85. m.now = t
  86. m.mu.Unlock()
  87. // Give a small buffer to make sure the other goroutines get handled.
  88. gosched()
  89. }
  90. // runNextTimer executes the next timer in chronological order and moves the
  91. // current time to the timer's next tick time. The next time is not executed if
  92. // it's next time if after the max time. Returns true if a timer is executed.
  93. func (m *Mock) runNextTimer(max time.Time) bool {
  94. m.mu.Lock()
  95. // Sort timers by time.
  96. sort.Sort(m.timers)
  97. // If we have no more timers then exit.
  98. if len(m.timers) == 0 {
  99. m.mu.Unlock()
  100. return false
  101. }
  102. // Retrieve next timer. Exit if next tick is after new time.
  103. t := m.timers[0]
  104. if t.Next().After(max) {
  105. m.mu.Unlock()
  106. return false
  107. }
  108. // Move "now" forward and unlock clock.
  109. m.now = t.Next()
  110. m.mu.Unlock()
  111. // Execute timer.
  112. t.Tick(m.now)
  113. return true
  114. }
  115. // After waits for the duration to elapse and then sends the current time on the returned channel.
  116. func (m *Mock) After(d time.Duration) <-chan time.Time {
  117. return m.Timer(d).C
  118. }
  119. // AfterFunc waits for the duration to elapse and then executes a function.
  120. // A Timer is returned that can be stopped.
  121. func (m *Mock) AfterFunc(d time.Duration, f func()) *Timer {
  122. t := m.Timer(d)
  123. t.C = nil
  124. t.fn = f
  125. return t
  126. }
  127. // Now returns the current wall time on the mock clock.
  128. func (m *Mock) Now() time.Time {
  129. m.mu.Lock()
  130. defer m.mu.Unlock()
  131. return m.now
  132. }
  133. // Since returns time since the mock clocks wall time.
  134. func (m *Mock) Since(t time.Time) time.Duration {
  135. return m.Now().Sub(t)
  136. }
  137. // Sleep pauses the goroutine for the given duration on the mock clock.
  138. // The clock must be moved forward in a separate goroutine.
  139. func (m *Mock) Sleep(d time.Duration) {
  140. <-m.After(d)
  141. }
  142. // Tick is a convenience function for Ticker().
  143. // It will return a ticker channel that cannot be stopped.
  144. func (m *Mock) Tick(d time.Duration) <-chan time.Time {
  145. return m.Ticker(d).C
  146. }
  147. // Ticker creates a new instance of Ticker.
  148. func (m *Mock) Ticker(d time.Duration) *Ticker {
  149. m.mu.Lock()
  150. defer m.mu.Unlock()
  151. ch := make(chan time.Time, 1)
  152. t := &Ticker{
  153. C: ch,
  154. c: ch,
  155. mock: m,
  156. d: d,
  157. next: m.now.Add(d),
  158. }
  159. m.timers = append(m.timers, (*internalTicker)(t))
  160. return t
  161. }
  162. // Timer creates a new instance of Timer.
  163. func (m *Mock) Timer(d time.Duration) *Timer {
  164. m.mu.Lock()
  165. defer m.mu.Unlock()
  166. ch := make(chan time.Time, 1)
  167. t := &Timer{
  168. C: ch,
  169. c: ch,
  170. mock: m,
  171. next: m.now.Add(d),
  172. stopped: false,
  173. }
  174. m.timers = append(m.timers, (*internalTimer)(t))
  175. return t
  176. }
  177. func (m *Mock) removeClockTimer(t clockTimer) {
  178. m.mu.Lock()
  179. defer m.mu.Unlock()
  180. for i, timer := range m.timers {
  181. if timer == t {
  182. copy(m.timers[i:], m.timers[i+1:])
  183. m.timers[len(m.timers)-1] = nil
  184. m.timers = m.timers[:len(m.timers)-1]
  185. break
  186. }
  187. }
  188. sort.Sort(m.timers)
  189. }
  190. // clockTimer represents an object with an associated start time.
  191. type clockTimer interface {
  192. Next() time.Time
  193. Tick(time.Time)
  194. }
  195. // clockTimers represents a list of sortable timers.
  196. type clockTimers []clockTimer
  197. func (a clockTimers) Len() int { return len(a) }
  198. func (a clockTimers) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
  199. func (a clockTimers) Less(i, j int) bool { return a[i].Next().Before(a[j].Next()) }
  200. // Timer represents a single event.
  201. // The current time will be sent on C, unless the timer was created by AfterFunc.
  202. type Timer struct {
  203. C <-chan time.Time
  204. c chan time.Time
  205. timer *time.Timer // realtime impl, if set
  206. next time.Time // next tick time
  207. mock *Mock // mock clock, if set
  208. fn func() // AfterFunc function, if set
  209. stopped bool // True if stopped, false if running
  210. }
  211. // Stop turns off the ticker.
  212. func (t *Timer) Stop() bool {
  213. if t.timer != nil {
  214. return t.timer.Stop()
  215. }
  216. registered := !t.stopped
  217. t.mock.removeClockTimer((*internalTimer)(t))
  218. t.stopped = true
  219. return registered
  220. }
  221. // Reset changes the expiry time of the timer
  222. func (t *Timer) Reset(d time.Duration) bool {
  223. if t.timer != nil {
  224. return t.timer.Reset(d)
  225. }
  226. t.next = t.mock.now.Add(d)
  227. registered := !t.stopped
  228. if t.stopped {
  229. t.mock.mu.Lock()
  230. t.mock.timers = append(t.mock.timers, (*internalTimer)(t))
  231. t.mock.mu.Unlock()
  232. }
  233. t.stopped = false
  234. return registered
  235. }
  236. type internalTimer Timer
  237. func (t *internalTimer) Next() time.Time { return t.next }
  238. func (t *internalTimer) Tick(now time.Time) {
  239. if t.fn != nil {
  240. t.fn()
  241. } else {
  242. t.c <- now
  243. }
  244. t.mock.removeClockTimer((*internalTimer)(t))
  245. t.stopped = true
  246. gosched()
  247. }
  248. // Ticker holds a channel that receives "ticks" at regular intervals.
  249. type Ticker struct {
  250. C <-chan time.Time
  251. c chan time.Time
  252. ticker *time.Ticker // realtime impl, if set
  253. next time.Time // next tick time
  254. mock *Mock // mock clock, if set
  255. d time.Duration // time between ticks
  256. }
  257. // Stop turns off the ticker.
  258. func (t *Ticker) Stop() {
  259. if t.ticker != nil {
  260. t.ticker.Stop()
  261. } else {
  262. t.mock.removeClockTimer((*internalTicker)(t))
  263. }
  264. }
  265. type internalTicker Ticker
  266. func (t *internalTicker) Next() time.Time { return t.next }
  267. func (t *internalTicker) Tick(now time.Time) {
  268. select {
  269. case t.c <- now:
  270. default:
  271. }
  272. t.next = now.Add(t.d)
  273. gosched()
  274. }
  275. // Sleep momentarily so that other goroutines can process.
  276. func gosched() { time.Sleep(1 * time.Millisecond) }