Allow test strategies to treat exclusive tests as regular parallel tests.
PiperOrigin-RevId: 292337914
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/AnalysisResult.java b/src/main/java/com/google/devtools/build/lib/analysis/AnalysisResult.java
index 01a490b..c4aedce 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/AnalysisResult.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/AnalysisResult.java
@@ -17,6 +17,7 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedSet;
+import com.google.common.collect.Sets;
import com.google.devtools.build.lib.actions.ActionGraph;
import com.google.devtools.build.lib.actions.PackageRoots;
import com.google.devtools.build.lib.analysis.config.BuildConfigurationCollection;
@@ -167,4 +168,27 @@
public ImmutableSortedSet<String> getNonSymlinkedDirectoriesUnderExecRoot() {
return nonSymlinkedDirectoriesUnderExecRoot;
}
+
+ /**
+ * Returns an equivalent {@link AnalysisResult}, except with exclusive tests treated as parallel
+ * tests.
+ */
+ public AnalysisResult withExclusiveTestsAsParallelTests() {
+ return new AnalysisResult(
+ configurations,
+ targetsToBuild,
+ aspects,
+ targetsToTest,
+ targetsToSkip,
+ error,
+ actionGraph,
+ topLevelArtifactsToOwnerLabels,
+ Sets.union(parallelTests, exclusiveTests).immutableCopy(),
+ /*exclusiveTests=*/ ImmutableSet.of(),
+ topLevelContext,
+ packageRoots,
+ workspaceName,
+ topLevelTargetsWithConfigs,
+ nonSymlinkedDirectoriesUnderExecRoot);
+ }
}
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/test/TestActionContext.java b/src/main/java/com/google/devtools/build/lib/analysis/test/TestActionContext.java
index 3ce4bac..a68ea8c 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/test/TestActionContext.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/test/TestActionContext.java
@@ -38,6 +38,17 @@
/** Returns whether test_keep_going is enabled. */
boolean isTestKeepGoing();
+ /**
+ * Returns {@code true} to indicate that exclusive tests should be treated as regular parallel
+ * tests.
+ *
+ * <p>Returning {@code true} may make sense for certain forced remote test execution strategies
+ * where running tests in sequence would be wasteful.
+ */
+ default boolean forceParallelTestExecution() {
+ return false;
+ }
+
/** Creates a cached test result. */
TestResult newCachedTestResult(Path execRoot, TestRunnerAction action, TestResultData cached)
throws IOException;
diff --git a/src/main/java/com/google/devtools/build/lib/buildtool/BuildTool.java b/src/main/java/com/google/devtools/build/lib/buildtool/BuildTool.java
index c667362..d625154 100644
--- a/src/main/java/com/google/devtools/build/lib/buildtool/BuildTool.java
+++ b/src/main/java/com/google/devtools/build/lib/buildtool/BuildTool.java
@@ -24,6 +24,7 @@
import com.google.devtools.build.lib.analysis.AnalysisResult;
import com.google.devtools.build.lib.analysis.BuildInfoEvent;
import com.google.devtools.build.lib.analysis.BuildView;
+import com.google.devtools.build.lib.analysis.ConfiguredTarget;
import com.google.devtools.build.lib.analysis.ViewCreationFailedException;
import com.google.devtools.build.lib.analysis.WorkspaceStatusAction.DummyEnvironment;
import com.google.devtools.build.lib.analysis.config.BuildOptions;
@@ -38,6 +39,7 @@
import com.google.devtools.build.lib.events.Event;
import com.google.devtools.build.lib.events.OutputFilter;
import com.google.devtools.build.lib.events.Reporter;
+import com.google.devtools.build.lib.exec.ExecutionOptions;
import com.google.devtools.build.lib.pkgcache.LoadingFailedException;
import com.google.devtools.build.lib.profiler.ProfilePhase;
import com.google.devtools.build.lib.profiler.Profiler;
@@ -147,6 +149,22 @@
// execution phase.
executionTool = new ExecutionTool(env, request);
if (request.getBuildOptions().performAnalysisPhase) {
+
+ if (!analysisResult.getExclusiveTests().isEmpty()
+ && executionTool.getTestActionContext().forceParallelTestExecution()) {
+ String testStrategy = request.getOptions(ExecutionOptions.class).testStrategy;
+ for (ConfiguredTarget test : analysisResult.getExclusiveTests()) {
+ getReporter()
+ .handle(
+ Event.warn(
+ test.getLabel()
+ + " is tagged exclusive, but --test_strategy="
+ + testStrategy
+ + " forces parallel test execution."));
+ }
+ analysisResult = analysisResult.withExclusiveTestsAsParallelTests();
+ }
+
result.setBuildConfigurationCollection(analysisResult.getConfigurationCollection());
result.setActualTargets(analysisResult.getTargetsToBuild());
result.setTestTargets(analysisResult.getTargetsToTest());
diff --git a/src/main/java/com/google/devtools/build/lib/buildtool/ExecutionTool.java b/src/main/java/com/google/devtools/build/lib/buildtool/ExecutionTool.java
index fc343e4..ce536e2 100644
--- a/src/main/java/com/google/devtools/build/lib/buildtool/ExecutionTool.java
+++ b/src/main/java/com/google/devtools/build/lib/buildtool/ExecutionTool.java
@@ -202,6 +202,10 @@
}
}
+ TestActionContext getTestActionContext() {
+ return spawnActionContextMaps.getContext(TestActionContext.class);
+ }
+
/**
* Performs the execution phase (phase 3) of the build, in which the Builder is applied to the
* action graph to bring the targets up to date. (This function will return prior to