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
proposal: testing: reconsider adding Context method to testing.T #36532
Comments
Did you intend for your sample |
@seh yup, fixed, thanks! |
I'm having second thoughts about this proposal. Given that it's so simple to define your own test-context function, does I believe the function below does almost exactly the same thing as the
|
I think the changes to In particular, that change would allow you to do something like: func TestFoo(t *testing.T) {
g, ctx := errgroup.New(context.Background())
t.Cleanup(g.Stop)
g.Go(func() error {
defer wg.Done()
doSomething(ctx)
return nil
})
} |
Thinking about this some more: I think a Some users would likely assume that it is (only) cancelled if and when the test is marked as failed. Others might assume that it is cancelled at start of the Since there is no single “intuitive” interpretation, we should avoid the ambiguous name. Perhaps we could find a less ambiguous name, but given that the explicit code isn't much longer I'm not sure that's worth the API weight. |
After some discussion with @mvdan, I realised that my original proposal here was not sufficient for his use case (he wants to start tearing things down immediately there's a test error). I don't agree with tearing everything down on any call to Calling wdyt? |
The approach in that We don't need to couple cancellation to Note that one of the changes in that |
I like that thought. The only issue is that you'd have to be careful to add the corresponding code to every goroutine, I guess. That might turn out to be a pain (and it's error-prone). We'd still need to drop the "FailNow must be called from the goroutine running the test or benchmark function, not from other goroutines created during the test." sentence from the docs. Does that seem reasonable to you? |
That seems reasonable. I would probably replace that sentence with a more explicit one, rather than dropping it outright. Perhaps something like:
And in the comment for
And for
|
I am interested in continuing this discussion, can we add this to the proposal rotation, or was there something blocking the discussion? |
What I've done for couple of projects was to introduce the following function: const (
// Arbitrary amount of time to let tests exit cleanly before main process terminates.
timeoutGracePeriod = 10 * time.Second
)
// contextWithDeadline returns context with will timeout before t.Deadline().
func contextWithDeadline(t *testing.T) context.Context {
t.Helper()
deadline, ok := t.Deadline()
if !ok {
return context.Background()
}
ctx, cancel := context.WithDeadline(context.Background(), deadline.Truncate(timeoutGracePeriod))
t.Cleanup(cancel)
return ctx
} This allows to properly respect gracePeriod := time.Second
ctx := t.ContextWithDeadline(gracePeriod) We could also validate that |
I am strongly in favor of adding this. It seems like every single test that I write begins with: func TestXxx(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel() I have also found that tests which use contexts and don't begin with that preamble usually leak resources or contain other context related bugs. I think making this functionality built-in would help encourage better testing. |
There have been various previous proposals (#16221 #18182 #18199 #18368) to add a Context method to testing.T. #16221 was even accepted and implemented but then reverted.
By my understanding, the principal argument against adding a Context method was that Context provides a way to tell things to shut down, but no way to wait for things to actually finish, so adding this functionality doesn't actually provide a good way to wait for tests to gracefully shut down, because they might fail and resources might continue to be used even after the testing package has marked the tests as successful.
For example @bcmills wrote:
Similarly from @niemeyer here:
However, @dsnet, who reverted the code, suggested that the decision wasn't necessarily final:
I propose that the recently added T.Cleanup method can now provide the wait mechanism that's needed - the other half of
Context.Done
. We can define the semantics such that the the testing context is cancelled just before invoking the Cleanup-registered functions. That way, it's easy to both listen for the test being done, and also to wait for asynchronous operations to finish when it is.By hooking into the
Cleanup
mechanism, we don't presuppose any particular kind of waiting - this can hook into whatever mechanism your infrastructure provides for graceful shutdown.A possible API description:
Example usage:
The text was updated successfully, but these errors were encountered: