Skip to content

Commit

Permalink
os: use testenv.Command and os.Executable in tests
Browse files Browse the repository at this point in the history
On Unix platforms, testenv.Command sends SIGQUIT to stuck commands
before the test times out. For subprocesses that are written in Go,
that causes the runtime to dump running goroutines, and in other
languages it triggers similar behavior (such as a core dump).
If the subprocess is stuck due to a bug (such as #57999), that may
help to diagnose it.

For #57999.

Change-Id: I00f381b8052cbbb1a7eea90e7f102a3f68c842d1
Reviewed-on: https://go-review.googlesource.com/c/go/+/521817
TryBot-Result: Gopher Robot <gobot@golang.org>
Run-TryBot: Bryan Mills <bcmills@google.com>
Reviewed-by: Ian Lance Taylor <iant@google.com>
Auto-Submit: Bryan Mills <bcmills@google.com>
  • Loading branch information
Bryan C. Mills authored and pull[bot] committed Jan 24, 2024
1 parent fa87d81 commit 1752610
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 11 deletions.
45 changes: 35 additions & 10 deletions src/os/signal/signal_cgo_test.go
Expand Up @@ -14,9 +14,9 @@ import (
"context"
"encoding/binary"
"fmt"
"internal/testenv"
"internal/testpty"
"os"
"os/exec"
"os/signal"
"runtime"
"strconv"
Expand Down Expand Up @@ -93,7 +93,7 @@ func TestTerminalSignal(t *testing.T) {
// Main test process, run code below.
break
case "1":
runSessionLeader(pause)
runSessionLeader(t, pause)
panic("unreachable")
case "2":
runStoppingChild()
Expand Down Expand Up @@ -128,9 +128,22 @@ func TestTerminalSignal(t *testing.T) {
t.Fatal(err)
}

ctx, cancel := context.WithTimeout(context.Background(), 100*time.Second)
defer cancel()
cmd := exec.CommandContext(ctx, os.Args[0], "-test.run=TestTerminalSignal")
var (
ctx = context.Background()
cmdArgs = []string{"-test.run=TestTerminalSignal"}
)
if deadline, ok := t.Deadline(); ok {
d := time.Until(deadline)
var cancel context.CancelFunc
ctx, cancel = context.WithTimeout(ctx, d)
t.Cleanup(cancel)

// We run the subprocess with an additional 20% margin to allow it to fail
// and clean up gracefully if it times out.
cmdArgs = append(cmdArgs, fmt.Sprintf("-test.timeout=%v", d*5/4))
}

cmd := testenv.CommandContext(t, ctx, os.Args[0], cmdArgs...)
cmd.Env = append(os.Environ(), "GO_TEST_TERMINAL_SIGNALS=1")
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout // for logging
Expand Down Expand Up @@ -216,7 +229,7 @@ func TestTerminalSignal(t *testing.T) {
}

// GO_TEST_TERMINAL_SIGNALS=1 subprocess above.
func runSessionLeader(pause time.Duration) {
func runSessionLeader(t *testing.T, pause time.Duration) {
// "Attempts to use tcsetpgrp() from a process which is a
// member of a background process group on a fildes associated
// with its controlling terminal shall cause the process group
Expand All @@ -235,10 +248,22 @@ func runSessionLeader(pause time.Duration) {
pty := os.NewFile(ptyFD, "pty")
controlW := os.NewFile(controlFD, "control-pipe")

// Slightly shorter timeout than in the parent.
ctx, cancel := context.WithTimeout(context.Background(), 90*time.Second)
defer cancel()
cmd := exec.CommandContext(ctx, os.Args[0], "-test.run=TestTerminalSignal")
var (
ctx = context.Background()
cmdArgs = []string{"-test.run=TestTerminalSignal"}
)
if deadline, ok := t.Deadline(); ok {
d := time.Until(deadline)
var cancel context.CancelFunc
ctx, cancel = context.WithTimeout(ctx, d)
t.Cleanup(cancel)

// We run the subprocess with an additional 20% margin to allow it to fail
// and clean up gracefully if it times out.
cmdArgs = append(cmdArgs, fmt.Sprintf("-test.timeout=%v", d*5/4))
}

cmd := testenv.CommandContext(t, ctx, os.Args[0], cmdArgs...)
cmd.Env = append(os.Environ(), "GO_TEST_TERMINAL_SIGNALS=2")
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
Expand Down
2 changes: 1 addition & 1 deletion src/os/signal/signal_test.go
Expand Up @@ -483,7 +483,7 @@ func TestNohup(t *testing.T) {
defer wg.Done()

// POSIX specifies that nohup writes to a file named nohup.out if standard
// output is a terminal. However, for an exec.Command, standard output is
// output is a terminal. However, for an exec.Cmd, standard output is
// not a terminal — so we don't need to read or remove that file (and,
// indeed, cannot even create it if the current user is unable to write to
// GOROOT/src, such as when GOROOT is installed and owned by root).
Expand Down

0 comments on commit 1752610

Please sign in to comment.