Commit 0be4ef3e authored by Brad Fitzpatrick's avatar Brad Fitzpatrick

cmd/go: ensure streaming test's stdout, stderr are same as cmd/go's

Fixes #18153

Change-Id: Ie8a32dd6fe306f00e51cde77dd4ea353f7109940
Reviewed-on: https://go-review.googlesource.com/34010Reviewed-by: 's avatarIan Lance Taylor <iant@golang.org>
parent 94a4485f
...@@ -15,6 +15,7 @@ import ( ...@@ -15,6 +15,7 @@ import (
"os/exec" "os/exec"
"path/filepath" "path/filepath"
"regexp" "regexp"
"runtime"
"strconv" "strconv"
"strings" "strings"
"sync" "sync"
...@@ -331,6 +332,10 @@ func (t *tester) registerRaceBenchTest(pkg string) { ...@@ -331,6 +332,10 @@ func (t *tester) registerRaceBenchTest(pkg string) {
}) })
} }
// stdOutErrAreTerminals is defined in test_linux.go, to report
// whether stdout & stderr are terminals.
var stdOutErrAreTerminals func() bool
func (t *tester) registerTests() { func (t *tester) registerTests() {
if strings.HasSuffix(os.Getenv("GO_BUILDER_NAME"), "-vetall") { if strings.HasSuffix(os.Getenv("GO_BUILDER_NAME"), "-vetall") {
// Run vet over std and cmd and call it quits. // Run vet over std and cmd and call it quits.
...@@ -347,6 +352,27 @@ func (t *tester) registerTests() { ...@@ -347,6 +352,27 @@ func (t *tester) registerTests() {
return return
} }
// This test needs its stdout/stderr to be terminals, so we don't run it from cmd/go's tests.
// See issue 18153.
if runtime.GOOS == "linux" {
t.tests = append(t.tests, distTest{
name: "cmd_go_test_terminal",
heading: "cmd/go terminal test",
fn: func(dt *distTest) error {
t.runPending(dt)
if !stdOutErrAreTerminals() {
fmt.Println("skipping terminal test; stdout/stderr not terminals")
return nil
}
cmd := exec.Command("go", "test")
cmd.Dir = filepath.Join(os.Getenv("GOROOT"), "src/cmd/go/testdata/testterminal18153")
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd.Run()
},
})
}
// Fast path to avoid the ~1 second of `go list std cmd` when // Fast path to avoid the ~1 second of `go list std cmd` when
// the caller lists specific tests to run. (as the continuous // the caller lists specific tests to run. (as the continuous
// build coordinator does). // build coordinator does).
......
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build linux
package main
import (
"syscall"
"unsafe"
)
const ioctlReadTermios = syscall.TCGETS
// isTerminal reports whether fd is a terminal.
func isTerminal(fd uintptr) bool {
var termios syscall.Termios
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
return err == 0
}
func init() {
stdOutErrAreTerminals = func() bool {
return isTerminal(1) && isTerminal(2)
}
}
...@@ -13,7 +13,6 @@ import ( ...@@ -13,7 +13,6 @@ import (
"go/doc" "go/doc"
"go/parser" "go/parser"
"go/token" "go/token"
"io"
"os" "os"
"os/exec" "os/exec"
"path" "path"
...@@ -1122,12 +1121,8 @@ func (b *builder) runTest(a *action) error { ...@@ -1122,12 +1121,8 @@ func (b *builder) runTest(a *action) error {
cmd.Env = envForDir(cmd.Dir, origEnv) cmd.Env = envForDir(cmd.Dir, origEnv)
var buf bytes.Buffer var buf bytes.Buffer
if testStreamOutput { if testStreamOutput {
// The only way to keep the ordering of the messages and still cmd.Stdout = os.Stdout
// intercept its contents. os/exec will share the same Pipe for cmd.Stderr = os.Stderr
// both Stdout and Stderr when running the test program.
mw := io.MultiWriter(os.Stdout, &buf)
cmd.Stdout = mw
cmd.Stderr = mw
} else { } else {
cmd.Stdout = &buf cmd.Stdout = &buf
cmd.Stderr = &buf cmd.Stderr = &buf
...@@ -1192,7 +1187,7 @@ func (b *builder) runTest(a *action) error { ...@@ -1192,7 +1187,7 @@ func (b *builder) runTest(a *action) error {
t := fmt.Sprintf("%.3fs", time.Since(t0).Seconds()) t := fmt.Sprintf("%.3fs", time.Since(t0).Seconds())
if err == nil { if err == nil {
norun := "" norun := ""
if testShowPass && !testStreamOutput { if testShowPass {
a.testOutput.Write(out) a.testOutput.Write(out)
} }
if bytes.HasPrefix(out, noTestsToRun[1:]) || bytes.Contains(out, noTestsToRun) { if bytes.HasPrefix(out, noTestsToRun[1:]) || bytes.Contains(out, noTestsToRun) {
...@@ -1204,9 +1199,7 @@ func (b *builder) runTest(a *action) error { ...@@ -1204,9 +1199,7 @@ func (b *builder) runTest(a *action) error {
setExitStatus(1) setExitStatus(1)
if len(out) > 0 { if len(out) > 0 {
if !testStreamOutput {
a.testOutput.Write(out) a.testOutput.Write(out)
}
// assume printing the test binary's exit status is superfluous // assume printing the test binary's exit status is superfluous
} else { } else {
fmt.Fprintf(a.testOutput, "%s\n", err) fmt.Fprintf(a.testOutput, "%s\n", err)
......
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build linux
// This test is run by src/cmd/dist/test.go (cmd_go_test_terminal),
// and not by cmd/go's tests. This is because this test requires that
// that it be called with its stdout and stderr being a terminal.
// dist doesn't run `cmd/go test` against this test directory if
// dist's stdout/stderr aren't terminals.
//
// See issue 18153.
package p
import (
"syscall"
"testing"
"unsafe"
)
const ioctlReadTermios = syscall.TCGETS
// isTerminal reports whether fd is a terminal.
func isTerminal(fd uintptr) bool {
var termios syscall.Termios
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
return err == 0
}
func TestIsTerminal(t *testing.T) {
if !isTerminal(1) {
t.Errorf("stdout is not a terminal")
}
if !isTerminal(2) {
t.Errorf("stderr is not a terminal")
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment