Skip to content

assert: check early in Eventually, EventuallyWithT, and Never #1427

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

Open
wants to merge 7 commits into
base: master
Choose a base branch
from

Conversation

cszczepaniak
Copy link

@cszczepaniak cszczepaniak commented Jul 15, 2023

Summary

Addresses #1424.

Eventually and EventuallyWithT current must always wait at least the polling duration before they can succeed. This PR starts checking the condition immediately. The assertion still fails if the initial check of the condition takes longer than the configured timeout.

Changes

Motivation

This will provide a small optimization to callers, because tests can complete more quickly than they did before if conditions are met already.

Related issues

@dolmen dolmen added enhancement pkg-assert Change related to package testify/assert labels Jul 25, 2023
@dolmen
Copy link
Collaborator

dolmen commented Jul 25, 2023

This PR changes more than what it claims.

Please keep it focused on #1424 and move the changes related to the tick separately. Because it seems that runs of the condition will not overlap anymore.

@cszczepaniak
Copy link
Author

cszczepaniak commented Jul 25, 2023

@dolmen What more does it change? The changes I made to the tick here are to facilitate addressing #1424. How would you do it differently?

@cszczepaniak cszczepaniak force-pushed the cs/quicker_eventually branch from d4ebae4 to dc3af0f Compare July 30, 2023 17:51
@cszczepaniak
Copy link
Author

#1439 could also address this issue. @dolmen what are your thoughts on this PR's approach vs. addressing #1439 instead?

@dolmen
Copy link
Collaborator

dolmen commented Jul 30, 2023

I intend to merge #1395 first. Could you help with your own review now, and we will work on your own changes after the merge?

@cszczepaniak
Copy link
Author

@dolmen After #1395, I think we should pursue either the approach in this PR or the approach outlined in #1439, but not both. I will wait until we have the input needed to decide on #1439

@dolmen dolmen added the assert.Eventually About assert.Eventually/EventuallyWithT label Jul 31, 2023
@dolmen dolmen changed the title Return early in Eventually and EventuallyWithT assert: early in Eventually and EventuallyWithT Oct 16, 2023
@dolmen dolmen changed the title assert: early in Eventually and EventuallyWithT assert: check early in Eventually and EventuallyWithT Oct 30, 2023
Comment on lines 2840 to 3048
condition := func(t *CollectT) { <-time.After(time.Millisecond) }

done := make(chan struct{})
go func() {
defer close(done)
True(t, EventuallyWithT(mockT, condition, 1000*time.Millisecond, 100*time.Millisecond))
}()

select {
case <-done:
case <-time.After(10 * time.Millisecond):
Fail(t, `condition not satisfied quickly enough`)
}

This comment was marked as resolved.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great idea!

Comment on lines 2822 to 3038
condition := func() bool { <-time.After(time.Millisecond); return true }

done := make(chan struct{})
go func() {
defer close(done)
True(t, Eventually(mockT, condition, 1000*time.Millisecond, 100*time.Millisecond))
}()

select {
case <-done:
case <-time.After(10 * time.Millisecond):
Fail(t, `condition not satisfied quickly enough`)
}

This comment was marked as resolved.

@cszczepaniak cszczepaniak force-pushed the cs/quicker_eventually branch from dc3af0f to 7ec44f8 Compare June 8, 2024 23:56
Comment on lines +2973 to +2985
// Check that a long running condition doesn't block Eventually.
// See issue 805 (and its long tail of following issues)
func TestEventuallyTimeout(t *testing.T) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test isn't new; I just moved it so that all of the Eventually* tests are grouped together rather than having the Never* tests in between them

@cszczepaniak cszczepaniak requested a review from pgimalac June 9, 2024 00:10
@cszczepaniak cszczepaniak changed the title assert: check early in Eventually and EventuallyWithT assert: check early in Eventually, EventuallyWithT, and Never Jun 9, 2024
@dolmen
Copy link
Collaborator

dolmen commented Jun 13, 2024

@cszczepaniak I just merged #1481 which uses runtime.Goexit. The single goroutine approach is incompatible.

@cszczepaniak
Copy link
Author

@dolmen sounds good. I don't think that affects this PR, though.

Copy link

@pgimalac pgimalac left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving for visibility

@dolmen
Copy link
Collaborator

dolmen commented Jul 9, 2024

@cszczepaniak Please rebase as this requires to resolve merge conflicts.

@cszczepaniak cszczepaniak force-pushed the cs/quicker_eventually branch from 82097f1 to bae586f Compare July 9, 2024 13:45
@cszczepaniak
Copy link
Author

@dolmen Thanks, I've rebased now.

@pgimalac
Copy link

👋 Hey @dolmen @cszczepaniak, any update on this PR ?
I think it's a really nice improvement of Eventually so it would be nice if it was merged

@cszczepaniak
Copy link
Author

@pgimalac I'd like it to merge. Just waiting on final review from @dolmen

@pgimalac
Copy link

👋 Hey @dolmen, any chance you could give this PR another review ?

Copy link
Collaborator

@brackendawson brackendawson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the code in this PR is perfectly fine and implements the feature cleanly. I especially like that it removes the rather implicit assignment of ticker.C to tick in the for statement.

@dolmen's concern that this removes any overlapping runs of the condition isn't an issue. The condition already cannot overlap because of tick being set to null before calling the condition function.

Because of the way tickers work this cannot alter the timing of when the last condition function call happens so long as the condition function function always has a shorter duration than tick. If the condition function can take longer than tick then this may alter the timing. In all cases where the duration of the condition function is unrelated to when it is called this change can add at most 1 additional call of the condition function. It is possible that poorly written code with race conditions may now panic, deadlock, or any number of other things that make tests fail.

It's unlikely that even very fast asynchronous code will satisfy the new first call to the condition function if Eventually is called soon after the asynchronous code starts. But this means it's more likely that more condition functions will be exercised in their failing state. I don't think this will speed up many tests at all.

I think these factors all stand to improve the condition of code tested by Testify, but I'm sure there will be tests which previously passed which now fail in poorly written code-bases. We will need to be ready to field support requests.

I'm going to leave my approve but give other maintainers a couple of weeks to consider what I've written here before merging.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
assert.Eventually About assert.Eventually/EventuallyWithT enhancement pkg-assert Change related to package testify/assert
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants