diff --git a/mock.go b/mock.go index ffda2e7..cc8e064 100644 --- a/mock.go +++ b/mock.go @@ -480,17 +480,24 @@ func (m *mockTickerFunc) next() time.Time { func (m *mockTickerFunc) fire(_ time.Time) { m.mock.mu.Lock() - defer m.mock.mu.Unlock() - if m.done || m.inProgress { + if m.done { + m.mock.mu.Unlock() return } m.nxt = m.nxt.Add(m.d) m.mock.recomputeNextLocked() + // we need this check to happen after we've computed the next tick, + // otherwise it will be immediately rescheduled. + if m.inProgress { + m.mock.mu.Unlock() + return + } m.inProgress = true m.mock.mu.Unlock() err := m.f() m.mock.mu.Lock() + defer m.mock.mu.Unlock() m.inProgress = false m.cond.Broadcast() // wake up anything waiting for f to finish if err != nil { diff --git a/mock_test.go b/mock_test.go index 47316ca..8099738 100644 --- a/mock_test.go +++ b/mock_test.go @@ -292,9 +292,13 @@ func TestTickerFunc_LongCallback(t *testing.T) { case <-testCtx.Done(): t.Fatal("timeout waiting for tickStart") } - // second tick completes immediately, since it doesn't actually call the - // ticker function. - mClock.Advance(time.Second).MustWait(testCtx) + // additional ticks complete immediately. + elapsed := time.Duration(0) + for elapsed < 5*time.Second { + d, wt := mClock.AdvanceNext() + elapsed += d + wt.MustWait(testCtx) + } waitErr := make(chan error, 1) go func() {