You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

clock.go 8.6KB

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