Move TestStrategy to lib.exec package.

This is part of refactoring test strategy to unify its implementation between
Bazel and Blaze (Google's internal version of Bazel), which should fix several
issues in Bazel.

It's also necessary to untangle lib.rules and lib.exec to enforce proper
layering by separating compilation of these packages, and to provide a minimal
Bazel binary. In particular, no core part of Bazel should depend on any of the
rules, to facilitate moving them out of Bazel / reimplementing them in Skylark
(except for some core rules like test_suite, alias, and genquery).

--
PiperOrigin-RevId: 142151901
MOS_MIGRATED_REVID=142151901
diff --git a/src/main/java/com/google/devtools/build/lib/exec/ExecutionOptions.java b/src/main/java/com/google/devtools/build/lib/exec/ExecutionOptions.java
index 96597c0..dc823f2 100644
--- a/src/main/java/com/google/devtools/build/lib/exec/ExecutionOptions.java
+++ b/src/main/java/com/google/devtools/build/lib/exec/ExecutionOptions.java
@@ -14,16 +14,14 @@
 package com.google.devtools.build.lib.exec;
 
 import com.google.devtools.build.lib.actions.ResourceSet;
+import com.google.devtools.build.lib.exec.TestStrategy.TestOutputFormat;
+import com.google.devtools.build.lib.exec.TestStrategy.TestSummaryFormat;
 import com.google.devtools.build.lib.packages.TestTimeout;
-import com.google.devtools.build.lib.rules.test.TestStrategy;
-import com.google.devtools.build.lib.rules.test.TestStrategy.TestOutputFormat;
-import com.google.devtools.build.lib.rules.test.TestStrategy.TestSummaryFormat;
 import com.google.devtools.build.lib.util.OptionsUtils;
 import com.google.devtools.build.lib.vfs.PathFragment;
 import com.google.devtools.common.options.Option;
 import com.google.devtools.common.options.Options;
 import com.google.devtools.common.options.OptionsBase;
-
 import java.util.Map;
 
 /**
diff --git a/src/main/java/com/google/devtools/build/lib/rules/test/StandaloneTestStrategy.java b/src/main/java/com/google/devtools/build/lib/exec/StandaloneTestStrategy.java
similarity index 87%
rename from src/main/java/com/google/devtools/build/lib/rules/test/StandaloneTestStrategy.java
rename to src/main/java/com/google/devtools/build/lib/exec/StandaloneTestStrategy.java
index 05eeb7a..fb196cb 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/test/StandaloneTestStrategy.java
+++ b/src/main/java/com/google/devtools/build/lib/exec/StandaloneTestStrategy.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.devtools.build.lib.rules.test;
+package com.google.devtools.build.lib.exec;
 
 import com.google.common.collect.ImmutableSet;
 import com.google.devtools.build.lib.actions.ActionExecutionContext;
@@ -34,6 +34,9 @@
 import com.google.devtools.build.lib.events.Event;
 import com.google.devtools.build.lib.events.EventKind;
 import com.google.devtools.build.lib.events.Reporter;
+import com.google.devtools.build.lib.rules.test.TestActionContext;
+import com.google.devtools.build.lib.rules.test.TestResult;
+import com.google.devtools.build.lib.rules.test.TestRunnerAction;
 import com.google.devtools.build.lib.util.io.FileOutErr;
 import com.google.devtools.build.lib.vfs.Path;
 import com.google.devtools.build.lib.vfs.PathFragment;
@@ -46,10 +49,11 @@
 import java.util.HashMap;
 import java.util.Map;
 
-/**
- * Runs TestRunnerAction actions.
- */
-@ExecutionStrategy(contextType = TestActionContext.class, name = { "standalone" })
+/** Runs TestRunnerAction actions. */
+@ExecutionStrategy(
+  contextType = TestActionContext.class,
+  name = {"standalone"}
+)
 public class StandaloneTestStrategy extends TestStrategy {
   // TODO(bazel-team) - add tests for this strategy.
   public static final String COLLECT_COVERAGE =
@@ -193,13 +197,16 @@
     try {
       try {
         if (executionOptions.testOutput.equals(TestOutputFormat.STREAMED)) {
-          streamed = new StreamedTestOutput(
-              Reporter.outErrForReporter(
-                  actionExecutionContext.getExecutor().getEventHandler()), testLogPath);
+          streamed =
+              new StreamedTestOutput(
+                  Reporter.outErrForReporter(
+                      actionExecutionContext.getExecutor().getEventHandler()),
+                  testLogPath);
         }
         spawnActionContext.exec(spawn, actionExecutionContext);
 
-        builder.setTestPassed(true)
+        builder
+            .setTestPassed(true)
             .setStatus(BlazeTestStatus.PASSED)
             .setCachable(true)
             .setPassedLog(testLogPath.getPathString());
@@ -224,12 +231,15 @@
         }
       }
 
-      TestCase details = parseTestResult(
-          action.resolve(actionExecutionContext.getExecutor().getExecRoot()).getXmlOutputPath());
+      TestCase details =
+          parseTestResult(
+              action
+                  .resolve(actionExecutionContext.getExecutor().getExecRoot())
+                  .getXmlOutputPath());
       if (details != null) {
         builder.setTestCase(details);
       }
-      
+
       if (isCoverageMode(action)) {
         builder.setHasCoverage(true);
       }
@@ -258,24 +268,30 @@
         executor.getEventHandler().handle(Event.of(EventKind.PASS, null, result.getTestName()));
       } else {
         if (result.getData().getStatus() == BlazeTestStatus.TIMEOUT) {
-          executor.getEventHandler().handle(
-              Event.of(EventKind.TIMEOUT, null, result.getTestName()
-                  + " (see " + testOutput + ")"));
+          executor
+              .getEventHandler()
+              .handle(
+                  Event.of(
+                      EventKind.TIMEOUT, null, result.getTestName() + " (see " + testOutput + ")"));
         } else {
-          executor.getEventHandler().handle(
-              Event.of(EventKind.FAIL, null, result.getTestName() + " (see " + testOutput + ")"));
+          executor
+              .getEventHandler()
+              .handle(
+                  Event.of(
+                      EventKind.FAIL, null, result.getTestName() + " (see " + testOutput + ")"));
         }
       }
     }
   }
 
