diff --git a/modules/mesh-delivery-checker/internal/check/judge.go b/modules/mesh-delivery-checker/internal/check/judge.go index bf1b4aa..afd9bf8 100644 --- a/modules/mesh-delivery-checker/internal/check/judge.go +++ b/modules/mesh-delivery-checker/internal/check/judge.go @@ -583,9 +583,24 @@ func dropSummary(out string) (string, bool) { return strings.TrimSpace(strings.Join(kept, "\n")), passed } -// causeIn is the first "panic:", "fatal error:" or "signal:" line of a failure's output, in that order, or "". +// causeIn is a race the race detector reported, as its heading, its access and the frame that made it ("WARNING: DATA +// RACE: Write at 0x... by goroutine 9 in pkg.F.func1()"); else the first "panic:", "fatal error:" or "signal:" line of a +// failure's output, in that order; or "". func causeIn(out string) string { lines := strings.Split(out, "\n") + for i, l := range lines { + if strings.TrimSpace(l) != "WARNING: DATA RACE" { + continue + } + words := "WARNING: DATA RACE" + if i+1 < len(lines) && strings.TrimSpace(lines[i+1]) != "" { + words += ": " + strings.TrimSuffix(strings.TrimSpace(lines[i+1]), ":") + if i+2 < len(lines) && strings.HasPrefix(lines[i+2], " ") { + words += " in " + strings.TrimSpace(lines[i+2]) + } + } + return words + } for _, prefix := range []string{"panic: ", "fatal error: ", "signal: "} { for _, l := range lines { if l = strings.TrimSpace(l); strings.HasPrefix(l, prefix) { diff --git a/modules/mesh-delivery-checker/internal/check/package_cause_test.go b/modules/mesh-delivery-checker/internal/check/package_cause_test.go index 0c4206b..08f8b2f 100644 --- a/modules/mesh-delivery-checker/internal/check/package_cause_test.go +++ b/modules/mesh-delivery-checker/internal/check/package_cause_test.go @@ -8,13 +8,15 @@ import ( // What the build module before this fix sent for two packages that failed after their tests passed (issue 1901, its third // meeting: a try of mesh-controller kept "PASS" as its failure's words). Each is that build module's Output for the real // `go test -json` of a throwaway package (mesh-catalog modules/mesh-build-go testdata/captured/go-test-json-pkg-*.jsonl): -// TestMain panicking in a goroutine after m.Run, and TestMain exiting 2 after m.Run. +// TestMain panicking in a goroutine after m.Run, TestMain exiting 2 after m.Run, and TestMain racing after m.Run. const ( oldPassThenPanic = "PASS\npanic: the bus closed after the tests: nats: connection closed\ngoroutine 20 [running]:\n" + "example.com/passthenfail.TestMain.func1()\n\t/tmp/fix-1901b/passthenfail/p_test.go:13 +0x25\n" + "created by example.com/passthenfail.TestMain in goroutine 1\n\t/tmp/fix-1901b/passthenfail/p_test.go:13 +0x25\n" + "FAIL\texample.com/passthenfail\t0.005s" oldPassThenExit = "PASS\nFAIL\texample.com/mainexit\t0.004s" + // TestMain racing after m.Run passed, under go test -race (go-test-json-pkg-racemain.jsonl). + oldPassThenRace = "PASS\n==================\nWARNING: DATA RACE\nWrite at 0x000000836428 by goroutine 9:\n example.com/racemain.TestMain.func1()\n /tmp/fix-1901b/racemain/p_test.go:15 +0x24\nPrevious write at 0x000000836428 by main goroutine:\n example.com/racemain.TestMain()\n /tmp/fix-1901b/racemain/p_test.go:16 +0x44\n main.main()\n _testmain.go:48 +0x171\nGoroutine 9 (running) created at:\n example.com/racemain.TestMain()\n /tmp/fix-1901b/racemain/p_test.go:15 +0x37\n main.main()\n _testmain.go:48 +0x171\n==================\nFound 1 data race(s)\nFAIL\texample.com/racemain\t1.031s" ) // A failure with no cause told apart never has "PASS" or "ok" as its words: the checker takes the panic line from the @@ -25,6 +27,7 @@ func TestAPackageFailureIsNeverWordedPass(t *testing.T) { // 1901/AC5 }{ {"panic after the tests", oldPassThenPanic, "panic: the bus closed after the tests: nats: connection closed"}, {"exit after the tests", oldPassThenExit, "the tests passed, then the test program exited with a failure"}, + {"race after the tests", oldPassThenRace, "WARNING: DATA RACE: Write at 0x000000836428 by goroutine 9 in example.com/racemain.TestMain.func1()"}, {"a panic deep in a long output", "PASS\npanic: the seat row vanished\n" + strings.Repeat("goroutine 7 [chan receive]:\n\tsome/frame.go:1 +0x1\n", 300) + "FAIL\tp\t2.0s", "panic: the seat row vanished"}, } for _, c := range cases {