@@ -112,6 +112,36 @@ func (m *Mock) WaitForAllTimers() time.Time {
112112 return m .now
113113}
114114
115+ // WaitForAllTimersOnce fires all timers at least once.
116+ func (m * Mock ) WaitForAllTimersOnce () time.Time {
117+ m .mu .Lock ()
118+ defer m .mu .Unlock ()
119+
120+ scheduled := make (map [* mockTimer ]struct {}, len (m .timers ))
121+ for _ , t := range m .timers {
122+ scheduled [t ] = struct {}{}
123+ }
124+
125+ for len (m .timers ) > 0 && len (scheduled ) > 0 {
126+ delete (scheduled , m .timers [0 ])
127+ m .fireNext ()
128+ }
129+
130+ return m .now
131+ }
132+
133+ // RunNextTimer fires the next timer.
134+ func (m * Mock ) RunNextTimer () time.Time {
135+ m .mu .Lock ()
136+ defer m .mu .Unlock ()
137+
138+ if len (m .timers ) > 0 {
139+ m .fireNext ()
140+ }
141+
142+ return m .now
143+ }
144+
115145// Set sets the current time.
116146func (m * Mock ) Set (until time.Time ) {
117147 m .mu .Lock ()
@@ -137,7 +167,7 @@ func (m *Mock) set(until time.Time) {
137167}
138168
139169func (m * Mock ) fireNext () {
140- t := heap . Pop ( & m .timers ).( * mockTimer )
170+ t := m .timers [ 0 ]
141171 m .now = t .next
142172 t .fire ()
143173
@@ -167,18 +197,11 @@ func (m *Mock) AfterFunc(d time.Duration, f func()) *Timer {
167197 if d <= 0 {
168198 t .fire ()
169199 } else {
170- m . schedule ( t )
200+ heap . Push ( & m . timers , t )
171201 }
172202 return & Timer {mocktime : t }
173203}
174204
175- func (m * Mock ) schedule (t * mockTimer ) {
176- if t .index >= 0 {
177- panic ("already scheduled!" )
178- }
179- heap .Push (& m .timers , t )
180- }
181-
182205// Now returns the current wall time on the mock clock.
183206func (m * Mock ) Now () time.Time {
184207 m .mu .Lock ()
@@ -211,7 +234,7 @@ func (m *Mock) Tick(d time.Duration) <-chan time.Time {
211234// Ticker creates a new instance of Ticker.
212235func (m * Mock ) Ticker (d time.Duration ) * Ticker {
213236 if d <= 0 {
214- panic ("ticker duration must be > 0 " )
237+ panic ("non-positive interval for Ticker.Reset " )
215238 }
216239
217240 m .mu .Lock ()
@@ -230,7 +253,7 @@ func (m *Mock) Ticker(d time.Duration) *Ticker {
230253 index : - 1 ,
231254 next : m .now .Add (d ),
232255 }
233- m . schedule ( t )
256+ heap . Push ( & m . timers , t )
234257 return & Ticker {C : ch , mocktime : t }
235258}
236259
@@ -254,7 +277,7 @@ func (m *Mock) Timer(d time.Duration) *Timer {
254277 if d <= 0 {
255278 t .fire ()
256279 } else {
257- m . schedule ( t )
280+ heap . Push ( & m . timers , t )
258281 }
259282 return & Timer {C : ch , mocktime : t }
260283}
@@ -300,7 +323,6 @@ func (t *Timer) Reset(d time.Duration) bool {
300323 if t .realtime != nil {
301324 return t .realtime .Reset (d )
302325 }
303-
304326 return t .mocktime .reset (d )
305327}
306328
@@ -346,14 +368,18 @@ type mockTimer struct {
346368}
347369
348370func (t * mockTimer ) fire () {
349- now := t .mock .now
350-
351371 if t .d != nil {
352- t .next = now .Add (* t .d )
353- t .mock .schedule (t )
372+ t .next = t .mock .now .Add (* t .d )
373+ if t .index < 0 {
374+ heap .Push (& t .mock .timers , t )
375+ } else {
376+ heap .Fix (& t .mock .timers , t .index )
377+ }
378+ } else if t .index >= 0 {
379+ heap .Remove (& t .mock .timers , t .index )
354380 }
355381
356- (t .fn )(now )
382+ (t .fn )(t . mock . now )
357383}
358384
359385func (t * mockTimer ) stop () bool {
@@ -363,7 +389,6 @@ func (t *mockTimer) stop() bool {
363389 return false
364390 }
365391 heap .Remove (& t .mock .timers , t .index )
366- t .index = - 1
367392 return true
368393}
369394
@@ -372,18 +397,22 @@ func (t *mockTimer) reset(dur time.Duration) bool {
372397 defer t .mock .mu .Unlock ()
373398
374399 if t .d != nil {
400+ if dur <= 0 {
401+ panic ("non-positive interval for Ticker.Reset" )
402+ }
375403 * t .d = dur
376404 }
377405
378406 t .next = t .mock .now .Add (dur )
379-
380- if t .index < 0 {
381- heap .Push (& t .mock .timers , t )
382- return false
383- } else {
407+ wasPending := t .index >= 0
408+ if dur <= 0 {
409+ t .fire ()
410+ } else if wasPending {
384411 heap .Fix (& t .mock .timers , t .index )
385- return true
412+ } else {
413+ heap .Push (& t .mock .timers , t )
386414 }
415+ return wasPending
387416}
388417
389418// Sleep momentarily so that other goroutines can process.
0 commit comments