Keep coverage errors out of the output of the pipeline tests

On the Windows CI job,
TestStartPipelineReadsWhatTheCommandsComplainAbout fails now and then
because the output it reads has an extra line after the expected one.
The line starts with "error: coverage meta-data emit failed" and ends
with "The process cannot access the file because it is being used by
another process."

The pipeline tests run the test binary itself as the members of the
pipeline. CI builds it with -cover, and the members inherit GOCOVERDIR
from go test, so each of them writes coverage data to that directory
when it calls os.Exit. The meta-data file has the same name for every
process of one binary, and every process replaces it by renaming a new
copy onto it. (Go's check for an existing file compares its size against
the wrong length, so it never finds one.) On Windows this rename fails
if another process holds the file open. In this test both members exit
at the same time, and the runtime prints the failure to stderr.
StartPipeline puts every member's stderr into the output that the test
compares.

Exit the members with syscall.Exit instead. It skips the runtime's exit
hooks, so the members write no coverage data at all. Nothing is lost by
this. Their coverage data went to a temporary directory of go test, not
to the directory that CI uploads.

The test was added in dfd6a7dbf2.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Stefan Haller
2026-09-26 12:10:37 +02:00
co-authored by Claude Opus 5.5
parent a82c0d0122
commit f9eb2090a6
+9 -2
View File
@@ -5,6 +5,7 @@ import (
"io"
"os"
"strings"
"syscall"
"testing"
"time"
@@ -26,6 +27,12 @@ func pipelineMember(role string) *CmdObj {
// TestPipelineMember is the program the pipeline tests run, not a test of its
// own. It exits before the testing package reports anything, so that its output
// is what the role wrote and nothing else.
//
// For the same reason it exits with syscall.Exit, which skips the exit hooks
// that os.Exit runs. In a binary built with -cover, one of these hooks writes
// coverage data to $GOCOVERDIR and prints an error to stderr if that fails. On
// Windows it fails now and then if two members of a pipeline exit at the same
// time, because both of them replace the same file in that directory.
func TestPipelineMember(t *testing.T) {
switch os.Getenv(pipelineRoleEnvVar) {
case "":
@@ -41,7 +48,7 @@ func TestPipelineMember(t *testing.T) {
_, _ = io.Copy(os.Stdout, os.Stdin)
case "complain":
fmt.Fprintln(os.Stderr, "something went wrong")
os.Exit(3)
syscall.Exit(3)
case "flood":
// A failed write means the reader is gone, and there is no point
// writing to nobody. On platforms that raise a signal for it instead,
@@ -53,7 +60,7 @@ func TestPipelineMember(t *testing.T) {
}
}
os.Exit(0)
syscall.Exit(0)
}
func TestStartPipelineStreamsTheOutputOfTheLastCommand(t *testing.T) {