]> Cypherpunks.ru repositories - gostls13.git/commitdiff
runtime: eliminate arbitrary timeouts in runBuiltTestProg and TestGdbBacktrace
authorBryan C. Mills <bcmills@google.com>
Thu, 3 Nov 2022 13:08:33 +0000 (09:08 -0400)
committerGopher Robot <gobot@golang.org>
Fri, 4 Nov 2022 16:48:32 +0000 (16:48 +0000)
This may fix the TestEINTR failures that have been frequent on the
riscv64 builders since CL 445597.

Updates #37405.
Updates #39043.

Change-Id: Iaf1403ff5ce2ff0203d5d0059908097d32d0b217
Reviewed-on: https://go-review.googlesource.com/c/go/+/447495
Auto-Submit: Bryan Mills <bcmills@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Austin Clements <austin@google.com>
Run-TryBot: Bryan Mills <bcmills@google.com>

src/runtime/crash_test.go
src/runtime/runtime-gdb_test.go

index 3782a9272962a8ca4cd4be8a5ef3b77dd6515d65..309777d6968a3a1e7e9173f6fcc36b6f1ba7e113 100644 (file)
@@ -6,7 +6,6 @@ package runtime_test
 
 import (
        "bytes"
-       "context"
        "errors"
        "flag"
        "fmt"
@@ -66,15 +65,17 @@ func runBuiltTestProg(t *testing.T, exe, name string, env ...string) string {
                t.Skip("-quick")
        }
 
-       ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
-       defer cancel()
-       cmd := testenv.CleanCmdEnv(testenv.CommandContext(t, ctx, exe, name))
+       start := time.Now()
+
+       cmd := testenv.CleanCmdEnv(testenv.Command(t, exe, name))
        cmd.Env = append(cmd.Env, env...)
        if testing.Short() {
                cmd.Env = append(cmd.Env, "RUNTIME_TEST_SHORT=1")
        }
        out, err := cmd.CombinedOutput()
-       if err != nil {
+       if err == nil {
+               t.Logf("%v (%v): ok", cmd, time.Since(start))
+       } else {
                if _, ok := err.(*exec.ExitError); ok {
                        t.Logf("%v: %v", cmd, err)
                } else if errors.Is(err, exec.ErrWaitDelay) {
index d3a30870c18004bef35a3c71aa82b8a7b959b792..4e7c22762a170f438cbb7a7b46a503a226e0c591 100644 (file)
@@ -6,7 +6,7 @@ package runtime_test
 
 import (
        "bytes"
-       "context"
+       "flag"
        "fmt"
        "internal/testenv"
        "os"
@@ -400,6 +400,15 @@ func TestGdbBacktrace(t *testing.T) {
        if runtime.GOOS == "netbsd" {
                testenv.SkipFlaky(t, 15603)
        }
+       if flag.Lookup("test.parallel").Value.(flag.Getter).Get().(int) < 2 {
+               // It is possible that this test will hang for a long time due to an
+               // apparent GDB bug reported in https://go.dev/issue/37405.
+               // If test parallelism is high enough, that might be ok: the other parallel
+               // tests will finish, and then this test will finish right before it would
+               // time out. However, if test are running sequentially, a hang in this test
+               // would likely cause the remaining tests to run out of time.
+               testenv.SkipFlaky(t, 37405)
+       }
 
        checkGdbEnvironment(t)
        t.Parallel()
@@ -421,6 +430,7 @@ func TestGdbBacktrace(t *testing.T) {
        }
 
        // Execute gdb commands.
+       start := time.Now()
        args := []string{"-nx", "-batch",
                "-iex", "add-auto-load-safe-path " + filepath.Join(testenv.GOROOT(t), "src", "runtime"),
                "-ex", "set startup-with-shell off",
@@ -430,9 +440,32 @@ func TestGdbBacktrace(t *testing.T) {
                "-ex", "continue",
                filepath.Join(dir, "a.exe"),
        }
-       ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
-       defer cancel()
-       got, err := testenv.CommandContext(t, ctx, "gdb", args...).CombinedOutput()
+       cmd = testenv.Command(t, "gdb", args...)
+
+       // Work around the GDB hang reported in https://go.dev/issue/37405.
+       // Sometimes (rarely), the GDB process hangs completely when the Go program
+       // exits, and we suspect that the bug is on the GDB side.
+       //
+       // The default Cancel function added by testenv.Command will mark the test as
+       // failed if it is in danger of timing out, but we want to instead mark it as
+       // skipped. Change the Cancel function to kill the process and merely log
+       // instead of failing the test.
+       //
+       // (This approach does not scale: if the test parallelism is less than or
+       // equal to the number of tests that run right up to the deadline, then the
+       // remaining parallel tests are likely to time out. But as long as it's just
+       // this one flaky test, it's probably fine..?)
+       //
+       // If there is no deadline set on the test at all, relying on the timeout set
+       // by testenv.Command will cause the test to hang indefinitely, but that's
+       // what “no deadline” means, after all — and it's probably the right behavior
+       // anyway if someone is trying to investigate and fix the GDB bug.
+       cmd.Cancel = func() error {
+               t.Logf("GDB command timed out after %v: %v", time.Since(start), cmd)
+               return cmd.Process.Kill()
+       }
+
+       got, err := cmd.CombinedOutput()
        t.Logf("gdb output:\n%s", got)
        if err != nil {
                if bytes.Contains(got, []byte("internal-error: wait returned unexpected status 0x0")) {