Skip to content

fix(test): attribute Go failures from go test -json and carry their output (#283) - #297

Merged
piwi3910 merged 4 commits into
mainfrom
fix/testrun-failure-output
Sep 23, 2026
Merged

piwi3910 merged 4 commits into
mainfrom
fix/testrun-failure-output

Conversation

@piwi3910

Copy link
Copy Markdown
Contributor

Refs #283

What this does

The failing package's output is now kept (the issue's suggested next step). Every Go failure carries a short excerpt of its own output: the assertion, the panic or the build error. It appears under the FAIL line in procoder test and in the gate's finding. It has hard limits: 3 failures, 20 lines each (the first 5 are kept, because that is where a panic says what it was), 240 bytes per line and 4 KiB in total. The one-line summary is unchanged.

Hypothesis 1 (wrong test name reported): the parser does misattribute. The runner used to pull ^--- FAIL: (\S+) out of go test's text output. I ran it against real go test output and found two problems:

  • If a test prints --- FAIL: TestNoDirectProcoderFileIO (0.10s) to stdout, it is reported as that test failing, and the failure count goes up. The text stream can't tell a printed line from the framework's own verdict.
  • A package that fails outside any test has no --- FAIL: line: a build or setup failure, a panic in a background goroutine, a timeout. When another package had a real test failure, this package disappeared from the report. When it failed alone, the summary was just the first line of output, which can be another package's ok.

The Go runner now uses go test -json. Failures come from the framework's fail events. A failed subtest is named by the subtest itself (TestParent/child), and its parent isn't counted again. A package that failed outside any test is named by package, with go's reason (pkg [build failed]). Output is matched to a test by the event's Test field, so parallel tests can't mix their output. Pass counts, [no test files], [no tests to run] and the coverage average are worked out from the package-level lines, so the pass path reports the same thing as before (checked against the old binary on this repository).

Hypothesis 2 (a file parsed mid-write). Both store guards now use parseListed. It skips a file that no longer exists when it is parsed, and only that case. A file that exists but does not parse, including a half-written one, still fails the guard.

Why Refs and not Fixes

This does not prove what failed on run 34395461728. Nothing in this repository prints a --- FAIL: line, and no test runs the suite inside another test, so I can't show that the spoofing case is what happened there. What this change does is make the next occurrence explain itself. The report will have the real failing test or package plus its output, and if the guard fails on a parse error, the path and the parser error will be in the excerpt.

Tests (each one fails if its change is reverted)

  • TestAPrintedFailLineIsNotAFailingTest: the spoofing case
  • TestAPackageThatFailedOutsideAnyTestIsNamed: a panic in a background goroutine plus a build failure, next to a real test failure
  • TestALoneBuildFailureIsNamedByPackage
  • TestAFailedSubtestIsNamedOnce
  • TestParallelOutputStaysWithItsTest: parallel tests plus a test that panics
  • TestTheGateFindingCarriesTheAssertion: the gate finding and procoder test both carry the excerpt
  • TestTheExcerptIsBounded
  • TestPreJSONBuildErrorsStillReachTheExcerpt: before Go 1.24, build errors are printed as stderr text rather than JSON events
  • TestParseListedForgivesOnlyAVanishedFile: a vanished file is skipped, a partial file still fails

Verification

  • procoder test: ok go pass (57 package(s))
  • procoder check: procoder gate: 8 clean, 0 unformatted, 0 unchecked, 0 out of scope, 10 hygiene finding(s) (0 blocking)

…utput (#283)

procoder test and the gate's test leg scraped `^--- FAIL: (\S+)` out of
go test's text stream. Two misattributions were demonstrated on real go
test output:

- a test that prints a `--- FAIL: TestOther` line to stdout is reported
  as TestOther failing, and the count is wrong;
- a package that fails outside any test (build or setup failure, a panic
  in a background goroutine, a timeout) has no `--- FAIL:` line, so it
  vanished beside a real test failure and, alone, was summarised as the
  first line of output, which can be an unrelated package's "ok".

The Go runner now reads `go test -json`: failures come from the
framework's fail events, subtests are named by the leaf that failed, and
package-only failures are named by package with go's reason
("[build failed]"). Each failure carries a bounded excerpt of its own
output (3 failures, 20 lines each keeping the head where a panic names
itself, 240-byte lines, 4 KiB total) under the FAIL line in procoder
test and in the gate's finding, so the next unreproducible red says what
it asserted rather than only a name.

The store guard tests now tolerate a file that vanished between the walk
and the parse, and only that: a present file that does not parse,
partial writes included, still fails the guard.
Copilot AI lite review requested due to automatic review settings September 23, 2026 12:21

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Unresolved issues remain in diagnostic attribution, excerpt preservation, and excerpt size limits.

Get a fresh assessment by requesting another Copilot review.

Review effort: Lite
Findings: 2 Medium severity

Open (2)
What changed in this PR

Updates Go test execution to use go test -json, improve failure attribution, preserve bounded diagnostics, and tolerate vanished store files.

Changes:

  • Adds JSON-based failure parsing and excerpts to reports and gate findings.
  • Adds regression tests for attribution, output limits, and disappearing files.
  • Updates related documentation and command expectations.
File Summary
internal/​testrun/​testrun.go Integrates JSON parsing and failure output.
internal/​testrun/​gojson.go Parses Go events and builds excerpts.
internal/​testrun/​gojson_test.go Adds parser and attribution tests.
internal/​testrun/​gate.go Adds excerpts to gate findings.
internal/​testrun/​filter_test.go Updates expected Go arguments.
internal/​store/​coverage_test.go Handles vanished files during parsing.
docs/​domains.md Documents JSON-based Go testing.
docs/​commands.md Documents Go failure diagnostics.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread internal/testrun/gojson.go Outdated
Comment thread internal/testrun/gojson.go Outdated
Review of #297: a long subtest name or import path was written uncapped and could spend the excerpt budget before the diagnosis; and on Go before 1.24 the stray stderr stream was copied under every package that failed outside a test, reading as each package's own error.
@piwi3910
piwi3910 merged commit 6a6293f into main Sep 23, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants