testmark-go

Merge pull request #6 from warpfork/exec-exitcodes

commit 14b6f0f554ecb0df2288b899fccece9618e61760 · parent 91a00c1f23 · parent e7168030d7 · browse this tree
Eric Myhre, 2021-09-26 21:25:23 UTC

testexec: getting exit codes correctly.
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) {