-
Notifications
You must be signed in to change notification settings - Fork 1.6k
add await.Require and await.RequireTrue
#9490
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
Merged
Merged
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
9968cd8
better `eventually`
stephanos ff8a0e3
doc.go
stephanos 70dcafe
use testing.TB
stephanos fc8fe76
use t.Fail()
stephanos 7898741
drop prefix
stephanos d44c410
drop contextOverride
stephanos d048057
fix lint
stephanos 0cde661
sync.Once
stephanos File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| // Package await provides polling-based test assertions as a replacement | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be in a
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've seen both approaches ( |
||
| // for testify's Eventually, EventuallyWithT, and their formatted variants. | ||
| // | ||
| // Improvements over testify's eventually functions: | ||
| // | ||
| // - Misuse detection: accidentally using the real *testing.T (e.g. s.T() or | ||
| // suite assertion methods) instead of the callback's collect T is a | ||
| // common mistake. This package detects it and fails with a clear message. | ||
| // | ||
| // - Safer bool predicates: unlike testify's Eventually, [RequireTrue] only | ||
| // accepts func() bool, so returning false is the sole retry signal. If the | ||
| // predicate accidentally marks the real test failed, it reports that | ||
| // immediately instead of polling until timeout. | ||
| // | ||
| // - Timeout-aware callbacks: callbacks receive a context derived from the | ||
| // parent context and canceled when the await timeout or test deadline is | ||
| // reached, so RPCs and blocking waits can exit instead of continuing after | ||
| // the retry window has expired. | ||
| // | ||
| // - Panic propagation: if the condition panics (e.g. nil dereference), the | ||
| // panic is propagated immediately rather than being silently swallowed | ||
| // or retried until timeout. | ||
| // See https://github.com/stretchr/testify/issues/1810 | ||
| // | ||
| // - Bounded goroutine lifetime: each attempt completes before the next | ||
| // starts, avoiding the overlapping-attempt data races and "panic: Fail | ||
| // in goroutine after Test has completed" crashes seen with testify's | ||
| // Eventually. | ||
| // See https://github.com/stretchr/testify/issues/1611 | ||
| // | ||
| // - Deadlock detection: a condition that ignores t.Context() is abandoned | ||
| // after a grace period, producing a clear "does it honor t.Context()?" | ||
| // failure instead of hanging until go test -timeout. | ||
| // | ||
| // - Condition always runs: testify's Eventually can fail without ever | ||
| // running the condition due to a timer/ticker race with short timeouts. | ||
| // This package runs the condition immediately on the first iteration. | ||
| // See https://github.com/stretchr/testify/issues/1652 | ||
| package await | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,65 @@ | ||
| package await | ||
|
|
||
| import ( | ||
| "fmt" | ||
| "strings" | ||
| "testing" | ||
| "time" | ||
| ) | ||
|
|
||
| // reportAttemptErrors emits the collected attempt failures. When there are | ||
| // many, only the first and the last few are shown — long polls would | ||
| // otherwise produce hundreds of duplicate lines. | ||
| const ( | ||
| reportHeadAttempts = 1 | ||
| reportTailAttempts = 3 | ||
| ) | ||
|
|
||
| type attemptFailure struct { | ||
| attempt int | ||
| errors []string | ||
| } | ||
|
|
||
| // reportTimeout reports the timeout failure plus collected attempt errors. | ||
| func reportTimeout(tb testing.TB, failures []attemptFailure, funcName, timeoutMsg string, effectiveTimeout time.Duration, polls int) { | ||
| reportAttemptErrors(tb, failures) | ||
| if timeoutMsg != "" { | ||
| tb.Fatalf("%s: %s (not satisfied after %v, %d polls)", funcName, timeoutMsg, effectiveTimeout, polls) | ||
| } else { | ||
| tb.Fatalf("%s: condition not satisfied after %v (%d polls)", funcName, effectiveTimeout, polls) | ||
| } | ||
| } | ||
|
|
||
| func reportAttemptErrors(tb testing.TB, failures []attemptFailure) { | ||
| if len(failures) == 0 { | ||
| return | ||
| } | ||
|
|
||
| var b strings.Builder | ||
| b.WriteString("attempt errors:") | ||
| if len(failures) <= reportHeadAttempts+reportTailAttempts { | ||
| for _, f := range failures { | ||
| writeAttemptFailure(&b, f) | ||
| } | ||
| } else { | ||
| for _, f := range failures[:reportHeadAttempts] { | ||
| writeAttemptFailure(&b, f) | ||
| } | ||
| omitted := len(failures) - reportHeadAttempts - reportTailAttempts | ||
| fmt.Fprintf(&b, "\n ... %d attempts omitted ...", omitted) | ||
| for _, f := range failures[len(failures)-reportTailAttempts:] { | ||
| writeAttemptFailure(&b, f) | ||
| } | ||
| } | ||
| tb.Errorf("%s", b.String()) | ||
| } | ||
|
|
||
| func writeAttemptFailure(b *strings.Builder, f attemptFailure) { | ||
| fmt.Fprintf(b, "\n attempt %d:", f.attempt) | ||
| for _, e := range f.errors { | ||
| for line := range strings.SplitSeq(e, "\n") { | ||
| b.WriteString("\n ") | ||
| b.WriteString(line) | ||
| } | ||
| } | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Require new code to use new
Await