[testrunner] Add flag for setting local testing working directory

The testsharder output has Linux/Mac test paths as relative to the build
directory; setting this flag to $root_build_dir locally allows for more
flexible use.

Change-Id: I0dd5eec3271c05999022fcff500da7322eefda29
diff --git a/cmd/testrunner/main.go b/cmd/testrunner/main.go
index 7570c1d..4382a17 100644
--- a/cmd/testrunner/main.go
+++ b/cmd/testrunner/main.go
@@ -47,6 +47,9 @@
 
 	// The path where a tar archive containing test results should be created.
 	archive string
+
+	// Working directory of the local testing subprocesses.
+	localWD string
 )
 
 // TestRunnerOutput manages the output of this test runner.
@@ -106,6 +109,7 @@
 func init() {
 	flag.BoolVar(&help, "help", false, "Whether to show Usage and exit.")
 	flag.StringVar(&archive, "archive", "", "Optional path where a tar archive containing test results should be created.")
+	flag.StringVar(&localWD, "C", "", "Working directory of local testing subprocesses; if unset the current working directory will be used.")
 	flag.Usage = usage
 }
 
@@ -172,11 +176,15 @@
 		return fmt.Errorf("could not determine the runtime system for following tests %v", unknown)
 	}
 
-	if err := runTests(linux, RunTestInSubprocess, output); err != nil {
+	localTester := &SubprocessTester{
+		WD: localWD,
+	}
+
+	if err := runTests(linux, localTester.Test, output); err != nil {
 		return err
 	}
 
-	if err := runTests(mac, RunTestInSubprocess, output); err != nil {
+	if err := runTests(mac, localTester.Test, output); err != nil {
 		return err
 	}
 
diff --git a/cmd/testrunner/tester.go b/cmd/testrunner/tester.go
index 53296d4..ef3cbd3 100644
--- a/cmd/testrunner/tester.go
+++ b/cmd/testrunner/tester.go
@@ -16,8 +16,12 @@
 // Tester is executes a Test.
 type Tester func(context.Context, testsharder.Test, io.Writer, io.Writer) error
 
-// RunTestInSubprocess is a TesterFunc that executes the given test in a local subprocess.
-func RunTestInSubprocess(ctx context.Context, test testsharder.Test, stdout io.Writer, stderr io.Writer) error {
+// SubprocessTester executes tests in local subprocesses.
+type SubprocessTester struct {
+	WD string
+}
+
+func (t *SubprocessTester) Test(ctx context.Context, test testsharder.Test, stdout io.Writer, stderr io.Writer) error {
 	var command []string
 	if len(test.Location) > 0 {
 		command = []string{test.Location}
@@ -26,10 +30,11 @@
 	}
 
 	runner := new(testrunner.SubprocessRunner)
+	runner.WD = t.WD
 	return runner.Run(ctx, command, stdout, stderr)
 }
 
-// SSHTester is executes tests over an SSH connection. It assumes the test.Command
+// SSHTester executes tests over an SSH connection. It assumes the test.Command
 // contains the command line to execute on the remote machine.
 type SSHTester struct {
 	client *ssh.Client
diff --git a/cmd/testrunner/tester_test.go b/cmd/testrunner/tester_test.go
index 81d425f..b40de24 100644
--- a/cmd/testrunner/tester_test.go
+++ b/cmd/testrunner/tester_test.go
@@ -15,11 +15,11 @@
 )
 
 func TestTester(t *testing.T) {
-	tester := RunTestInSubprocess
+	tester := &SubprocessTester{}
 	cases := []testCase{
 		{
 			name:   "should run a command a local subprocess",
-			tester: tester,
+			tester: tester.Test,
 			test: testsharder.Test{
 				Name: "hello_world_test",
 				// Assumes that we're running on a Unix system.
diff --git a/testrunner/subprocess_runner.go b/testrunner/subprocess_runner.go
index 4189b4f..3ad36a1 100644
--- a/testrunner/subprocess_runner.go
+++ b/testrunner/subprocess_runner.go
@@ -19,6 +19,9 @@
 
 // SubprocessRunner is a Runner that runs commands as local subprocesses.
 type SubprocessRunner struct {
+	// WD is the working directory of the subprocesses; if unspecified, that
+	// of the current process will be used.
+	WD string
 }
 
 // Run executes the given command.
@@ -28,6 +31,7 @@
 		Args:        command,
 		Stdout:      stdout,
 		Stderr:      stderr,
+		Dir:         r.WD,
 		SysProcAttr: &syscall.SysProcAttr{Setpgid: true},
 	}