-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
assert: Eventually should not leak a goroutine #1611
Comments
Cc: @cszczepaniak |
Here is a test that we will add to the testsuite to detect this wrong behavior: type dummyT struct{}
func (dummyT) Errorf(string, ...any) {}
func TestEventuallyNoLeak(t *testing.T) {
done := make(chan bool)
inEventually := true
assert.Eventually(dummyT{}, func() bool {
defer func() {
done <- inEventually
}()
time.Sleep(500 * time.Millisecond)
return true
}, 100*time.Millisecond, 10*time.Millisecond)
inEventually = false
assert.True(t, <-done, "Condition should end while Eventually still runs.")
} Currently failing:
|
In the above test, even though Eventually should wait for the condition to finish, I'm assuming that the Eventually test should still fail since the condition could not be true within the |
My proposal:
Notes:
|
As per the API, |
Need some more clarity on this. Say we have the following tests: func Test1(t *testing.T) {
condition := func() bool {
time.Sleep(50 * time.Millisecond)
return true
}
Eventually(t, condition, 20*time.Millisecond, 5*time.Millisecond) // should raise an error for long condition func and return false
Never(t, condition, 20*time.Millisecond, 5*time.Millisecond) // should raise an error for long condition func and return true
}
func Test2(t *testing.T) {
condition := func() bool {
time.Sleep(50 * time.Millisecond)
return false
}
Eventually(t, condition, 20*time.Millisecond, 5*time.Millisecond) // should raise an error for long condition func and return false
Never(t, condition, 20*time.Millisecond, 5*time.Millisecond) // should raise an error for long condition func and return true
} Do the comments reflect the expected behaviour in each of the cases? |
This would be a breaking change I suppose as it could fail some of the existing tests. |
I am trying to understand here. But doesn't it defeat the purpose of providing the waitfor? If the condition overruns the waitfor duration, ideally, Eventually should throw an error along with condition to stop executing further. Apologies, if I misunderstood anything! |
@anonmanak2000 the proposal here is somewhat similar. We want to throw an error when the condition exceeds waitFor duration. However, since the condition runs in a separate go routine, we need to ensure that the go routine finishes before we return from Eventually. |
@dolmen the proposal looks good, but I have concerns around:
Both of these seem like breaking changes to me. Wdyt? |
I think this (and every other problem with Eventually) is solved by making the call to |
Description
If the condition function runs for longer than the timeout given to
assert.Eventually
(and family:EventuallyWithT
,Never
) it returns anyway right after the timeout, and the goroutine in which the condition runs continues in the background beyondEventually
returns. This is a goroutine leak that can lead to dirty bugs and flaky tests.Note that the
Eventually
internal test suiteTestEventuallyWithT_ReturnsTheLatestFinishedConditionErrors
andTestEventuallyTimeout
rely on this behavior so we first have to fix those 2 tests.Step To Reproduce
On the Go Playground: https://go.dev/play/p/mDyUOIJXQS5
Expected behavior
Every log happening in the condition should happen before "Eventually done".
Actual behavior
The text was updated successfully, but these errors were encountered: