Add execution information to standalone test results.
In StandaloneTestStrategy, copy as much information as SpawnResult makes
available to us through to both the TestResultData and BEP's
TestResult.ExecutionInfo protos. One immediate consequence is that the UI and
BEP can tell you whether a test result was cached remotely.
I changed Executor.getEventHandler to return an ExtendedEventHandler because it
makes this change easier to test.
Closes #5081.
Change-Id: I94fefdcd2e029c81085076736ad13a4bdf1bae8f
PiperOrigin-RevId: 194383009
diff --git a/src/main/java/com/google/devtools/build/lib/actions/ActionExecutionContext.java b/src/main/java/com/google/devtools/build/lib/actions/ActionExecutionContext.java
index a75ee38..cd5085d 100644
--- a/src/main/java/com/google/devtools/build/lib/actions/ActionExecutionContext.java
+++ b/src/main/java/com/google/devtools/build/lib/actions/ActionExecutionContext.java
@@ -22,8 +22,8 @@
import com.google.devtools.build.lib.clock.Clock;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.events.Event;
-import com.google.devtools.build.lib.events.EventHandler;
import com.google.devtools.build.lib.events.EventKind;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
import com.google.devtools.build.lib.util.io.FileOutErr;
import com.google.devtools.build.lib.vfs.FileSystem;
import com.google.devtools.build.lib.vfs.Path;
@@ -172,7 +172,7 @@
return executor.getEventBus();
}
- public EventHandler getEventHandler() {
+ public ExtendedEventHandler getEventHandler() {
return executor.getEventHandler();
}
diff --git a/src/main/java/com/google/devtools/build/lib/actions/Executor.java b/src/main/java/com/google/devtools/build/lib/actions/Executor.java
index 3dc0e5d..5511052 100644
--- a/src/main/java/com/google/devtools/build/lib/actions/Executor.java
+++ b/src/main/java/com/google/devtools/build/lib/actions/Executor.java
@@ -15,7 +15,7 @@
import com.google.common.eventbus.EventBus;
import com.google.devtools.build.lib.clock.Clock;
-import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
import com.google.devtools.build.lib.vfs.FileSystem;
import com.google.devtools.build.lib.vfs.Path;
import com.google.devtools.common.options.OptionsClassProvider;
@@ -77,10 +77,10 @@
boolean reportsSubcommands();
/**
- * An event listener to report messages to. Errors that signal a action failure should
- * use ActionExecutionException.
+ * An event listener to report messages to. Errors that signal a action failure should use
+ * ActionExecutionException.
*/
- EventHandler getEventHandler();
+ ExtendedEventHandler getEventHandler();
/**
* Looks up and returns an action context implementation of the given interface type.
diff --git a/src/main/java/com/google/devtools/build/lib/exec/StandaloneTestResult.java b/src/main/java/com/google/devtools/build/lib/exec/StandaloneTestResult.java
index d94e131..58d0575 100644
--- a/src/main/java/com/google/devtools/build/lib/exec/StandaloneTestResult.java
+++ b/src/main/java/com/google/devtools/build/lib/exec/StandaloneTestResult.java
@@ -17,6 +17,7 @@
import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableList;
import com.google.devtools.build.lib.actions.SpawnResult;
+import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos;
import com.google.devtools.build.lib.view.test.TestStatus.TestResultData;
import java.util.List;
@@ -30,17 +31,13 @@
/** Returns the TestResultData for the test. */
public abstract TestResultData testResultData();
+ public abstract BuildEventStreamProtos.TestResult.ExecutionInfo executionInfo();
+
/** Returns a builder that can be used to construct a {@link StandaloneTestResult} object. */
public static Builder builder() {
return new AutoValue_StandaloneTestResult.Builder();
}
- /** Creates a StandaloneTestResult, given spawnResults and testResultData. */
- public static StandaloneTestResult create(
- List<SpawnResult> spawnResults, TestResultData testResultData) {
- return builder().setSpawnResults(spawnResults).setTestResultData(testResultData).build();
- }
-
/** Builder for a {@link StandaloneTestResult} instance, which is immutable once built. */
@AutoValue.Builder
public abstract static class Builder {
@@ -54,6 +51,9 @@
/** Sets the TestResultData for the test. */
public abstract Builder setTestResultData(TestResultData testResultData);
+ public abstract Builder setExecutionInfo(
+ BuildEventStreamProtos.TestResult.ExecutionInfo executionInfo);
+
abstract StandaloneTestResult realBuild();
/**
diff --git a/src/main/java/com/google/devtools/build/lib/exec/StandaloneTestStrategy.java b/src/main/java/com/google/devtools/build/lib/exec/StandaloneTestStrategy.java
index 06cda21..279fea4 100644
--- a/src/main/java/com/google/devtools/build/lib/exec/StandaloneTestStrategy.java
+++ b/src/main/java/com/google/devtools/build/lib/exec/StandaloneTestStrategy.java
@@ -34,6 +34,7 @@
import com.google.devtools.build.lib.analysis.test.TestResult;
import com.google.devtools.build.lib.analysis.test.TestRunnerAction;
import com.google.devtools.build.lib.analysis.test.TestRunnerAction.ResolvedPaths;
+import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos;
import com.google.devtools.build.lib.buildeventstream.TestFileNameConstants;
import com.google.devtools.build.lib.events.Event;
import com.google.devtools.build.lib.events.EventKind;
@@ -149,11 +150,7 @@
&& attempt < maxAttempts;
attempt++) {
processFailedTestAttempt(
- attempt,
- actionExecutionContext,
- action,
- dataBuilder,
- standaloneTestResult.testResultData());
+ attempt, actionExecutionContext, action, dataBuilder, standaloneTestResult);
standaloneTestResult =
executeTestAttempt(
action,
@@ -167,10 +164,11 @@
processLastTestAttempt(attempt, dataBuilder, standaloneTestResult.testResultData());
ImmutableList<Pair<String, Path>> testOutputs = action.getTestOutputsMapping(execRoot);
actionExecutionContext
- .getEventBus()
+ .getEventHandler()
.post(
new TestAttempt(
action,
+ standaloneTestResult.executionInfo(),
attempt,
standaloneTestResult.testResultData().getStatus(),
standaloneTestResult.testResultData().getStartTimeMillisEpoch(),
@@ -194,7 +192,7 @@
ActionExecutionContext actionExecutionContext,
TestRunnerAction action,
Builder dataBuilder,
- TestResultData data)
+ StandaloneTestResult result)
throws IOException {
ImmutableList.Builder<Pair<String, Path>> testOutputsBuilder = new ImmutableList.Builder<>();
// Rename outputs
@@ -238,14 +236,16 @@
}
// Add the test log to the output
+ TestResultData data = result.testResultData();
dataBuilder.addFailedLogs(testLog.toString());
dataBuilder.addTestTimes(data.getTestTimes(0));
dataBuilder.addAllTestProcessTimes(data.getTestProcessTimesList());
actionExecutionContext
- .getEventBus()
+ .getEventHandler()
.post(
new TestAttempt(
action,
+ result.executionInfo(),
attempt,
data.getStatus(),
data.getStartTimeMillisEpoch(),
@@ -258,6 +258,8 @@
private void processLastTestAttempt(int attempt, Builder dataBuilder, TestResultData data) {
dataBuilder.setHasCoverage(data.getHasCoverage());
+ dataBuilder.setRemotelyCached(data.getRemotelyCached());
+ dataBuilder.setIsRemoteStrategy(data.getIsRemoteStrategy());
dataBuilder.setStatus(
data.getStatus() == BlazeTestStatus.PASSED && attempt > 1
? BlazeTestStatus.FLAKY
@@ -331,6 +333,8 @@
long startTime = actionExecutionContext.getClock().currentTimeMillis();
SpawnActionContext spawnActionContext = actionExecutionContext.getSpawnActionContext(spawn);
List<SpawnResult> spawnResults = ImmutableList.of();
+ BuildEventStreamProtos.TestResult.ExecutionInfo.Builder executionInfo =
+ BuildEventStreamProtos.TestResult.ExecutionInfo.newBuilder();
try {
try {
if (executionOptions.testOutput.equals(TestOutputFormat.STREAMED)) {
@@ -370,6 +374,7 @@
// set. We fall back to the time measured here for backwards compatibility.
SpawnResult primaryResult = Iterables.getOnlyElement(spawnResults);
duration = primaryResult.getWallTime().orElse(Duration.ofMillis(duration)).toMillis();
+ extractExecutionInfo(primaryResult, builder, executionInfo);
}
builder.setStartTimeMillisEpoch(startTime);
@@ -394,12 +399,34 @@
builder.setHasCoverage(true);
}
- return StandaloneTestResult.create(spawnResults, builder.build());
+ return StandaloneTestResult.builder()
+ .setSpawnResults(spawnResults)
+ .setTestResultData(builder.build())
+ .setExecutionInfo(executionInfo.build())
+ .build();
} catch (IOException e) {
throw new TestExecException(e.getMessage());
}
}
+ private static void extractExecutionInfo(
+ SpawnResult spawnResult,
+ TestResultData.Builder result,
+ BuildEventStreamProtos.TestResult.ExecutionInfo.Builder executionInfo) {
+ if (spawnResult.isCacheHit()) {
+ result.setRemotelyCached(true);
+ executionInfo.setCachedRemotely(true);
+ }
+ String strategy = spawnResult.getRunnerName();
+ if (strategy != null) {
+ executionInfo.setStrategy(strategy);
+ result.setIsRemoteStrategy(strategy.equals("remote"));
+ }
+ if (spawnResult.getExecutorHostName() != null) {
+ executionInfo.setHostname(spawnResult.getExecutorHostName());
+ }
+ }
+
/**
* Outputs test result to the stdout after test has finished (e.g. for --test_output=all or
* --test_output=errors). Will also try to group output lines together (up to 10000 lines) so
diff --git a/src/main/java/com/google/devtools/build/lib/exec/TestAttempt.java b/src/main/java/com/google/devtools/build/lib/exec/TestAttempt.java
index aadc219..a7a4db6 100644
--- a/src/main/java/com/google/devtools/build/lib/exec/TestAttempt.java
+++ b/src/main/java/com/google/devtools/build/lib/exec/TestAttempt.java
@@ -144,6 +144,16 @@
return files;
}
+ @VisibleForTesting
+ public BuildEventStreamProtos.TestResult.ExecutionInfo getExecutionInfo() {
+ return executionInfo;
+ }
+
+ @VisibleForTesting
+ public BlazeTestStatus getStatus() {
+ return status;
+ }
+
@Override
public BuildEventId getEventId() {
return BuildEventId.testResult(
diff --git a/src/test/java/com/google/devtools/build/lib/actions/util/ActionsTestUtil.java b/src/test/java/com/google/devtools/build/lib/actions/util/ActionsTestUtil.java
index 49a6aa0..1266ab8 100644
--- a/src/test/java/com/google/devtools/build/lib/actions/util/ActionsTestUtil.java
+++ b/src/test/java/com/google/devtools/build/lib/actions/util/ActionsTestUtil.java
@@ -167,7 +167,7 @@
buildDriver, executor == null ? null : executor.getEventHandler()));
}
- public static ActionExecutionContext createContext(EventHandler eventHandler) {
+ public static ActionExecutionContext createContext(ExtendedEventHandler eventHandler) {
DummyExecutor dummyExecutor = new DummyExecutor(eventHandler);
return new ActionExecutionContext(
dummyExecutor,
diff --git a/src/test/java/com/google/devtools/build/lib/actions/util/DummyExecutor.java b/src/test/java/com/google/devtools/build/lib/actions/util/DummyExecutor.java
index 14076b6..1d0cd9b 100644
--- a/src/test/java/com/google/devtools/build/lib/actions/util/DummyExecutor.java
+++ b/src/test/java/com/google/devtools/build/lib/actions/util/DummyExecutor.java
@@ -20,7 +20,7 @@
import com.google.devtools.build.lib.actions.SpawnActionContext;
import com.google.devtools.build.lib.clock.BlazeClock;
import com.google.devtools.build.lib.clock.Clock;
-import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
import com.google.devtools.build.lib.vfs.FileSystem;
import com.google.devtools.build.lib.vfs.Path;
import com.google.devtools.common.options.OptionsClassProvider;
@@ -32,17 +32,17 @@
private final FileSystem fileSystem;
private final Path inputDir;
- private final EventHandler eventHandler;
+ private final ExtendedEventHandler eventHandler;
public DummyExecutor(FileSystem fileSystem, Path inputDir) {
this(fileSystem, inputDir, null);
}
- public DummyExecutor(EventHandler eventHandler) {
+ public DummyExecutor(ExtendedEventHandler eventHandler) {
this(null, null, eventHandler);
}
- public DummyExecutor(FileSystem fileSystem, Path inputDir, EventHandler eventHandler) {
+ public DummyExecutor(FileSystem fileSystem, Path inputDir, ExtendedEventHandler eventHandler) {
this.fileSystem = fileSystem;
this.inputDir = inputDir;
this.eventHandler = eventHandler;
@@ -74,7 +74,7 @@
}
@Override
- public EventHandler getEventHandler() {
+ public ExtendedEventHandler getEventHandler() {
return eventHandler;
}
diff --git a/src/test/java/com/google/devtools/build/lib/exec/StandaloneTestStrategyTest.java b/src/test/java/com/google/devtools/build/lib/exec/StandaloneTestStrategyTest.java
index 34058a42..0f0a023 100644
--- a/src/test/java/com/google/devtools/build/lib/exec/StandaloneTestStrategyTest.java
+++ b/src/test/java/com/google/devtools/build/lib/exec/StandaloneTestStrategyTest.java
@@ -24,6 +24,7 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
+import com.google.common.collect.MoreCollectors;
import com.google.devtools.build.lib.actions.ActionExecutionContext;
import com.google.devtools.build.lib.actions.ActionInput;
import com.google.devtools.build.lib.actions.Artifact;
@@ -36,10 +37,12 @@
import com.google.devtools.build.lib.analysis.test.TestRunnerAction;
import com.google.devtools.build.lib.analysis.util.BuildViewTestCase;
import com.google.devtools.build.lib.clock.BlazeClock;
+import com.google.devtools.build.lib.events.StoredEventHandler;
import com.google.devtools.build.lib.exec.TestStrategy.TestOutputFormat;
import com.google.devtools.build.lib.util.io.FileOutErr;
import com.google.devtools.build.lib.vfs.FileSystemUtils;
import com.google.devtools.build.lib.vfs.Path;
+import com.google.devtools.build.lib.view.test.TestStatus.BlazeTestStatus;
import com.google.devtools.common.options.Options;
import java.io.IOException;
import java.io.OutputStream;
@@ -59,6 +62,8 @@
public final class StandaloneTestStrategyTest extends BuildViewTestCase {
private static class TestedStandaloneTestStrategy extends StandaloneTestStrategy {
+ TestResult postedResult = null;
+
public TestedStandaloneTestStrategy(
ExecutionOptions executionOptions, BinTools binTools, Path tmpDirRoot) {
super(executionOptions, binTools, tmpDirRoot);
@@ -67,7 +72,7 @@
@Override
protected void postTestResult(ActionExecutionContext actionExecutionContext, TestResult result)
throws IOException {
- // Make postTestResult a no-op for testing purposes
+ postedResult = result;
}
}
@@ -75,13 +80,15 @@
@Mock private SpawnActionContext spawnActionContext;
+ private StoredEventHandler storedEvents = new StoredEventHandler();
+
@Before
public final void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
}
@Test
- public void testSpawnResultsAreReturned() throws Exception {
+ public void testRunTestOnce() throws Exception {
// setup a StandaloneTestStrategy
@@ -117,8 +124,7 @@
when(actionExecutionContext.withFileOutErr(any())).thenReturn(actionExecutionContext);
when(actionExecutionContext.getExecRoot()).thenReturn(outputBase.getRelative("execroot"));
when(actionExecutionContext.getClientEnv()).thenReturn(ImmutableMap.of());
- when(actionExecutionContext.getEventHandler()).thenReturn(reporter);
- when(actionExecutionContext.getEventBus()).thenReturn(eventBus);
+ when(actionExecutionContext.getEventHandler()).thenReturn(storedEvents);
when(actionExecutionContext.getInputPath(any())).thenAnswer(this::getInputPathMock);
SpawnResult expectedSpawnResult =
@@ -135,8 +141,274 @@
List<SpawnResult> spawnResults =
standaloneTestStrategy.exec(testRunnerAction, actionExecutionContext);
+ assertThat(spawnResults).containsExactly(expectedSpawnResult);
+ TestResult result = standaloneTestStrategy.postedResult;
+ assertThat(result).isNotNull();
+ assertThat(result.isCached()).isFalse();
+ assertThat(result.getTestStatusArtifact()).isEqualTo(testStatusArtifact);
+ assertThat(result.getData().getTestPassed()).isTrue();
+ assertThat(result.getData().getRemotelyCached()).isFalse();
+ assertThat(result.getData().getIsRemoteStrategy()).isFalse();
+ assertThat(result.getData().getRunDurationMillis()).isEqualTo(10);
+ assertThat(result.getData().getTestTimesList()).containsExactly(10L);
+ TestAttempt attempt =
+ storedEvents
+ .getPosts()
+ .stream()
+ .filter(TestAttempt.class::isInstance)
+ .map(TestAttempt.class::cast)
+ .collect(MoreCollectors.onlyElement());
+ assertThat(attempt.getExecutionInfo().getStrategy()).isEqualTo("test");
+ assertThat(attempt.getExecutionInfo().getHostname()).isEqualTo("");
+ }
+
+ @Test
+ public void testRunFlakyTest() throws Exception {
+
+ // setup a StandaloneTestStrategy
+
+ ExecutionOptions executionOptions = ExecutionOptions.DEFAULTS;
+ Path tmpDirRoot = TestStrategy.getTmpRoot(rootDirectory, outputBase, executionOptions);
+ BinTools binTools = BinTools.forUnitTesting(directories, analysisMock.getEmbeddedTools());
+ TestedStandaloneTestStrategy standaloneTestStrategy =
+ new TestedStandaloneTestStrategy(executionOptions, binTools, tmpDirRoot);
+
+ // setup a test action
+
+ scratch.file("standalone/simple_test.sh", "this does not get executed, it is mocked out");
+
+ scratch.file(
+ "standalone/BUILD",
+ "sh_test(",
+ " name = \"simple_test\",",
+ " size = \"small\",",
+ " srcs = [\"simple_test.sh\"],",
+ " flaky = True,",
+ ")");
+
+ ConfiguredTarget configuredTarget = getConfiguredTarget("//standalone:simple_test");
+ List<Artifact> testStatusArtifacts =
+ configuredTarget.getProvider(TestProvider.class).getTestParams().getTestStatusArtifacts();
+ Artifact testStatusArtifact = Iterables.getOnlyElement(testStatusArtifacts);
+ TestRunnerAction testRunnerAction = (TestRunnerAction) getGeneratingAction(testStatusArtifact);
+ assertThat(testRunnerAction.getTestProperties().isFlaky()).isTrue();
+ FileSystemUtils.createDirectoryAndParents(
+ testRunnerAction.getTestLog().getPath().getParentDirectory());
+
+ // setup a mock ActionExecutionContext
+
+ when(actionExecutionContext.getClock()).thenReturn(BlazeClock.instance());
+ when(actionExecutionContext.withFileOutErr(any())).thenReturn(actionExecutionContext);
+ when(actionExecutionContext.getExecRoot()).thenReturn(outputBase.getRelative("execroot"));
+ when(actionExecutionContext.getClientEnv()).thenReturn(ImmutableMap.of());
+ when(actionExecutionContext.getEventHandler()).thenReturn(storedEvents);
+ when(actionExecutionContext.getInputPath(any())).thenAnswer(this::getInputPathMock);
+
+ SpawnResult failSpawnResult =
+ new SpawnResult.Builder()
+ .setStatus(Status.NON_ZERO_EXIT)
+ .setExitCode(1)
+ .setWallTime(Duration.ofMillis(10))
+ .setRunnerName("test")
+ .build();
+ SpawnResult passSpawnResult =
+ new SpawnResult.Builder()
+ .setStatus(Status.SUCCESS)
+ .setWallTime(Duration.ofMillis(15))
+ .setRunnerName("test")
+ .build();
+ when(spawnActionContext.exec(any(), any()))
+ .thenThrow(new SpawnExecException("test failed", failSpawnResult, false))
+ .thenReturn(ImmutableList.of(passSpawnResult));
+
+ when(actionExecutionContext.getSpawnActionContext(any())).thenReturn(spawnActionContext);
+
+ // actual StandaloneTestStrategy execution
+ List<SpawnResult> spawnResults =
+ standaloneTestStrategy.exec(testRunnerAction, actionExecutionContext);
+
+ assertThat(spawnResults).containsExactly(passSpawnResult);
+ TestResult result = standaloneTestStrategy.postedResult;
+ assertThat(result).isNotNull();
+ assertThat(result.isCached()).isFalse();
+ assertThat(result.getTestStatusArtifact()).isEqualTo(testStatusArtifact);
+ assertThat(result.getData().getStatus()).isEqualTo(BlazeTestStatus.FLAKY);
+ assertThat(result.getData().getTestPassed()).isTrue();
+ assertThat(result.getData().getRemotelyCached()).isFalse();
+ assertThat(result.getData().getIsRemoteStrategy()).isFalse();
+ assertThat(result.getData().getRunDurationMillis()).isEqualTo(15L);
+ assertThat(result.getData().getTestTimesList()).containsExactly(10L, 15L);
+ List<TestAttempt> attempts =
+ storedEvents
+ .getPosts()
+ .stream()
+ .filter(TestAttempt.class::isInstance)
+ .map(TestAttempt.class::cast)
+ .collect(ImmutableList.toImmutableList());
+ assertThat(attempts).hasSize(2);
+ TestAttempt failedAttempt = attempts.get(0);
+ assertThat(failedAttempt.getExecutionInfo().getStrategy()).isEqualTo("test");
+ assertThat(failedAttempt.getExecutionInfo().getHostname()).isEqualTo("");
+ assertThat(failedAttempt.getStatus()).isEqualTo(BlazeTestStatus.FAILED);
+ assertThat(failedAttempt.getExecutionInfo().getCachedRemotely()).isFalse();
+ TestAttempt okAttempt = attempts.get(1);
+ assertThat(okAttempt.getStatus()).isEqualTo(BlazeTestStatus.PASSED);
+ assertThat(okAttempt.getExecutionInfo().getStrategy()).isEqualTo("test");
+ assertThat(okAttempt.getExecutionInfo().getHostname()).isEqualTo("");
+ }
+
+ @Test
+ public void testRunTestRemotely() throws Exception {
+
+ // setup a StandaloneTestStrategy
+
+ ExecutionOptions executionOptions = ExecutionOptions.DEFAULTS;
+ Path tmpDirRoot = TestStrategy.getTmpRoot(rootDirectory, outputBase, executionOptions);
+ BinTools binTools = BinTools.forUnitTesting(directories, analysisMock.getEmbeddedTools());
+ TestedStandaloneTestStrategy standaloneTestStrategy =
+ new TestedStandaloneTestStrategy(executionOptions, binTools, tmpDirRoot);
+
+ // setup a test action
+
+ scratch.file("standalone/simple_test.sh", "this does not get executed, it is mocked out");
+
+ scratch.file(
+ "standalone/BUILD",
+ "sh_test(",
+ " name = \"simple_test\",",
+ " size = \"small\",",
+ " srcs = [\"simple_test.sh\"],",
+ ")");
+
+ ConfiguredTarget configuredTarget = getConfiguredTarget("//standalone:simple_test");
+ List<Artifact> testStatusArtifacts =
+ configuredTarget.getProvider(TestProvider.class).getTestParams().getTestStatusArtifacts();
+ Artifact testStatusArtifact = Iterables.getOnlyElement(testStatusArtifacts);
+ TestRunnerAction testRunnerAction = (TestRunnerAction) getGeneratingAction(testStatusArtifact);
+ FileSystemUtils.createDirectoryAndParents(
+ testRunnerAction.getTestLog().getPath().getParentDirectory());
+
+ // setup a mock ActionExecutionContext
+
+ when(actionExecutionContext.getClock()).thenReturn(BlazeClock.instance());
+ when(actionExecutionContext.withFileOutErr(any())).thenReturn(actionExecutionContext);
+ when(actionExecutionContext.getExecRoot()).thenReturn(outputBase.getRelative("execroot"));
+ when(actionExecutionContext.getClientEnv()).thenReturn(ImmutableMap.of());
+ when(actionExecutionContext.getEventHandler()).thenReturn(storedEvents);
+ when(actionExecutionContext.getInputPath(any())).thenAnswer(this::getInputPathMock);
+
+ SpawnResult expectedSpawnResult =
+ new SpawnResult.Builder()
+ .setStatus(Status.SUCCESS)
+ .setWallTime(Duration.ofMillis(10))
+ .setRunnerName("remote")
+ .setExecutorHostname("a-remote-host")
+ .build();
+ when(spawnActionContext.exec(any(), any())).thenReturn(ImmutableList.of(expectedSpawnResult));
+
+ when(actionExecutionContext.getSpawnActionContext(any())).thenReturn(spawnActionContext);
+
+ // actual StandaloneTestStrategy execution
+ List<SpawnResult> spawnResults =
+ standaloneTestStrategy.exec(testRunnerAction, actionExecutionContext);
+
+ assertThat(spawnResults).containsExactly(expectedSpawnResult);
+ TestResult result = standaloneTestStrategy.postedResult;
+ assertThat(result).isNotNull();
+ assertThat(result.isCached()).isFalse();
+ assertThat(result.getTestStatusArtifact()).isEqualTo(testStatusArtifact);
+ assertThat(result.getData().getTestPassed()).isTrue();
+ assertThat(result.getData().getRemotelyCached()).isFalse();
+ assertThat(result.getData().getIsRemoteStrategy()).isTrue();
+ assertThat(result.getData().getRunDurationMillis()).isEqualTo(10);
+ assertThat(result.getData().getTestTimesList()).containsExactly(10L);
+ TestAttempt attempt =
+ storedEvents
+ .getPosts()
+ .stream()
+ .filter(TestAttempt.class::isInstance)
+ .map(TestAttempt.class::cast)
+ .collect(MoreCollectors.onlyElement());
+ assertThat(attempt.getStatus()).isEqualTo(BlazeTestStatus.PASSED);
+ assertThat(attempt.getExecutionInfo().getStrategy()).isEqualTo("remote");
+ assertThat(attempt.getExecutionInfo().getHostname()).isEqualTo("a-remote-host");
+ }
+
+ @Test
+ public void testRunRemotelyCachedTest() throws Exception {
+
+ // setup a StandaloneTestStrategy
+
+ ExecutionOptions executionOptions = ExecutionOptions.DEFAULTS;
+ Path tmpDirRoot = TestStrategy.getTmpRoot(rootDirectory, outputBase, executionOptions);
+ BinTools binTools = BinTools.forUnitTesting(directories, analysisMock.getEmbeddedTools());
+ TestedStandaloneTestStrategy standaloneTestStrategy =
+ new TestedStandaloneTestStrategy(executionOptions, binTools, tmpDirRoot);
+
+ // setup a test action
+
+ scratch.file("standalone/simple_test.sh", "this does not get executed, it is mocked out");
+
+ scratch.file(
+ "standalone/BUILD",
+ "sh_test(",
+ " name = \"simple_test\",",
+ " size = \"small\",",
+ " srcs = [\"simple_test.sh\"],",
+ ")");
+
+ ConfiguredTarget configuredTarget = getConfiguredTarget("//standalone:simple_test");
+ List<Artifact> testStatusArtifacts =
+ configuredTarget.getProvider(TestProvider.class).getTestParams().getTestStatusArtifacts();
+ Artifact testStatusArtifact = Iterables.getOnlyElement(testStatusArtifacts);
+ TestRunnerAction testRunnerAction = (TestRunnerAction) getGeneratingAction(testStatusArtifact);
+ FileSystemUtils.createDirectoryAndParents(
+ testRunnerAction.getTestLog().getPath().getParentDirectory());
+
+ // setup a mock ActionExecutionContext
+
+ when(actionExecutionContext.getClock()).thenReturn(BlazeClock.instance());
+ when(actionExecutionContext.withFileOutErr(any())).thenReturn(actionExecutionContext);
+ when(actionExecutionContext.getExecRoot()).thenReturn(outputBase.getRelative("execroot"));
+ when(actionExecutionContext.getClientEnv()).thenReturn(ImmutableMap.of());
+ when(actionExecutionContext.getEventHandler()).thenReturn(storedEvents);
+ when(actionExecutionContext.getInputPath(any())).thenAnswer(this::getInputPathMock);
+
+ SpawnResult expectedSpawnResult =
+ new SpawnResult.Builder()
+ .setStatus(Status.SUCCESS)
+ .setCacheHit(true)
+ .setWallTime(Duration.ofMillis(10))
+ .setRunnerName("remote cache")
+ .build();
+ when(spawnActionContext.exec(any(), any())).thenReturn(ImmutableList.of(expectedSpawnResult));
+
+ when(actionExecutionContext.getSpawnActionContext(any())).thenReturn(spawnActionContext);
+
+ // actual StandaloneTestStrategy execution
+ List<SpawnResult> spawnResults =
+ standaloneTestStrategy.exec(testRunnerAction, actionExecutionContext);
+
// check that the rigged SpawnResult was returned
assertThat(spawnResults).containsExactly(expectedSpawnResult);
+ TestResult result = standaloneTestStrategy.postedResult;
+ assertThat(result).isNotNull();
+ assertThat(result.isCached()).isFalse();
+ assertThat(result.getTestStatusArtifact()).isEqualTo(testStatusArtifact);
+ assertThat(result.getData().getTestPassed()).isTrue();
+ assertThat(result.getData().getRemotelyCached()).isTrue();
+ assertThat(result.getData().getIsRemoteStrategy()).isFalse();
+ assertThat(result.getData().getRunDurationMillis()).isEqualTo(10);
+ assertThat(result.getData().getTestTimesList()).containsExactly(10L);
+ TestAttempt attempt =
+ storedEvents
+ .getPosts()
+ .stream()
+ .filter(TestAttempt.class::isInstance)
+ .map(TestAttempt.class::cast)
+ .collect(MoreCollectors.onlyElement());
+ assertThat(attempt.getExecutionInfo().getStrategy()).isEqualTo("remote cache");
+ assertThat(attempt.getExecutionInfo().getHostname()).isEqualTo("");
}
@Test