testexec: getting exit codes correctly.
commit e7168030d7dfe1f547b99c1f3d2973e45458e60f · parent 9dc11b366b
· browse this tree
Eric Myhre, 2021-09-24 18:20:32 UTC
(Which remains a bit of a bear, apparently. Especially if you want to talk accurrately about signals.)
diff --git a/testexec/defaults.go b/testexec/defaults.go index 26d3ad6..3ecad65 100644 --- a/testexec/defaults.go +++ b/testexec/defaults.go @@ -3,6 +3,7 @@ package testexec import ( "io" "os/exec" + "syscall" "testing" ) @@ -12,8 +13,28 @@ func ExecFn_Exec(args []string, stdin io.Reader, stdout, stderr io.Writer) (exit cmd.Stdout = stdout cmd.Stderr = stderr err := cmd.Run() - // FIXME: get the error code. - return -1, err + // A bunch of processing is required to get typical unix error codes out of golang's exec system, unfortunately. + // We're going to: + // - Try to return the exit code, if we can parse it -- and then *not* return an error. + // - Try to return a negative number with the signal if that's what killed things -- and then again *not* return an error. + // - Or return -1000 and an error, for anything else we can't make sense of. + // The -1000 return probably doesn't matter much -- you should check the error first (and where testmark uses this callback, it does), + // but a non-zero value there seems like better defense-in-depth anyway. + if exitErr, ok := err.(*exec.ExitError); ok { + waitStatus, ok := exitErr.Sys().(syscall.WaitStatus) + if !ok { + return exitErr.ExitCode(), nil + } + if waitStatus.Exited() { + return waitStatus.ExitStatus(), nil + } else if waitStatus.Signaled() { + return -int(waitStatus.Signal()), nil + } + } + if err != nil { + return -1000, err + } + return 0, nil } func ScriptFn_ExecBash(script string, stdin io.Reader, stdout, stderr io.Writer) (exitcode int, oshit error) {