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