Skip to content

Commit c62ef95

Browse files
fmeumcopybara-github
authored andcommitted
Make test.xml a regular test action output
This ensures that BwoB correctly invalidates the action if `test.xml` is newly requested to be downloaded. Fixes #25762 Closes #26048. PiperOrigin-RevId: 799116042 Change-Id: I5d0b4182ea43e1447cd8b3d10cc0c378f5ab9e5f
1 parent dfc9103 commit c62ef95

File tree

4 files changed

+93
-15
lines changed

4 files changed

+93
-15
lines changed

src/main/java/com/google/devtools/build/lib/analysis/test/TestActionBuilder.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import com.google.common.collect.ImmutableList;
2323
import com.google.common.collect.Lists;
2424
import com.google.devtools.build.lib.actions.ActionInput;
25+
import com.google.devtools.build.lib.actions.ActionInputHelper;
2526
import com.google.devtools.build.lib.actions.ActionOwner;
2627
import com.google.devtools.build.lib.actions.Artifact;
2728
import com.google.devtools.build.lib.actions.ArtifactRoot;
@@ -54,6 +55,13 @@
5455

5556
/** Helper class to create test actions. */
5657
public final class TestActionBuilder {
58+
59+
// Whether the test.xml is a declared output of this action rather than just an output of the test
60+
// spawn. True for Bazel so that it behaves properly with Build without the Bytes (i.e.,
61+
// --remote_download_regex), but false for Blaze because not all test rules generate a test.xml.
62+
// DO NOT inline this constant, as it's rewritten by Copybara on import/export.
63+
private static final boolean TEST_XML_IS_ACTION_OUTPUT = true;
64+
5765
private static final String CC_CODE_COVERAGE_SCRIPT = "CC_CODE_COVERAGE_SCRIPT";
5866
private static final String LCOV_MERGER = "LCOV_MERGER";
5967
// The coverage tool Bazel uses to generate a code coverage report for C++.
@@ -353,6 +361,11 @@ private TestParams createTestAction()
353361

354362
Artifact.DerivedArtifact testLog =
355363
ruleContext.getPackageRelativeArtifact(dir.getRelative("test.log"), root);
364+
ActionInput testXml =
365+
TEST_XML_IS_ACTION_OUTPUT
366+
? ruleContext.getPackageRelativeArtifact(dir.getRelative("test.xml"), root)
367+
: ActionInputHelper.fromPath(
368+
testLog.getExecPath().getParentDirectory().getRelative("test.xml"));
356369
Artifact.DerivedArtifact cacheStatus =
357370
ruleContext.getPackageRelativeArtifact(dir.getRelative("test.cache_status"), root);
358371

@@ -386,6 +399,7 @@ private TestParams createTestAction()
386399
testXmlGeneratorExecutable,
387400
collectCoverageScript,
388401
testLog,
402+
testXml,
389403
cacheStatus,
390404
coverageArtifact,
391405
coverageDirectory,

src/main/java/com/google/devtools/build/lib/analysis/test/TestRunnerAction.java

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ public class TestRunnerAction extends AbstractAction
119119
private final BuildConfigurationValue configuration;
120120
private final TestConfiguration testConfiguration;
121121
private final Artifact testLog;
122+
private final ActionInput testXml;
122123
private final Artifact cacheStatus;
123124
private final PathFragment testWarningsPath;
124125
private final PathFragment unusedRunfilesLogPath;
@@ -129,7 +130,6 @@ public class TestRunnerAction extends AbstractAction
129130
private final PathFragment undeclaredOutputsManifestPath;
130131
private final PathFragment undeclaredOutputsAnnotationsPath;
131132
private final PathFragment undeclaredOutputsAnnotationsPbPath;
132-
private final PathFragment xmlOutputPath;
133133
@Nullable private final PathFragment testShard;
134134
private final PathFragment testExitSafe;
135135
private final PathFragment testStderr;
@@ -199,6 +199,7 @@ private static ImmutableSet<Artifact> nonNullAsSet(Artifact... artifacts) {
199199
@Nullable
200200
FilesToRunProvider collectCoverageScript, // filesToRun must be in input, if not null
201201
Artifact testLog,
202+
ActionInput testXml,
202203
Artifact cacheStatus,
203204
Artifact coverageArtifact,
204205
@Nullable Artifact coverageDirectory,
@@ -219,7 +220,13 @@ private static ImmutableSet<Artifact> nonNullAsSet(Artifact... artifacts) {
219220
owner,
220221
inputs,
221222
nonNullAsSet(
222-
testLog, cacheStatus, coverageArtifact, coverageDirectory, undeclaredOutputsDir));
223+
testLog,
224+
// See TestActionBuilder.TEST_XML_IS_ACTION_OUTPUT for details.
225+
testXml instanceof Artifact testXmlArtifact ? testXmlArtifact : null,
226+
cacheStatus,
227+
coverageArtifact,
228+
coverageDirectory,
229+
undeclaredOutputsDir));
223230
Preconditions.checkState((collectCoverageScript == null) == (coverageArtifact == null));
224231
this.runfilesTree = runfilesTree;
225232
this.testSetupScript = testSetupScript;
@@ -228,6 +235,7 @@ private static ImmutableSet<Artifact> nonNullAsSet(Artifact... artifacts) {
228235
this.configuration = checkNotNull(configuration);
229236
this.testConfiguration = checkNotNull(configuration.getFragment(TestConfiguration.class));
230237
this.testLog = testLog;
238+
this.testXml = testXml;
231239
this.cacheStatus = cacheStatus;
232240
this.coverageData = coverageArtifact;
233241
this.coverageDirectory = coverageDirectory;
@@ -246,7 +254,6 @@ private static ImmutableSet<Artifact> nonNullAsSet(Artifact... artifacts) {
246254
this.testExitSafe = baseDir.getChild("test.exited_prematurely");
247255
// testShard Path should be set only if sharding is enabled.
248256
this.testShard = totalShards > 1 ? baseDir.getChild("test.shard") : null;
249-
this.xmlOutputPath = baseDir.getChild("test.xml");
250257
this.testWarningsPath = baseDir.getChild("test.warnings");
251258
this.unusedRunfilesLogPath = baseDir.getChild("test.unused_runfiles_log");
252259
this.testStderr = baseDir.getChild("test.err");
@@ -282,7 +289,6 @@ private static ImmutableSet<Artifact> nonNullAsSet(Artifact... artifacts) {
282289
ImmutableSet.Builder<PathFragment> filesToDeleteBuilder =
283290
ImmutableSet.<PathFragment>builder()
284291
.add(
285-
xmlOutputPath,
286292
testWarningsPath,
287293
unusedRunfilesLogPath,
288294
testStderr,
@@ -292,6 +298,9 @@ private static ImmutableSet<Artifact> nonNullAsSet(Artifact... artifacts) {
292298
// instead.
293299
baseDir.getChild("coverage.dat"),
294300
baseDir.getChild("test.zip")); // Delete files fetched from remote execution.
301+
if (!(testXml instanceof Artifact)) {
302+
filesToDeleteBuilder.add(testXml.getExecPath());
303+
}
295304
if (testShard != null) {
296305
filesToDeleteBuilder.add(testShard);
297306
}
@@ -360,7 +369,7 @@ public boolean checkShardingSupport() {
360369

361370
public List<ActionInput> getSpawnOutputs() {
362371
final List<ActionInput> outputs = new ArrayList<>();
363-
outputs.add(ActionInputHelper.fromPath(getXmlOutputPath()));
372+
outputs.add(testXml);
364373
outputs.add(ActionInputHelper.fromPath(getExitSafeFile()));
365374
if (isSharded()) {
366375
outputs.add(ActionInputHelper.fromPath(getTestShard()));
@@ -767,7 +776,7 @@ public void setupEnvVariables(Map<String, String> env) {
767776
env.put("TEST_TOTAL_SHARDS", Integer.toString(getExecutionSettings().getTotalShards()));
768777
env.put("TEST_SHARD_STATUS_FILE", getTestShard().getPathString());
769778
}
770-
env.put("XML_OUTPUT_FILE", getXmlOutputPath().getPathString());
779+
env.put("XML_OUTPUT_FILE", testXml.getExecPathString());
771780

772781
if (!configuration.runfilesEnabled()) {
773782
// If runfiles are disabled, tell remote-runtest.sh/local-runtest.sh about that.
@@ -826,6 +835,10 @@ public Artifact getTestLog() {
826835
return testLog;
827836
}
828837

838+
public ActionInput getTestXml() {
839+
return testXml;
840+
}
841+
829842
/** Returns all environment variables which must be set in order to run this test. */
830843
public ActionEnvironment getExtraTestEnv() {
831844
return extraTestEnv;
@@ -900,11 +913,6 @@ public PathFragment getInfrastructureFailureFile() {
900913
return testInfrastructureFailure;
901914
}
902915

903-
/** Returns path to the optionally created XML output file created by the test. */
904-
public PathFragment getXmlOutputPath() {
905-
return xmlOutputPath;
906-
}
907-
908916
/** Returns coverage data artifact or null if code coverage was not requested. */
909917
@Nullable
910918
public Artifact getCoverageData() {
@@ -1184,7 +1192,7 @@ public Path getInfrastructureFailureFile() {
11841192

11851193
/** Returns path to the optionally created XML output file created by the test. */
11861194
public Path getXmlOutputPath() {
1187-
return getPath(xmlOutputPath);
1195+
return getPath(testXml.getExecPath());
11881196
}
11891197

11901198
public Path getCoverageDirectory() {

src/main/java/com/google/devtools/build/lib/exec/StandaloneTestStrategy.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
import com.google.common.io.ByteStreams;
2727
import com.google.devtools.build.lib.actions.ActionExecutionContext;
2828
import com.google.devtools.build.lib.actions.ActionInput;
29-
import com.google.devtools.build.lib.actions.ActionInputHelper;
3029
import com.google.devtools.build.lib.actions.Artifact.SpecialArtifact;
3130
import com.google.devtools.build.lib.actions.ArtifactPathResolver;
3231
import com.google.devtools.build.lib.actions.EnvironmentalExecException;
@@ -459,7 +458,7 @@ private static Spawn createXmlGeneratingSpawn(
459458
.getExecPath()
460459
.getCallablePathStringForOs(action.getExecutionSettings().getExecutionOs()),
461460
action.getTestLog().getExecPathString(),
462-
action.getXmlOutputPath().getPathString(),
461+
action.getTestXml().getExecPathString(),
463462
Integer.toString(result.getWallTimeInMs() / 1000),
464463
Integer.toString(result.exitCode()));
465464
ImmutableMap.Builder<String, String> envBuilder = ImmutableMap.builder();
@@ -483,7 +482,7 @@ private static Spawn createXmlGeneratingSpawn(
483482
/* inputs= */ NestedSetBuilder.create(
484483
Order.STABLE_ORDER, action.getTestXmlGeneratorScript(), action.getTestLog()),
485484
/* tools= */ NestedSetBuilder.emptySet(Order.STABLE_ORDER),
486-
/* outputs= */ ImmutableSet.of(ActionInputHelper.fromPath(action.getXmlOutputPath())),
485+
/* outputs= */ ImmutableSet.of(action.getTestXml()),
487486
/* mandatoryOutputs= */ null,
488487
SpawnAction.DEFAULT_RESOURCE_SET);
489488
}

src/test/shell/bazel/remote/build_without_the_bytes_test.sh

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -700,6 +700,63 @@ EOF
700700
assert_exists bazel-bin/a/test
701701
}
702702

703+
function test_download_regex_changed_with_action_cache_hit_for_test() {
704+
# Regression test for #25762
705+
# Test that changes to --remote_download_regex are effective when matching
706+
# test.xml even when the test is cached.
707+
708+
add_rules_shell "MODULE.bazel"
709+
mkdir -p a
710+
711+
cat > a/test.sh <<'EOF'
712+
#!/bin/sh
713+
714+
cat > "$XML_OUTPUT_FILE" <<EOF2
715+
<?xml version="1.0" encoding="UTF-8"?>
716+
<testsuites>
717+
<testsuite name="test" tests="1" failures="0" errors="0">
718+
<testcase name="test_case" status="run">
719+
<system-out>test_case succeeded.</system-out>
720+
</testcase>
721+
</testsuite>
722+
</testsuites>
723+
EOF2
724+
echo "hi" > "$TEST_UNDECLARED_OUTPUTS_DIR/out.txt"
725+
EOF
726+
727+
chmod +x a/test.sh
728+
729+
cat > a/BUILD <<EOF
730+
load("@rules_shell//shell:sh_test.bzl", "sh_test")
731+
sh_test(
732+
name = 'test',
733+
srcs = [ 'test.sh' ],
734+
)
735+
EOF
736+
737+
bazel test \
738+
--remote_executor=grpc://localhost:${worker_port} \
739+
--remote_download_minimal \
740+
//a:test >& $TEST_log || fail "Expected success"
741+
742+
rm -rf bazel-out bazel-testlogs
743+
744+
bazel test \
745+
--remote_executor=grpc://localhost:${worker_port} \
746+
--remote_download_minimal \
747+
//a:test >& $TEST_log || fail "Expected success"
748+
749+
assert_not_exists bazel-testlogs/a/test/test.xml
750+
751+
bazel test \
752+
--remote_executor=grpc://localhost:${worker_port} \
753+
--remote_download_minimal \
754+
--remote_download_regex='.*/test.xml' \
755+
//a:test >& $TEST_log || fail "Expected success"
756+
757+
assert_exists bazel-testlogs/a/test/test.xml
758+
}
759+
703760
function do_test_non_test_toplevel_targets() {
704761
# Regression test for https://github.com/bazelbuild/bazel/issues/17190.
705762
#

0 commit comments

Comments
 (0)