Skip to content

Commit ab9d31d

Browse files
adggopherbot
authored andcommitted
cmd/go/internal/test: wrap os.Stdout always
There is an issue where 'go test' will hang after the tests complete if a test starts a sub-process that does not exit (see #24050). However, go test only exhibits that behavior when a package name is explicitly passed as an argument. If 'go test' is invoked without any package arguments then the package in the working directory is assumed, however in that case (and only that case) os.Stdout is used as the test process's cmd.Stdout, which does *not* cause 'go test' wait for the sub-process to exit (see #23019). This change wraps os.Stdout in an io.Writer struct in this case, hiding the *os.File from the os/exec package, causing cmd.Wait to always wait for the full output from the test process and any of its sub-processes. In other words, this makes 'go test' exhibit the same behavior as 'go test .' (or 'go test ./...' and so on). Update #23019 Update #24050 Change-Id: Ica09bf156f3b017f9a31aad91ed0f16a7837195b Reviewed-on: https://go-review.googlesource.com/c/go/+/400877 Reviewed-by: Bryan Mills <[email protected]> Run-TryBot: Andrew Gerrand <[email protected]> Auto-Submit: Andrew Gerrand <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Reviewed-by: Andrew Gerrand <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]>
1 parent ebe1435 commit ab9d31d

File tree

2 files changed

+40
-1
lines changed

2 files changed

+40
-1
lines changed

src/cmd/go/internal/test/test.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1261,7 +1261,11 @@ func (c *runCache) builderRunTest(b *work.Builder, ctx context.Context, a *work.
12611261
return nil
12621262
}
12631263

1264-
var stdout io.Writer = os.Stdout
1264+
// The os/exec package treats an *os.File differently to an io.Writer.
1265+
// Embed os.Stdout in an io.Writer struct so that we get the same
1266+
// behavior regardless of whether we wrap it below.
1267+
// See golang.org/issue/24050
1268+
var stdout io.Writer = struct{ io.Writer }{os.Stdout}
12651269
var err error
12661270
if testJSON {
12671271
json := test2json.NewConverter(lockedStdout{}, a.Package.ImportPath, test2json.Timestamp)
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Wait for test output from sub-processes whether or not the package name is
2+
# provided on the command-line.
3+
go test -v
4+
stdout 'PASS\s+WAIT\s+ok'
5+
go test -v .
6+
stdout 'PASS\s+WAIT\s+ok'
7+
8+
-- go.mod --
9+
module x
10+
11+
-- x_test.go --
12+
package x
13+
14+
import (
15+
"os"
16+
"os/exec"
17+
"testing"
18+
)
19+
20+
func TestMain(m *testing.M) {
21+
if os.Getenv("WAIT") == "true" {
22+
os.Stdout.Write([]byte("WAIT\n"))
23+
return
24+
}
25+
m.Run()
26+
}
27+
28+
func TestWait(t *testing.T) {
29+
cmd := exec.Command(os.Args[0])
30+
cmd.Env = []string{"WAIT=true"}
31+
cmd.Stdout = os.Stdout
32+
if err := cmd.Start(); err != nil {
33+
t.Fatal(err)
34+
}
35+
}

0 commit comments

Comments
 (0)