Skip to content

Commit 0f1e0ae

Browse files
authored
Setting test.timeout according to TEST_TIMEOUT (#3920)
1 parent 6d352d6 commit 0f1e0ae

File tree

5 files changed

+43
-49
lines changed

5 files changed

+43
-49
lines changed

go/tools/builders/generate_test_main.go

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,11 +98,13 @@ import (
9898
"log"
9999
"os"
100100
"os/exec"
101+
"os/signal"
101102
{{if .TestMain}}
102103
"reflect"
103104
{{end}}
104105
"strconv"
105106
"strings"
107+
"syscall"
106108
"testing"
107109
"testing/internal/testdeps"
108110
@@ -235,7 +237,19 @@ func main() {
235237
}
236238
}
237239
{{end}}
238-
bzltestutil.RegisterTimeoutHandler()
240+
241+
testTimeout := os.Getenv("TEST_TIMEOUT")
242+
if testTimeout != "" {
243+
flag.Lookup("test.timeout").Value.Set(testTimeout+"s")
244+
// If Bazel sends a SIGTERM because the test timed out, it sends it to all child processes. Because
245+
// we set -test.timeout according to the TEST_TIMEOUT, we need to ignore the signal so the test has
246+
// time to properly produce the output (e.g. stack trace). It will be killed by Bazel after the grace
247+
// period (15s) expires.
248+
// If TEST_TIMEOUT is not set (e.g., when the test binary is run by Delve for debugging), we don't
249+
// ignore SIGTERM so it can be properly terminated.
250+
signal.Ignore(syscall.SIGTERM)
251+
}
252+
239253
{{if not .TestMain}}
240254
res := m.Run()
241255
{{else}}

go/tools/bzltestutil/BUILD.bazel

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ go_tool_library(
55
srcs = [
66
"lcov.go",
77
"test2json.go",
8-
"timeout.go",
98
"wrap.go",
109
"xml.go",
1110
],

go/tools/bzltestutil/timeout.go

Lines changed: 0 additions & 39 deletions
This file was deleted.

go/tools/bzltestutil/wrap.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -125,10 +125,11 @@ func Wrap(pkg string) error {
125125
exePath = filepath.Join(chdir.TestExecDir, exePath)
126126
}
127127

128-
// If Bazel sends a SIGTERM because the test timed out, it sends it to all child processes. As
129-
// a result, the child process will print stack traces of all Go routines and we want the
130-
// wrapper to be around to capute and forward this output. Thus, we need to ignore the signal
131-
// and will be killed by Bazel after the grace period instead.
128+
// If Bazel sends a SIGTERM because the test timed out, it sends it to all child processes. However,
129+
// we want the wrapper to be around to capute and forward the test output when this happens. Thus,
130+
// we need to ignore the signal. This wrapper will natually ends after the Go test ends, either by
131+
// SIGTERM or the time set by -test.timeout expires. If that doesn't happen, the test and this warpper
132+
// will be killed by Bazel after the grace period (15s) expires.
132133
signal.Ignore(syscall.SIGTERM)
133134

134135
cmd := exec.Command(exePath, args...)

tests/core/go_test/timeout_test.go

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,19 @@ func TestTimeout(t *testing.T) {
4141
t.Skip("stack traces on timeouts are not yet supported on Windows")
4242
}
4343

44-
if err := bazel_testing.RunBazel("test", "//:timeout_test", "--test_timeout=3"); err == nil {
44+
var stderr string
45+
if err := bazel_testing.RunBazel("test", "//:timeout_test", "--test_timeout=3", "--test_arg=-test.v"); err == nil {
4546
t.Fatal("expected bazel test to fail")
4647
} else if exitErr, ok := err.(*bazel_testing.StderrExitError); !ok || exitErr.Err.ExitCode() != 3 {
4748
t.Fatalf("expected bazel test to fail with exit code 3", err)
49+
} else {
50+
stderr = string(exitErr.Err.Stderr)
4851
}
52+
53+
if !strings.Contains(stderr, "TIMEOUT: //:timeout_test") {
54+
t.Errorf("expect Bazel to report the test timed out: \n%s", stderr)
55+
}
56+
4957
p, err := bazel_testing.BazelOutput("info", "bazel-testlogs")
5058
if err != nil {
5159
t.Fatalf("could not find testlogs root: %s", err)
@@ -57,10 +65,21 @@ func TestTimeout(t *testing.T) {
5765
}
5866

5967
testLog := string(b)
60-
if !strings.Contains(testLog, "Received SIGTERM, printing stack traces of all goroutines:") {
61-
t.Fatalf("test log does not contain expected header:\n%s", testLog)
68+
if !strings.Contains(testLog, "panic: test timed out after 3s") {
69+
t.Errorf("test log does not contain expected header:\n%s", testLog)
6270
}
6371
if !strings.Contains(testLog, "timeout_test.neverTerminates(") {
64-
t.Fatalf("test log does not contain expected stack trace:\n%s", testLog)
72+
t.Errorf("test log does not contain expected stack trace:\n%s", testLog)
73+
}
74+
75+
path = filepath.Join(strings.TrimSpace(string(p)), "timeout_test/test.xml")
76+
b, err = os.ReadFile(path)
77+
if err != nil {
78+
t.Fatalf("could not read test XML: %s", err)
79+
}
80+
81+
testXML := string(b)
82+
if !strings.Contains(testXML, `<testcase classname="timeout_test" name="TestFoo"`) {
83+
t.Errorf("test XML does not contain expected element:\n%s", testXML)
6584
}
6685
}

0 commit comments

Comments
 (0)