diff --git a/src/main/java/com/google/devtools/build/docgen/templates/attributes/common/tags.html b/src/main/java/com/google/devtools/build/docgen/templates/attributes/common/tags.html index c4877759a029c8..47bfb59e7a4714 100644 --- a/src/main/java/com/google/devtools/build/docgen/templates/attributes/common/tags.html +++ b/src/main/java/com/google/devtools/build/docgen/templates/attributes/common/tags.html @@ -62,6 +62,14 @@ is enabled. +
  • requires-test-xml-generation marks test actions as requiring + Bazel to ensure that they produce test XML. With + --experimental_test_xml_missing_behavior=workaround and split + XML generation enabled, Bazel supervises these test actions and generates + missing XML in the test spawn, as it does when + --noexperimental_split_xml_generation is set. +
  • +
  • block-network keyword blocks access to the external network from inside the sandbox. In this case, only communication with localhost is allowed. This tag only has an effect if sandboxing is diff --git a/src/main/java/com/google/devtools/build/lib/actions/ExecutionRequirements.java b/src/main/java/com/google/devtools/build/lib/actions/ExecutionRequirements.java index 94576c64fa41c6..b13462b7e1a276 100644 --- a/src/main/java/com/google/devtools/build/lib/actions/ExecutionRequirements.java +++ b/src/main/java/com/google/devtools/build/lib/actions/ExecutionRequirements.java @@ -261,6 +261,9 @@ public enum WorkerProtocolFormat { */ public static final String REQUIRES_NETWORK = "requires-network"; + /** Indicates that test actions need Bazel to ensure that they produce test XML. */ + public static final String REQUIRES_TEST_XML_GENERATION = "requires-test-xml-generation"; + /** * Disables networking for a spawn if possible (only if sandboxing is enabled and if the sandbox * supports it). diff --git a/src/main/java/com/google/devtools/build/lib/analysis/test/TestActionBuilder.java b/src/main/java/com/google/devtools/build/lib/analysis/test/TestActionBuilder.java index c027d232af66a7..fd9e153e7eabac 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/test/TestActionBuilder.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/test/TestActionBuilder.java @@ -27,6 +27,7 @@ import com.google.devtools.build.lib.actions.ActionOwner; import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.actions.ArtifactRoot; +import com.google.devtools.build.lib.actions.ExecutionRequirements; import com.google.devtools.build.lib.analysis.Allowlist; import com.google.devtools.build.lib.analysis.AnalysisEnvironment; import com.google.devtools.build.lib.analysis.FilesToRunProvider; @@ -305,7 +306,8 @@ private TestParams createTestAction() inputsBuilder.add(testXmlGeneratorExecutable); Artifact ensureXmlExecutable = null; if (testConfiguration.getTestXmlMissingBehavior() - == TestConfiguration.TestXmlMissingBehavior.WORKAROUND) { + == TestConfiguration.TestXmlMissingBehavior.WORKAROUND + && testProperties.getTags().contains(ExecutionRequirements.REQUIRES_TEST_XML_GENERATION)) { ensureXmlExecutable = getEnsureXmlExecutable(actionOwner); if (ensureXmlExecutable != null) { inputsBuilder.add(ensureXmlExecutable); 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 0f7963bc965767..908a435f089747 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 @@ -885,6 +885,12 @@ private TestAttemptResult runTestAttempt( String.format( "Test action %s failed to produce test.xml", testAction.getOwner().getLabel()); TestXmlMissingBehavior missingBehavior = testAction.getTestXmlMissingBehavior(); + if (missingBehavior == TestXmlMissingBehavior.WORKAROUND) { + missingXmlMessage += + String.format( + "; add '%s' to the test target's tags attribute", + ExecutionRequirements.REQUIRES_TEST_XML_GENERATION); + } if (missingBehavior == TestXmlMissingBehavior.FAIL || missingBehavior == TestXmlMissingBehavior.WORKAROUND) { throw createTestExecException(TestAction.Code.MISSING_XML_OUTPUT, missingXmlMessage); diff --git a/src/test/java/com/google/devtools/build/lib/analysis/test/TestActionBuilderTest.java b/src/test/java/com/google/devtools/build/lib/analysis/test/TestActionBuilderTest.java index dfdf56476004f9..242a42c9494c10 100644 --- a/src/test/java/com/google/devtools/build/lib/analysis/test/TestActionBuilderTest.java +++ b/src/test/java/com/google/devtools/build/lib/analysis/test/TestActionBuilderTest.java @@ -25,6 +25,7 @@ import com.google.common.eventbus.EventBus; import com.google.devtools.build.lib.actions.Action; import com.google.devtools.build.lib.actions.Artifact; +import com.google.devtools.build.lib.actions.ExecutionRequirements; import com.google.devtools.build.lib.actions.MiddlemanAction; import com.google.devtools.build.lib.actions.RunfilesTree; import com.google.devtools.build.lib.analysis.AnalysisResult; @@ -774,6 +775,7 @@ public void testEnsureXmlWrapsRunUnderAndTest() throws Exception { "foo_test(", " name = 'test',", " srcs = ['test.sh'],", + " tags = ['requires-test-xml-generation'],", ")"); scratch.file("xml_wrapper/test.sh", "#!/bin/sh", "exit 0"); useConfiguration( @@ -786,6 +788,8 @@ public void testEnsureXmlWrapsRunUnderAndTest() throws Exception { Artifact ensureXml = testAction.getEnsureXmlExecutable(); assertThat(ensureXml).isNotNull(); assertThat(testAction.getInputs().toList()).contains(ensureXml); + assertThat(testAction.getExecutionInfo()) + .containsKey(ExecutionRequirements.REQUIRES_TEST_XML_GENERATION); ImmutableList args = TestStrategy.expandedArgsFromAction(testAction, /* ensureXml= */ true); @@ -794,6 +798,21 @@ public void testEnsureXmlWrapsRunUnderAndTest() throws Exception { assertThat(PathFragment.create(args.get(3)).getBaseName()).isEqualTo("test"); } + @Test + public void testEnsureXmlIsNotInputWithoutRequiresTestXmlGenerationTag() throws Exception { + useConfiguration("--experimental_test_xml_missing_behavior=workaround"); + + TestRunnerAction testAction = + (TestRunnerAction) getGeneratingAction(getTestStatusArtifacts("//tests:small_test_2").get(0)); + + assertThat(testAction.getEnsureXmlExecutable()).isNull(); + assertThat( + testAction.getInputs().toList().stream() + .map(artifact -> artifact.getExecPath().getBaseName()) + .anyMatch(name -> name.startsWith("ensure_xml_"))) + .isFalse(); + } + @Test public void testEnsureXmlIsNotInputOutsideWorkaroundMode() throws Exception { useConfiguration("--experimental_test_xml_missing_behavior=warn"); @@ -821,7 +840,11 @@ public void testEnsureXmlUsesTargetPlatformForTests() throws Exception { " '" + TestConstants.CONSTRAINTS_PACKAGE_ROOT + "cpu:aarch64',", " ],", ")", - "foo_test(name = 'test', srcs = ['test.sh'])"); + "foo_test(", + " name = 'test',", + " srcs = ['test.sh'],", + " tags = ['requires-test-xml-generation'],", + ")"); scratch.file("xml_platform/test.sh", "#!/bin/sh", "exit 0"); useConfiguration( "--experimental_test_xml_missing_behavior=workaround", @@ -854,7 +877,11 @@ public void testEnsureXmlIsOmittedForUnsupportedExecutionPlatform() throws Excep " '" + TestConstants.CONSTRAINTS_PACKAGE_ROOT + "cpu:x86_64',", " ],", ")", - "foo_test(name = 'test', srcs = ['test.sh'])"); + "foo_test(", + " name = 'test',", + " srcs = ['test.sh'],", + " tags = ['requires-test-xml-generation'],", + ")"); scratch.file("xml_platform/test.sh", "#!/bin/sh", "exit 0"); useConfiguration( "--experimental_test_xml_missing_behavior=workaround", diff --git a/src/test/java/com/google/devtools/build/lib/exec/BUILD b/src/test/java/com/google/devtools/build/lib/exec/BUILD index 55f0121e86bb2f..c85f23da68122e 100644 --- a/src/test/java/com/google/devtools/build/lib/exec/BUILD +++ b/src/test/java/com/google/devtools/build/lib/exec/BUILD @@ -27,6 +27,7 @@ java_library( "//src/main/java/com/google/devtools/build/lib/actions:action_input_helper", "//src/main/java/com/google/devtools/build/lib/actions:artifact_expander", "//src/main/java/com/google/devtools/build/lib/actions:artifacts", + "//src/main/java/com/google/devtools/build/lib/actions:execution_requirements", "//src/main/java/com/google/devtools/build/lib/actions:file_metadata", "//src/main/java/com/google/devtools/build/lib/actions:fileset_output_symlink", "//src/main/java/com/google/devtools/build/lib/actions:fileset_output_tree", 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 9db5a521557b62..617dec1aa9e8d1 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 @@ -35,6 +35,7 @@ import com.google.devtools.build.lib.actions.ActionKeyContext; import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.actions.DiscoveredModulesPruner; +import com.google.devtools.build.lib.actions.ExecutionRequirements; import com.google.devtools.build.lib.actions.InputMetadataProvider; import com.google.devtools.build.lib.actions.Spawn; import com.google.devtools.build.lib.actions.SpawnResult; @@ -816,6 +817,15 @@ public void missingXmlStrictBehaviorFailsWithoutGeneratingXml( () -> execute(testRunnerAction, actionExecutionContext, standaloneTestStrategy)); assertThat(exception).hasMessageThat().contains("failed to produce test.xml"); + if (testXmlMissingBehavior == TestXmlMissingBehavior.WORKAROUND) { + assertThat(exception) + .hasMessageThat() + .contains(ExecutionRequirements.REQUIRES_TEST_XML_GENERATION); + } else { + assertThat(exception) + .hasMessageThat() + .doesNotContain(ExecutionRequirements.REQUIRES_TEST_XML_GENERATION); + } verify(spawnStrategy, times(1)).exec(any(), any()); } @@ -840,6 +850,7 @@ public void workaroundWrapperProducesXmlWithoutDerivedSpawn() throws Exception { name = "wrapped_test", size = "small", srcs = ["wrapped_test.sh"], + tags = ["requires-test-xml-generation"], ) """); TestRunnerAction testRunnerAction = getTestAction("//standalone:wrapped_test"); @@ -892,6 +903,7 @@ public void workaroundWrapperIsDisabledWithoutSplitXmlGeneration() throws Except name = "unwrapped_test", size = "small", srcs = ["unwrapped_test.sh"], + tags = ["requires-test-xml-generation"], ) """); TestRunnerAction testRunnerAction = getTestAction("//standalone:unwrapped_test");