diff --git a/test/utils/ktesting/contexthelper.go b/test/utils/ktesting/contexthelper.go index 6347211e0a7..b6f6263a4a8 100644 --- a/test/utils/ktesting/contexthelper.go +++ b/test/utils/ktesting/contexthelper.go @@ -48,11 +48,17 @@ func withTimeout(ctx context.Context, tb TB, timeout time.Duration, timeoutCause cancelCtx, cancel := context.WithCancelCause(ctx) after := time.NewTimer(timeout) stopCtx, stop := context.WithCancel(ctx) // Only used internally, doesn't need a cause. + done := make(chan struct{}) tb.Cleanup(func() { cancel(cleanupErr(tb.Name())) stop() + // Wait for goroutine termination. This is important because + // otherwise the goroutine might log through tb *after* the + // test has already finished, which causes a panic. + <-done }) go func() { + defer close(done) select { case <-stopCtx.Done(): after.Stop() diff --git a/test/utils/ktesting/contexthelper_test.go b/test/utils/ktesting/contexthelper_test.go index 721d2eada55..6ed9c5ce52c 100644 --- a/test/utils/ktesting/contexthelper_test.go +++ b/test/utils/ktesting/contexthelper_test.go @@ -119,7 +119,11 @@ func TestCause(t *testing.T) { assert.Equal(t, tt.expectDeadline, time.Until(actualDeadline), "remaining time till Deadline()") } } + // Unblock background goroutines. time.Sleep(tt.sleep) + // Wait for them to do their work. + synctest.Wait() + // Now check. actualErr := ctx.Err() actualCause := context.Cause(ctx) assert.Equal(t, tt.expectErr, actualErr, "ctx.Err()")