You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The issue is that I'm setting a timer with duration 0 which is legal. However, if you look at AdvanceNext you see:
func (m*Mock) AdvanceNext() (time.Duration, AdvanceWaiter) {
m.mu.Lock()
m.tb.Helper()
w:=AdvanceWaiter{tb: m.tb, ch: make(chanstruct{})}
ifm.nextTime.IsZero() {
deferclose(w.ch)
deferm.mu.Unlock()
m.tb.Error("cannot AdvanceNext because there are no timers or tickers running")
}
d:=m.nextTime.Sub(m.cur)
m.cur=m.nextTimegom.advanceLocked(w)
returnd, w
}
There's two bugs here I think:
It checks if m.nextTime.IsZero but that doesn't necessarily mean there's nothing scheduled as it is legal to set a timer with a duration of 0
If it does hit that condition it calls defer m.mu.Unlock but then it still calls advanceLocked which unlocks that mutex so you get a panic due to a double unlock of the mutex.
Granted it's a bit of an odd case to schedule a timer for 0 seconds in the future but I think there are valid use cases for it. For my use case a user puts a request for a function to be called into a channel. We read from that channel and schedule the callback. It is possible that by the time we read from the channel the time has expired so we should call right away. We could special case that code but as it's legal to schedule a timer with 0-delay with a real timer and that's less code and fewere if statements we simply schedule the timer to fire immediately.
The text was updated successfully, but these errors were encountered:
So, it is not fine to call AdvanceNext() after because there is nothing else scheduled.
Also, as an aside, in your example, I see that you set a trap for NewTimer().
The trap is set after you start a go routine that calls NewTimer(). This will race and there is no guarantee that you will actually trap the call. You need to set the trap before you start the goroutine.
Your code never calls Wait() on the trap. After setting the trap, you need to Wait() on it and then Release() the call in order for NewTimer() to return.
Closing because I think the actual bug is already resolved. Please reopen if you think there is still an issue with the latest main branch.
Thanks for the prompt reply! You're correct about the NewTimer trap - that was left over from the "real unit test" that was failing when I simplified it to make it suitable for a bug report.
It does look like the bug is fixed on main but that hasn't been released. The latest release, the one go mod tidy pulls, is 0.1.2 which was released before the bug fix. Any chance you could push a new release with the fix?
The following unit test fails with a panic:
The issue is that I'm setting a timer with duration 0 which is legal. However, if you look at
AdvanceNext
you see:There's two bugs here I think:
m.nextTime.IsZero
but that doesn't necessarily mean there's nothing scheduled as it is legal to set a timer with a duration of 0defer m.mu.Unlock
but then it still callsadvanceLocked
which unlocks that mutex so you get a panic due to a double unlock of the mutex.Granted it's a bit of an odd case to schedule a timer for 0 seconds in the future but I think there are valid use cases for it. For my use case a user puts a request for a function to be called into a channel. We read from that channel and schedule the callback. It is possible that by the time we read from the channel the time has expired so we should call right away. We could special case that code but as it's legal to schedule a timer with 0-delay with a real timer and that's less code and fewere if statements we simply schedule the timer to fire immediately.
The text was updated successfully, but these errors were encountered: