Support (test) timeouts in Bazel.

Fixes #279.

--
MOS_MIGRATED_REVID=97661546
diff --git a/src/main/java/com/google/devtools/build/lib/rules/test/StandaloneTestStrategy.java b/src/main/java/com/google/devtools/build/lib/rules/test/StandaloneTestStrategy.java
index ddea658..a391a30 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/test/StandaloneTestStrategy.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/test/StandaloneTestStrategy.java
@@ -39,6 +39,7 @@
 
 import java.io.Closeable;
 import java.io.IOException;
+import java.util.HashMap;
 import java.util.Map;
 
 /**
@@ -76,16 +77,24 @@
         .getChild(getTmpDirName(action.getExecutionSettings().getExecutable().getExecPath()));
     Path workingDirectory = runfilesDir.getRelative(action.getRunfilesPrefix());
 
+
     TestRunnerAction.ResolvedPaths resolvedPaths =
         action.resolve(actionExecutionContext.getExecutor().getExecRoot());
     Map<String, String> env = getEnv(action, runfilesDir, testTmpDir, resolvedPaths);
+
+    Map<String, String> info = new HashMap<>();
+
+    // This key is only understood by StandaloneSpawnStrategy.
+    info.put("timeout", "" + getTimeout(action));
+    info.putAll(action.getTestProperties().getExecutionInfo());
+
     Spawn spawn =
         new BaseSpawn(
             // Bazel lacks much of the tooling for coverage, so we don't attempt to pass a coverage
             // script here.
             getArgs(TEST_SETUP, "", action),
             env,
-            action.getTestProperties().getExecutionInfo(),
+            info,
             action,
             action
                 .getTestProperties()
diff --git a/src/main/java/com/google/devtools/build/lib/standalone/StandaloneSpawnStrategy.java b/src/main/java/com/google/devtools/build/lib/standalone/StandaloneSpawnStrategy.java
index 0b034b4..92f7a3c 100644
--- a/src/main/java/com/google/devtools/build/lib/standalone/StandaloneSpawnStrategy.java
+++ b/src/main/java/com/google/devtools/build/lib/standalone/StandaloneSpawnStrategy.java
@@ -62,6 +62,16 @@
               + "]", spawn.asShellCommand(executor.getExecRoot()));
     }
 
+    int timeout = -1;
+    String timeoutStr = spawn.getExecutionInfo().get("timeout");
+    if (timeoutStr != null) {
+      try {
+        timeout = Integer.parseInt(timeoutStr);
+      } catch (NumberFormatException e) {
+        throw new UserExecException("could not parse timeout: " + e);
+      }
+    }
+
     // We must wrap the subprocess with process-wrapper to kill the process tree.
     // All actions therefore depend on the process-wrapper file. Since it's embedded,
     // we don't bother with declaring it as an input.
@@ -72,13 +82,13 @@
       // Disable it for now to make the setup easier and to avoid further PATH hacks.
       // Ideally we should have a native implementation of process-wrapper for Windows.
       args.add(processWrapper.getPathString());
-      args.add("-1"); /* timeout */
-      args.add("0");  /* kill delay. */
+      args.add("" + timeout);
+      args.add("5"); /* kill delay: give some time to print stacktraces and whatnot. */
 
       // TODO(bazel-team): use process-wrapper redirection so we don't have to
       // pass test logs through the Java heap.
-      args.add("-");  /* stdout. */
-      args.add("-");  /* stderr. */
+      args.add("-"); /* stdout. */
+      args.add("-"); /* stderr. */
     }
     args.addAll(spawn.getArguments());
 
diff --git a/src/test/shell/bazel/bazel_test_test.sh b/src/test/shell/bazel/bazel_test_test.sh
index 5f3d0d3..e186db3 100755
--- a/src/test/shell/bazel/bazel_test_test.sh
+++ b/src/test/shell/bazel/bazel_test_test.sh
@@ -175,4 +175,30 @@
   expect_log 'hello script!!! testing/t1'
 }
 
+function test_test_timeout() {
+  mkdir -p dir
+
+  cat <<EOF > dir/test.sh
+#!/bin/sh
+sleep 3
+exit 0
+
+EOF
+
+  chmod +x dir/test.sh
+
+  cat <<EOF > dir/BUILD
+  sh_test(
+    name = "test",
+    timeout = "short",
+    srcs = [ "test.sh" ],
+    size = "small",
+  )
+EOF
+
+  bazel test --test_timeout=2 //dir:test && fail "should have timed out"
+  bazel test --test_timeout=4 //dir:test || fail "expected success"
+
+}
+
 run_suite "test tests"