-  private final void finalizeTest(ActionExecutionContext actionExecutionContext,
-      TestRunnerAction action, TestResultData data) throws IOException, ExecException {
+  private final void finalizeTest(
+      ActionExecutionContext actionExecutionContext, TestRunnerAction action, TestResultData data)
+      throws IOException, ExecException {
     TestResult result = new TestResult(action, data, false);
     postTestResult(actionExecutionContext.getExecutor(), result);
 
-    processTestOutput(actionExecutionContext.getExecutor(),
-        actionExecutionContext.getFileOutErr(), result);
+    processTestOutput(
+        actionExecutionContext.getExecutor(), actionExecutionContext.getFileOutErr(), result);
     // TODO(bazel-team): handle --test_output=errors, --test_output=all.
 
     if (!executionOptions.testKeepGoing && data.getStatus() != BlazeTestStatus.PASSED) {
diff --git a/src/main/java/com/google/devtools/build/lib/rules/test/TestLogHelper.java b/src/main/java/com/google/devtools/build/lib/exec/TestLogHelper.java
similarity index 79%
rename from src/main/java/com/google/devtools/build/lib/rules/test/TestLogHelper.java
rename to src/main/java/com/google/devtools/build/lib/exec/TestLogHelper.java
index 49ed2ab..65d1d61 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/test/TestLogHelper.java
+++ b/src/main/java/com/google/devtools/build/lib/exec/TestLogHelper.java
@@ -11,12 +11,11 @@
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 // See the License for the specific language governing permissions and
 // limitations under the License.
-package com.google.devtools.build.lib.rules.test;
+package com.google.devtools.build.lib.exec;
 
 import com.google.common.io.ByteStreams;
-import com.google.devtools.build.lib.rules.test.TestStrategy.TestOutputFormat;
+import com.google.devtools.build.lib.exec.TestStrategy.TestOutputFormat;
 import com.google.devtools.build.lib.vfs.Path;
-
 import java.io.BufferedOutputStream;
 import java.io.FilterOutputStream;
 import java.io.IOException;
@@ -25,36 +24,34 @@
 import java.io.PrintStream;
 
 /**
- * A helper class for test log handling. It determines whether the test log should
- * be output and formats the test log for console display.
+ * A helper class for test log handling. It determines whether the test log should be output and
+ * formats the test log for console display.
  */
 public class TestLogHelper {
 
   public static final String HEADER_DELIMITER =
-    "-----------------------------------------------------------------------------";
+      "-----------------------------------------------------------------------------";
 
   /**
-   * Determines whether the test log should be output from the current outputMode
-   * and whether the test has passed or not.
+   * Determines whether the test log should be output from the current outputMode and whether the
+   * test has passed or not.
    */
   public static boolean shouldOutputTestLog(TestOutputFormat outputMode, boolean hasPassed) {
-    return (outputMode == TestOutputFormat.ALL) ||
-      (!hasPassed && (outputMode == TestOutputFormat.ERRORS));
+    return (outputMode == TestOutputFormat.ALL)
+        || (!hasPassed && (outputMode == TestOutputFormat.ERRORS));
   }
 
   /**
-   * Reads the contents of the test log from the provided testOutput file, adds
-   * header and footer and returns the result.
-   * This method also looks for a header delimiter and cuts off the text before it,
-   * except if the header is 50 lines or longer.
+   * Reads the contents of the test log from the provided testOutput file, adds header and footer
+   * and returns the result. This method also looks for a header delimiter and cuts off the text
+   * before it, except if the header is 50 lines or longer.
    */
   public static void writeTestLog(Path testOutput, String testName, OutputStream out)
       throws IOException {
     InputStream input = null;
     PrintStream printOut = new PrintStream(new BufferedOutputStream(out));
     try {
-      final String outputHeader =
-          "==================== Test output for " + testName + ":";
+      final String outputHeader = "==================== Test output for " + testName + ":";
       final String outputFooter =
           "================================================================================";
 
@@ -81,8 +78,8 @@
   }
 
   /**
-   * Returns an output stream that doesn't write to original until it
-   * sees HEADER_DELIMITER by itself on a line.
+   * Returns an output stream that doesn't write to original until it sees HEADER_DELIMITER by
+   * itself on a line.
    */
   public static FilterTestHeaderOutputStream getHeaderFilteringOutputStream(OutputStream original) {
     return new FilterTestHeaderOutputStream(original);
@@ -92,10 +89,7 @@
     // Prevent Java from creating a public constructor.
   }
 
-  /**
-   * Use this class to filter the streaming output of a test until we see the
-   * header delimiter.
-   */
+  /** Use this class to filter the streaming output of a test until we see the header delimiter. */
   public static class FilterTestHeaderOutputStream extends FilterOutputStream {
 
     private boolean seenDelimiter = false;
diff --git a/src/main/java/com/google/devtools/build/lib/rules/test/TestStrategy.java b/src/main/java/com/google/devtools/build/lib/exec/TestStrategy.java
similarity index 87%
rename from src/main/java/com/google/devtools/build/lib/rules/test/TestStrategy.java
rename to src/main/java/com/google/devtools/build/lib/exec/TestStrategy.java
index ee6d670..96d8798 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/test/TestStrategy.java
+++ b/src/main/java/com/google/devtools/build/lib/exec/TestStrategy.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.devtools.build.lib.rules.test;
+package com.google.devtools.build.lib.exec;
 
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.collect.ImmutableMap;
@@ -25,10 +25,12 @@
 import com.google.devtools.build.lib.actions.Executor;
 import com.google.devtools.build.lib.analysis.config.BinTools;
 import com.google.devtools.build.lib.events.Event;
-import com.google.devtools.build.lib.exec.ExecutionOptions;
-import com.google.devtools.build.lib.exec.SymlinkTreeHelper;
 import com.google.devtools.build.lib.profiler.Profiler;
 import com.google.devtools.build.lib.profiler.ProfilerTask;
+import com.google.devtools.build.lib.rules.test.TestActionContext;
+import com.google.devtools.build.lib.rules.test.TestResult;
+import com.google.devtools.build.lib.rules.test.TestRunnerAction;
+import com.google.devtools.build.lib.rules.test.TestTargetExecutionSettings;
 import com.google.devtools.build.lib.util.OS;
 import com.google.devtools.build.lib.util.ShellEscaper;
 import com.google.devtools.build.lib.util.io.FileWatcher;
@@ -54,27 +56,24 @@
 import java.util.Map;
 import javax.annotation.Nullable;
 
-/**
- * A strategy for executing a {@link TestRunnerAction}.
- */
+/** A strategy for executing a {@link TestRunnerAction}. */
 public abstract class TestStrategy implements TestActionContext {
   public static final PathFragment COVERAGE_TMP_ROOT = new PathFragment("_coverage");
 
   public static final String TEST_SETUP_BASENAME = "test-setup.sh";
 
-  /**
-   * Returns true if coverage data should be gathered.
-   */
+  /** Returns true if coverage data should be gathered. */
   protected static boolean isCoverageMode(TestRunnerAction action) {
     return action.getCoverageData() != null;
   }
 
   /**
-   * Ensures that all directories used to run test are in the correct state and
-   * their content will not result in stale files.
+   * Ensures that all directories used to run test are in the correct state and their content will
+   * not result in stale files.
    */
-  protected void prepareFileSystem(TestRunnerAction testAction, Path tmpDir,
-      Path coverageDir, Path workingDirectory) throws IOException {
+  protected void prepareFileSystem(
+      TestRunnerAction testAction, Path tmpDir, Path coverageDir, Path workingDirectory)
+      throws IOException {
     if (isCoverageMode(testAction)) {
       recreateDirectory(coverageDir);
     }
@@ -82,17 +81,13 @@
     FileSystemUtils.createDirectoryAndParents(workingDirectory);
   }
 
-  /**
-   * Removes directory if it exists and recreates it.
-   */
+  /** Removes directory if it exists and recreates it. */
   protected void recreateDirectory(Path directory) throws IOException {
     FileSystemUtils.deleteTree(directory);
     FileSystemUtils.createDirectoryAndParents(directory);
   }
 
-  /**
-   * Converter for the --flaky_test_attempts option.
-   */
+  /** Converter for the --flaky_test_attempts option. */
   public static class TestAttemptsConverter extends RangeConverter {
     public TestAttemptsConverter() {
       super(1, 10);
@@ -119,9 +114,7 @@
     ALL, // Print output from all tests to the stderr after the test completion.
     STREAMED; // Stream output for each test.
 
-    /**
-     * Converts to {@link TestOutputFormat}.
-     */
+    /** Converts to {@link TestOutputFormat}. */
     public static class Converter extends EnumConverter<TestOutputFormat> {
       public Converter() {
         super(TestOutputFormat.class, "test output");
@@ -135,9 +128,7 @@
     DETAILED, // Print information only about failed test cases.
     NONE; // Do not print summary.
 
-    /**
-     * Converts to {@link TestSummaryFormat}.
-     */
+    /** Converts to {@link TestSummaryFormat}. */
     public static class Converter extends EnumConverter<TestSummaryFormat> {
       public Converter() {
         super(TestSummaryFormat.class, "test summary");
@@ -182,9 +173,9 @@
    * path within coverage directory.
    *
    * <p>Coverage directory name for the given test runner action is constructed as: {@code $(blaze
-   * info execution_root)/_coverage/target_path/test_log_name} where {@code test_log_name}
-   * is usually a target name but potentially can include extra suffix, such as a shard number (if
-   * test execution was sharded).
+   * info execution_root)/_coverage/target_path/test_log_name} where {@code test_log_name} is
+   * usually a target name but potentially can include extra suffix, such as a shard number (if test
+   * execution was sharded).
    */
   protected static PathFragment getCoverageDirectory(TestRunnerAction action) {
     return COVERAGE_TMP_ROOT.getRelative(
@@ -207,8 +198,8 @@
 
     if (action.isSharded()) {
       env.put("TEST_SHARD_INDEX", Integer.toString(action.getShardNum()));
-      env.put("TEST_TOTAL_SHARDS",
-          Integer.toString(action.getExecutionSettings().getTotalShards()));
+      env.put(
+          "TEST_TOTAL_SHARDS", Integer.toString(action.getExecutionSettings().getTotalShards()));
     }
 
     // When we run test multiple times, set different TEST_RANDOM_SEED values for each run.
@@ -234,12 +225,12 @@
   }
 
   /**
-   * Generates a command line to run for the test action, taking into account coverage
-   * and {@code --run_under} settings.
+   * Generates a command line to run for the test action, taking into account coverage and {@code
+   * --run_under} settings.
    *
-   * @param testScript  the setup script that invokes the test
-   * @param coverageScript a script interjected between setup script and rest of command line
-   * to collect coverage data. If this is an empty string, it is ignored.
+   * @param testScript the setup script that invokes the test
+   * @param coverageScript a script interjected between setup script and rest of command line to
+   *     collect coverage data. If this is an empty string, it is ignored.
    * @param testAction The test action.
    * @return the command line as string list.
    */
@@ -324,9 +315,8 @@
   /**
    * Returns a subset of the environment from the current shell.
    *
-   * <p>Warning: Since these variables are not part of the configuration's fingerprint, they
-   * MUST NOT be used by any rule or action in such a way as to affect the semantics of that
-   * build step.
+   * <p>Warning: Since these variables are not part of the configuration's fingerprint, they MUST
+   * NOT be used by any rule or action in such a way as to affect the semantics of that build step.
    */
   public Map<String, String> getAdmissibleShellEnvironment(Iterable<String> variables) {
     return getMapping(variables, clientEnv);
@@ -343,11 +333,10 @@
   /**
    * Returns a unique name for a temporary directory a test could use.
    *
-   * <p>Since each test within single Blaze run must have a unique TEST_TMPDIR,
-   * we will use rule name and a unique (within single Blaze request) number
-   * to generate directory name.</p>
+   * <p>Since each test within single Blaze run must have a unique TEST_TMPDIR, we will use rule
+   * name and a unique (within single Blaze request) number to generate directory name.
    *
-   * <p>This does not create the directory.</p>
+   * <p>This does not create the directory.
    */
   protected String getTmpDirName(PathFragment execPath) {
     String basename = execPath.getBaseName();
@@ -359,13 +348,11 @@
     }
   }
 
-  /**
-   * Parse a test result XML file into a {@link TestCase}.
-   */
+  /** Parse a test result XML file into a {@link TestCase}. */
   @Nullable
   protected TestCase parseTestResult(Path resultFile) {
     /* xml files. We avoid parsing it unnecessarily, since test results can potentially consume
-     a large amount of memory. */
+    a large amount of memory. */
     if (executionOptions.testSummary != TestSummaryFormat.DETAILED) {
       return null;
     }
@@ -382,7 +369,7 @@
    * create child directories to actually use.
    *
    * <p>This either dynamically generates a directory name or uses the directory specified by
-   * --test_tmpdir. This does not create the directory.</p>
+   * --test_tmpdir. This does not create the directory.
    */
   public static Path getTmpRoot(Path workspace, Path execRoot, ExecutionOptions executionOptions) {
     return executionOptions.testTmpDir != null
@@ -395,8 +382,8 @@
    * are defined in the given environment.
    */
   @VisibleForTesting
-  public static Map<String, String> getMapping(Iterable<String> variables,
-      Map<String, String> environment) {
+  public static Map<String, String> getMapping(
+      Iterable<String> variables, Map<String, String> environment) {
     Map<String, String> result = new HashMap<>();
     for (String var : variables) {
       if (environment.containsKey(var)) {
@@ -407,8 +394,8 @@
   }
 
   /**
-   * Returns the runfiles directory associated with the test executable,
-   * creating/updating it if necessary and --build_runfile_links is specified.
+   * Returns the runfiles directory associated with the test executable, creating/updating it if
+   * necessary and --build_runfile_links is specified.
    */
   protected static Path getLocalRunfilesDirectory(
       TestRunnerAction testAction,
@@ -470,7 +457,8 @@
     try {
       // Avoid rebuilding the runfiles directory if the manifest in it matches the input manifest,
       // implying the symlinks exist and are already up to date.
-      if (Arrays.equals(runfilesDir.getRelative("MANIFEST").getDigest(),
+      if (Arrays.equals(
+          runfilesDir.getRelative("MANIFEST").getDigest(),
           execSettings.getInputManifest().getPath().getDigest())) {
         return;
       }
@@ -478,26 +466,22 @@
       // Ignore it - we will just try to create runfiles directory.
     }
 
-    executor.getEventHandler().handle(Event.progress(
-        "Building runfiles directory for '" + execSettings.getExecutable().prettyPrint() + "'."));
+    executor
+        .getEventHandler()
+        .handle(
+            Event.progress(
+                "Building runfiles directory for '"
+                    + execSettings.getExecutable().prettyPrint()
+                    + "'."));
 
-    new SymlinkTreeHelper(
-            execSettings.getInputManifest().getPath(),
-            runfilesDir,
-            false)
+    new SymlinkTreeHelper(execSettings.getInputManifest().getPath(), runfilesDir, false)
         .createSymlinks(
-            testAction,
-            actionExecutionContext,
-            binTools,
-            shellEnvironment,
-            enableRunfiles);
+            testAction, actionExecutionContext, binTools, shellEnvironment, enableRunfiles);
 
     executor.getEventHandler().handle(Event.progress(testAction.getProgressMessage()));
   }
 
-  /**
-   * In rare cases, we might write something to stderr. Append it to the real test.log.
-   */
+  /** In rare cases, we might write something to stderr. Append it to the real test.log. */
   protected static void appendStderr(Path stdOut, Path stdErr) throws IOException {
     FileStatus stat = stdErr.statNullable();
     OutputStream out = null;
@@ -520,9 +504,7 @@
     }
   }
 
-  /**
-   * Implements the --test_output=streamed option.
-   */
+  /** Implements the --test_output=streamed option. */
   protected static class StreamedTestOutput implements Closeable {
     private final TestLogHelper.FilterTestHeaderOutputStream headerFilter;
     private final FileWatcher watcher;
@@ -556,5 +538,4 @@
       }
     }
   }
-
 }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/test/TestXmlOutputParser.java b/src/main/java/com/google/devtools/build/lib/exec/TestXmlOutputParser.java
similarity index 88%
rename from src/main/java/com/google/devtools/build/lib/rules/test/TestXmlOutputParser.java
rename to src/main/java/com/google/devtools/build/lib/exec/TestXmlOutputParser.java
index 7e1e503..277a87d 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/test/TestXmlOutputParser.java
+++ b/src/main/java/com/google/devtools/build/lib/exec/TestXmlOutputParser.java
@@ -12,27 +12,24 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.devtools.build.lib.rules.test;
+package com.google.devtools.build.lib.exec;
 
 import com.google.common.collect.ImmutableSet;
 import com.google.devtools.build.lib.view.test.TestStatus.TestCase;
 import com.google.devtools.build.lib.view.test.TestStatus.TestCase.Type;
 import com.google.protobuf.UninitializedMessageException;
-
 import java.io.InputStream;
 import java.util.Collection;
-
 import javax.xml.stream.XMLInputFactory;
 import javax.xml.stream.XMLStreamConstants;
 import javax.xml.stream.XMLStreamException;
 import javax.xml.stream.XMLStreamReader;
 
 /**
- * Parses a test.xml generated by jUnit or any testing framework
- * into a protocol buffer. The schema of the test.xml is a bit hazy, so there is
- * some guesswork involved.
+ * Parses a test.xml generated by jUnit or any testing framework into a protocol buffer. The schema
+ * of the test.xml is a bit hazy, so there is some guesswork involved.
  */
-class TestXmlOutputParser {
+final class TestXmlOutputParser {
   // jUnit can use either "testsuites" or "testsuite".
   private static final Collection<String> TOPLEVEL_ELEMENT_NAMES =
       ImmutableSet.of("testsuites", "testsuite");
@@ -44,14 +41,13 @@
 
   /**
    * Parses the a test result XML file into the corresponding protocol buffer.
-   * @param xmlStream the XML data stream
-   * @return the protocol buffer with the parsed data, or null if there was
-   * an error while parsing the file.
    *
+   * @param xmlStream the XML data stream
+   * @return the protocol buffer with the parsed data, or null if there was an error while parsing
+   *     the file.
    * @throws TestXmlOutputParserException when the XML file cannot be parsed
    */
-  private TestCase parseXmlToTree(InputStream xmlStream)
-      throws TestXmlOutputParserException {
+  private TestCase parseXmlToTree(InputStream xmlStream) throws TestXmlOutputParserException {
     XMLStreamReader parser = null;
 
     try {
@@ -74,12 +70,13 @@
       }
     } catch (XMLStreamException e) {
       throw new TestXmlOutputParserException(e);
-    }  catch (NumberFormatException e) {
+    } catch (NumberFormatException e) {
       // The parser is definitely != null here.
       throw new TestXmlOutputParserException(
           "Number could not be parsed at "
-          + parser.getLocation().getLineNumber() + ":"
-          + parser.getLocation().getColumnNumber(),
+              + parser.getLocation().getLineNumber()
+              + ":"
+              + parser.getLocation().getColumnNumber(),
           e);
     } catch (UninitializedMessageException e) {
       // This happens when the XML does not contain a field that is required
@@ -116,17 +113,21 @@
   }
 
   /**
-   * Creates an exception suitable to be thrown when and a bad end tag appears.
-   * The exception could also be thrown from here but that would result in an
-   * extra stack frame, whereas this way, the topmost frame shows the location
-   * where the error occurred.
+   * Creates an exception suitable to be thrown when and a bad end tag appears. The exception could
+   * also be thrown from here but that would result in an extra stack frame, whereas this way, the
+   * topmost frame shows the location where the error occurred.
    */
   private TestXmlOutputParserException createBadElementException(
       String expected, XMLStreamReader parser) {
-    return new TestXmlOutputParserException("Expected end of XML element '"
-        + expected + "' , but got '" + parser.getLocalName() + "' at "
-        + parser.getLocation().getLineNumber() + ":"
-        + parser.getLocation().getColumnNumber());
+    return new TestXmlOutputParserException(
+        "Expected end of XML element '"
+            + expected
+            + "' , but got '"
+            + parser.getLocalName()
+            + "' at "
+            + parser.getLocation().getLineNumber()
+            + ":"
+            + parser.getLocation().getColumnNumber());
   }
 
   /**
@@ -134,8 +135,7 @@
    *
    * @throws TestXmlOutputParserException if the XML document is malformed
    * @throws XMLStreamException if there was an error processing the XML
-   * @throws NumberFormatException if one of the numeric fields does not contain
-   *         a valid number
+   * @throws NumberFormatException if one of the numeric fields does not contain a valid number
    */
   private TestCase parseTestSuite(XMLStreamReader parser, String elementName)
       throws XMLStreamException, TestXmlOutputParserException {
@@ -159,8 +159,8 @@
   /**
    * Parses a time in test.xml format.
    *
-   * @throws NumberFormatException if the time is malformed (i.e. is neither an
-   * integer nor a decimal fraction with '.' as the fraction separator)
+   * @throws NumberFormatException if the time is malformed (i.e. is neither an integer nor a
+   *     decimal fraction with '.' as the fraction separator)
    */
   private long parseTime(String string) {
 
@@ -179,8 +179,7 @@
    *
    * @throws TestXmlOutputParserException if the XML document is malformed
    * @throws XMLStreamException if there was an error processing the XML
-   * @throws NumberFormatException if one of the numeric fields does not contain
-   *         a valid number
+   * @throws NumberFormatException if one of the numeric fields does not contain a valid number
    */
   private TestCase parseTestDecorator(XMLStreamReader parser)
       throws XMLStreamException, TestXmlOutputParserException {
@@ -203,15 +202,13 @@
   }
 
   /**
-   * Parses child elements of the specified tag. Strictly speaking, not every
-   * element can be a child of every other, but the HierarchicalTestResult can
-   * handle that, and (in this case) it does not hurt to be a bit more flexible
-   * than necessary.
+   * Parses child elements of the specified tag. Strictly speaking, not every element can be a child
+   * of every other, but the HierarchicalTestResult can handle that, and (in this case) it does not
+   * hurt to be a bit more flexible than necessary.
    *
    * @throws TestXmlOutputParserException if the XML document is malformed
    * @throws XMLStreamException if there was an error processing the XML
-   * @throws NumberFormatException if one of the numeric fields does not contain
-   *         a valid number
+   * @throws NumberFormatException if one of the numeric fields does not contain a valid number
    */
   private void parseContainedElements(
       XMLStreamReader parser, String elementName, TestCase.Builder builder)
@@ -284,14 +281,12 @@
     }
   }
 
-
   /**
    * Parses a 'testcase' element.
    *
    * @throws TestXmlOutputParserException if the XML document is malformed
    * @throws XMLStreamException if there was an error processing the XML
-   * @throws NumberFormatException if the time field does not contain a valid
-   *         number
+   * @throws NumberFormatException if the time field does not contain a valid number
    */
   private TestCase parseTestCase(XMLStreamReader parser)
       throws XMLStreamException, TestXmlOutputParserException {
@@ -331,8 +326,7 @@
   }
 
   /**
-   * Skips over a complete XML element on the input.
-   * Precondition: the cursor is at a START_ELEMENT.
+   * Skips over a complete XML element on the input. Precondition: the cursor is at a START_ELEMENT.
    * Postcondition: the cursor is at an END_ELEMENT.
    *
    * @throws XMLStreamException if the XML is malformed
diff --git a/src/main/java/com/google/devtools/build/lib/rules/test/TestXmlOutputParserException.java b/src/main/java/com/google/devtools/build/lib/exec/TestXmlOutputParserException.java
similarity index 81%
rename from src/main/java/com/google/devtools/build/lib/rules/test/TestXmlOutputParserException.java
rename to src/main/java/com/google/devtools/build/lib/exec/TestXmlOutputParserException.java
index 2650ff9..ca5b274 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/test/TestXmlOutputParserException.java
+++ b/src/main/java/com/google/devtools/build/lib/exec/TestXmlOutputParserException.java
@@ -12,13 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.devtools.build.lib.rules.test;
+package com.google.devtools.build.lib.exec;
 
-/**
- * This exception gets thrown if there was a problem with parsing a test.xml
- * file.
- */
-class TestXmlOutputParserException extends Exception {
+/** This exception gets thrown if there was a problem with parsing a test.xml file. */
+final class TestXmlOutputParserException extends Exception {
   public TestXmlOutputParserException(String message, Throwable cause) {
     super(message, cause);
   }
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/TerminalTestResultNotifier.java b/src/main/java/com/google/devtools/build/lib/runtime/TerminalTestResultNotifier.java
index a6d6a08..36c2bfc 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/TerminalTestResultNotifier.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/TerminalTestResultNotifier.java
@@ -14,17 +14,16 @@
 package com.google.devtools.build.lib.runtime;
 
 import com.google.devtools.build.lib.exec.ExecutionOptions;
-import com.google.devtools.build.lib.rules.test.TestLogHelper;
+import com.google.devtools.build.lib.exec.TestLogHelper;
+import com.google.devtools.build.lib.exec.TestStrategy.TestOutputFormat;
+import com.google.devtools.build.lib.exec.TestStrategy.TestSummaryFormat;
 import com.google.devtools.build.lib.rules.test.TestResult;
-import com.google.devtools.build.lib.rules.test.TestStrategy.TestOutputFormat;
-import com.google.devtools.build.lib.rules.test.TestStrategy.TestSummaryFormat;
 import com.google.devtools.build.lib.util.StringUtil;
 import com.google.devtools.build.lib.util.io.AnsiTerminalPrinter;
 import com.google.devtools.build.lib.view.test.TestStatus.BlazeTestStatus;
 import com.google.devtools.common.options.Option;
 import com.google.devtools.common.options.OptionsBase;
 import com.google.devtools.common.options.OptionsProvider;
-
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/TestSummaryPrinter.java b/src/main/java/com/google/devtools/build/lib/runtime/TestSummaryPrinter.java
index ae6e393..2acea95 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/TestSummaryPrinter.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/TestSummaryPrinter.java
@@ -15,8 +15,8 @@
 
 import com.google.common.base.Joiner;
 import com.google.common.base.Strings;
-import com.google.devtools.build.lib.rules.test.TestLogHelper;
-import com.google.devtools.build.lib.rules.test.TestStrategy.TestOutputFormat;
+import com.google.devtools.build.lib.exec.TestLogHelper;
+import com.google.devtools.build.lib.exec.TestStrategy.TestOutputFormat;
 import com.google.devtools.build.lib.util.LoggingUtil;
 import com.google.devtools.build.lib.util.io.AnsiTerminalPrinter;
 import com.google.devtools.build.lib.util.io.AnsiTerminalPrinter.Mode;
@@ -24,7 +24,6 @@
 import com.google.devtools.build.lib.view.test.TestStatus.BlazeTestStatus;
 import com.google.devtools.build.lib.view.test.TestStatus.FailedTestCasesStatus;
 import com.google.devtools.build.lib.view.test.TestStatus.TestCase;
-
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/commands/TestCommand.java b/src/main/java/com/google/devtools/build/lib/runtime/commands/TestCommand.java
index 3c2c70f..fe9715c 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/commands/TestCommand.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/commands/TestCommand.java
@@ -21,8 +21,8 @@
 import com.google.devtools.build.lib.buildtool.BuildTool;
 import com.google.devtools.build.lib.events.Event;
 import com.google.devtools.build.lib.exec.ExecutionOptions;
-import com.google.devtools.build.lib.rules.test.TestStrategy;
-import com.google.devtools.build.lib.rules.test.TestStrategy.TestOutputFormat;
+import com.google.devtools.build.lib.exec.TestStrategy;
+import com.google.devtools.build.lib.exec.TestStrategy.TestOutputFormat;
 import com.google.devtools.build.lib.runtime.AggregatingTestListener;
 import com.google.devtools.build.lib.runtime.BlazeCommand;
 import com.google.devtools.build.lib.runtime.BlazeCommandEventHandler;
@@ -40,7 +40,6 @@
 import com.google.devtools.common.options.OptionsParser;
 import com.google.devtools.common.options.OptionsParsingException;
 import com.google.devtools.common.options.OptionsProvider;
-
 import java.util.Collection;
 import java.util.List;
 
diff --git a/src/main/java/com/google/devtools/build/lib/standalone/StandaloneActionContextProvider.java b/src/main/java/com/google/devtools/build/lib/standalone/StandaloneActionContextProvider.java
index 92690c2..94b9d0d 100644
--- a/src/main/java/com/google/devtools/build/lib/standalone/StandaloneActionContextProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/standalone/StandaloneActionContextProvider.java
@@ -25,15 +25,14 @@
 import com.google.devtools.build.lib.buildtool.BuildRequest;
 import com.google.devtools.build.lib.exec.ExecutionOptions;
 import com.google.devtools.build.lib.exec.FileWriteStrategy;
+import com.google.devtools.build.lib.exec.StandaloneTestStrategy;
 import com.google.devtools.build.lib.rules.cpp.IncludeScanningContext;
 import com.google.devtools.build.lib.rules.cpp.SpawnGccStrategy;
 import com.google.devtools.build.lib.rules.cpp.SpawnLinkStrategy;
 import com.google.devtools.build.lib.rules.test.ExclusiveTestStrategy;
-import com.google.devtools.build.lib.rules.test.StandaloneTestStrategy;
 import com.google.devtools.build.lib.rules.test.TestActionContext;
 import com.google.devtools.build.lib.runtime.CommandEnvironment;
 import com.google.devtools.build.lib.vfs.FileSystemUtils;
-
 import java.io.IOException;
 
 /**
diff --git a/src/main/java/com/google/devtools/build/lib/worker/WorkerTestStrategy.java b/src/main/java/com/google/devtools/build/lib/worker/WorkerTestStrategy.java
index c090c2e..cf07306 100644
--- a/src/main/java/com/google/devtools/build/lib/worker/WorkerTestStrategy.java
+++ b/src/main/java/com/google/devtools/build/lib/worker/WorkerTestStrategy.java
@@ -27,7 +27,7 @@
 import com.google.devtools.build.lib.actions.Executor;
 import com.google.devtools.build.lib.actions.TestExecException;
 import com.google.devtools.build.lib.events.Event;
-import com.google.devtools.build.lib.rules.test.StandaloneTestStrategy;
+import com.google.devtools.build.lib.exec.StandaloneTestStrategy;
 import com.google.devtools.build.lib.rules.test.TestActionContext;
 import com.google.devtools.build.lib.rules.test.TestRunnerAction;
 import com.google.devtools.build.lib.runtime.CommandEnvironment;