clock.go 7.7 KB

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