|
|
|
@ -12,11 +12,9 @@ import ( |
|
|
|
"os/exec" |
|
|
|
"os/exec" |
|
|
|
"path/filepath" |
|
|
|
"path/filepath" |
|
|
|
"runtime" |
|
|
|
"runtime" |
|
|
|
"strconv" |
|
|
|
|
|
|
|
"strings" |
|
|
|
"strings" |
|
|
|
"sync" |
|
|
|
"sync" |
|
|
|
"testing" |
|
|
|
"testing" |
|
|
|
"time" |
|
|
|
|
|
|
|
) |
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
// The code in this file is adapted from internal/testenv in the Go source tree
|
|
|
|
// The code in this file is adapted from internal/testenv in the Go source tree
|
|
|
|
@ -52,15 +50,6 @@ func pathToTestProg(t *testing.T, binary string) string { |
|
|
|
return exe |
|
|
|
return exe |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func runTestProg(t *testing.T, binary, name string, env ...string) string { |
|
|
|
|
|
|
|
exe, err := buildTestProg(t, binary, "-buildvcs=false") |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
t.Fatal(err) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return runBuiltTestProg(t, exe, name, env...) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func startTestProg(t *testing.T, binary, name string, env ...string) { |
|
|
|
func startTestProg(t *testing.T, binary, name string, env ...string) { |
|
|
|
exe, err := buildTestProg(t, binary, "-buildvcs=false") |
|
|
|
exe, err := buildTestProg(t, binary, "-buildvcs=false") |
|
|
|
if err != nil { |
|
|
|
if err != nil { |
|
|
|
@ -70,16 +59,6 @@ func startTestProg(t *testing.T, binary, name string, env ...string) { |
|
|
|
startBuiltTestProg(t, exe, name, env...) |
|
|
|
startBuiltTestProg(t, exe, name, env...) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func runBuiltTestProg(t *testing.T, exe, name string, env ...string) string { |
|
|
|
|
|
|
|
cmd := exec.Command(exe, name) |
|
|
|
|
|
|
|
cmd.Env = append(cmd.Env, env...) |
|
|
|
|
|
|
|
if testing.Short() { |
|
|
|
|
|
|
|
cmd.Env = append(cmd.Env, "RUNTIME_TEST_SHORT=1") |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
out, _ := runWithTimeout(t, cmd) |
|
|
|
|
|
|
|
return string(out) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func startBuiltTestProg(t *testing.T, exe, name string, env ...string) { |
|
|
|
func startBuiltTestProg(t *testing.T, exe, name string, env ...string) { |
|
|
|
cmd := exec.Command(exe, name) |
|
|
|
cmd := exec.Command(exe, name) |
|
|
|
cmd.Env = append(cmd.Env, env...) |
|
|
|
cmd.Env = append(cmd.Env, env...) |
|
|
|
@ -276,20 +255,6 @@ func mustHaveGoBuild(t testing.TB) { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// hasGoRun reports whether the current system can run programs with “go run.”
|
|
|
|
|
|
|
|
func hasGoRun() bool { |
|
|
|
|
|
|
|
// For now, having go run and having go build are the same.
|
|
|
|
|
|
|
|
return hasGoBuild() |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// mustHaveGoRun checks that the current system can run programs with “go run.”
|
|
|
|
|
|
|
|
// If not, mustHaveGoRun calls t.Skip with an explanation.
|
|
|
|
|
|
|
|
func mustHaveGoRun(t testing.TB) { |
|
|
|
|
|
|
|
if !hasGoRun() { |
|
|
|
|
|
|
|
t.Skipf("skipping test: 'go run' not available on %s/%s", runtime.GOOS, runtime.GOARCH) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var ( |
|
|
|
var ( |
|
|
|
gorootOnce sync.Once |
|
|
|
gorootOnce sync.Once |
|
|
|
gorootPath string |
|
|
|
gorootPath string |
|
|
|
@ -366,57 +331,6 @@ func findGOROOT() (string, error) { |
|
|
|
return gorootPath, gorootErr |
|
|
|
return gorootPath, gorootErr |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// runWithTimeout runs cmd and returns its combined output. If the
|
|
|
|
|
|
|
|
// subprocess exits with a non-zero status, it will log that status
|
|
|
|
|
|
|
|
// and return a non-nil error, but this is not considered fatal.
|
|
|
|
|
|
|
|
func runWithTimeout(t testing.TB, cmd *exec.Cmd) ([]byte, error) { |
|
|
|
|
|
|
|
args := cmd.Args |
|
|
|
|
|
|
|
if args == nil { |
|
|
|
|
|
|
|
args = []string{cmd.Path} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var b bytes.Buffer |
|
|
|
|
|
|
|
cmd.Stdout = &b |
|
|
|
|
|
|
|
cmd.Stderr = &b |
|
|
|
|
|
|
|
if err := cmd.Start(); err != nil { |
|
|
|
|
|
|
|
t.Fatalf("starting %s: %v", args, err) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// If the process doesn't complete within 1 minute,
|
|
|
|
|
|
|
|
// assume it is hanging and kill it to get a stack trace.
|
|
|
|
|
|
|
|
p := cmd.Process |
|
|
|
|
|
|
|
done := make(chan bool) |
|
|
|
|
|
|
|
go func() { |
|
|
|
|
|
|
|
scale := 2 |
|
|
|
|
|
|
|
if s := os.Getenv("GO_TEST_TIMEOUT_SCALE"); s != "" { |
|
|
|
|
|
|
|
if sc, err := strconv.Atoi(s); err == nil { |
|
|
|
|
|
|
|
scale = sc |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
select { |
|
|
|
|
|
|
|
case <-done: |
|
|
|
|
|
|
|
case <-time.After(time.Duration(scale) * time.Minute): |
|
|
|
|
|
|
|
p.Signal(os.Kill) |
|
|
|
|
|
|
|
// If SIGQUIT doesn't do it after a little
|
|
|
|
|
|
|
|
// while, kill the process.
|
|
|
|
|
|
|
|
select { |
|
|
|
|
|
|
|
case <-done: |
|
|
|
|
|
|
|
case <-time.After(time.Duration(scale) * 30 * time.Second): |
|
|
|
|
|
|
|
p.Signal(os.Kill) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
err := cmd.Wait() |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
t.Logf("%s exit status: %v", args, err) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
close(done) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return b.Bytes(), err |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// start runs cmd asynchronously and returns immediately.
|
|
|
|
// start runs cmd asynchronously and returns immediately.
|
|
|
|
func start(t testing.TB, cmd *exec.Cmd) { |
|
|
|
func start(t testing.TB, cmd *exec.Cmd) { |
|
|
|
args := cmd.Args |
|
|
|
args := cmd.Args |
|
|
|
|