cmd/testwrapper: surface race reports and skip retries when detected
A data race in a package matters more than any individual test
result. Two related problems:
1. Where go test's race detector text ("WARNING: DATA RACE" plus
the goroutine stack traces) lands in JSON output is timing-
dependent: it can be attributed to a test that ends up reporting
PASS (e.g. when the racing goroutines outlive the test that
spawned them and TSan prints during a different test's window).
testwrapper's main loop only flushes the logs of failed tests,
so the race report ends up stuck in a passing test's buffer and
is silently dropped. The race builders just see a bare
"FAIL\nFAIL\tpkg\ttime".
2. If the failing test in such a package happens to be marked flaky,
testwrapper retries it. That is the worst possible response to a
race: the flaky test might not even be the racy code, and a
second run without the racy goroutines could "succeed" while
hiding the real bug.
Address both: scan every output line for the race detector's first-
line marker. Track whether the package observed a race at all, on
the pkgFinished testAttempt. When a race was seen, fold every per-
test log buffer into the package-level logs (so the full report
surfaces from the existing pkg-fail flush path), and drop any
flaky-test retry plans for that package so we fail immediately
instead of running another attempt.
Two new tests:
- TestRaceSuppressesFlakyRetry verifies that a flaky test alongside
a racy test does NOT get retried.
- TestRaceAttributedToPassingTest verifies that a race attributed by
test2json to a passing test still surfaces in the output.
Also add a corpus of captured raw test binary outputs under
cmd/testwrapper/testdata/, with one subdirectory per scenario,
documenting the six representative shapes that go test -race can
emit (race in test body, race in goroutines that outlive a test,
race forced into a later test, race in TestMain post-m.Run, and a
parallel-tests split-attribution case via a "=== NAME" redirect
line). See its README.md for details.
Fixes #19603
Change-Id: Ifbfcd67fb3b1882c4907bd9cb2d68a8b5a91dd54
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
committed by
Brad Fitzpatrick
parent
ee0a03b140
commit
95d874e9b4
@@ -0,0 +1,32 @@
|
||||
=== RUN TestSpawn
|
||||
==================
|
||||
WARNING: DATA RACE
|
||||
Read at 0x0000007f12a8 by goroutine 9:
|
||||
racesurvey/C_spawnwait.TestSpawn.func2()
|
||||
/tmp/racesurvey/C_spawnwait/c_test.go:14 +0x70
|
||||
|
||||
Previous write at 0x0000007f12a8 by goroutine 8:
|
||||
racesurvey/C_spawnwait.TestSpawn.func1()
|
||||
/tmp/racesurvey/C_spawnwait/c_test.go:13 +0x88
|
||||
|
||||
Goroutine 9 (running) created at:
|
||||
racesurvey/C_spawnwait.TestSpawn()
|
||||
/tmp/racesurvey/C_spawnwait/c_test.go:14 +0x44
|
||||
testing.tRunner()
|
||||
/home/ubuntu/sdk/go1.26.3/src/testing/testing.go:2036 +0x21c
|
||||
testing.(*T).Run.gowrap1()
|
||||
/home/ubuntu/sdk/go1.26.3/src/testing/testing.go:2101 +0x38
|
||||
|
||||
Goroutine 8 (finished) created at:
|
||||
racesurvey/C_spawnwait.TestSpawn()
|
||||
/tmp/racesurvey/C_spawnwait/c_test.go:13 +0x34
|
||||
testing.tRunner()
|
||||
/home/ubuntu/sdk/go1.26.3/src/testing/testing.go:2036 +0x21c
|
||||
testing.(*T).Run.gowrap1()
|
||||
/home/ubuntu/sdk/go1.26.3/src/testing/testing.go:2101 +0x38
|
||||
==================
|
||||
testing.go:1712: race detected during execution of test
|
||||
--- FAIL: TestSpawn (0.00s)
|
||||
=== RUN TestWait
|
||||
--- PASS: TestWait (0.00s)
|
||||
FAIL
|
||||
@@ -0,0 +1,31 @@
|
||||
=== RUN TestSpawn
|
||||
--- PASS: TestSpawn (0.00s)
|
||||
=== RUN TestWait
|
||||
==================
|
||||
WARNING: DATA RACE
|
||||
Read at 0x0000007f12a8 by goroutine 8:
|
||||
racesurvey/C_spawnwait.TestSpawn.func1()
|
||||
/tmp/racesurvey/C_spawnwait/c_test.go:13 +0x70
|
||||
|
||||
Previous write at 0x0000007f12a8 by goroutine 9:
|
||||
racesurvey/C_spawnwait.TestSpawn.func2()
|
||||
/tmp/racesurvey/C_spawnwait/c_test.go:14 +0x88
|
||||
|
||||
Goroutine 8 (running) created at:
|
||||
racesurvey/C_spawnwait.TestSpawn()
|
||||
/tmp/racesurvey/C_spawnwait/c_test.go:13 +0x34
|
||||
testing.tRunner()
|
||||
/home/ubuntu/sdk/go1.26.3/src/testing/testing.go:2036 +0x21c
|
||||
testing.(*T).Run.gowrap1()
|
||||
/home/ubuntu/sdk/go1.26.3/src/testing/testing.go:2101 +0x38
|
||||
|
||||
Goroutine 9 (finished) created at:
|
||||
racesurvey/C_spawnwait.TestSpawn()
|
||||
/tmp/racesurvey/C_spawnwait/c_test.go:14 +0x44
|
||||
testing.tRunner()
|
||||
/home/ubuntu/sdk/go1.26.3/src/testing/testing.go:2036 +0x21c
|
||||
testing.(*T).Run.gowrap1()
|
||||
/home/ubuntu/sdk/go1.26.3/src/testing/testing.go:2101 +0x38
|
||||
==================
|
||||
--- PASS: TestWait (0.00s)
|
||||
FAIL
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
// Copyright (c) Tailscale Inc & contributors
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
package spawnwait
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var counter int
|
||||
var wg sync.WaitGroup
|
||||
|
||||
func TestSpawn(t *testing.T) {
|
||||
wg.Add(2)
|
||||
go func() { defer wg.Done(); counter++ }()
|
||||
go func() { defer wg.Done(); counter++ }()
|
||||
}
|
||||
|
||||
func TestWait(t *testing.T) {
|
||||
wg.Wait()
|
||||
}
|
||||
Reference in New Issue
Block a user