From 39125b2213d60a52db0a186e2887d007010221cd Mon Sep 17 00:00:00 2001 From: Philipp Wollermann Date: Mon, 18 Jan 2016 14:19:33 +0000 Subject: Fix #757: Bazel does not copy xml test output from sandbox. -- MOS_MIGRATED_REVID=112404257 --- .../devtools/build/lib/actions/BaseSpawn.java | 64 +++++++++++++++++++--- .../devtools/build/lib/actions/DelegateSpawn.java | 5 ++ .../google/devtools/build/lib/actions/Spawn.java | 6 ++ .../lib/rules/test/StandaloneTestStrategy.java | 10 ++-- .../build/lib/sandbox/LinuxSandboxedStrategy.java | 11 +++- .../build/lib/sandbox/NamespaceSandboxRunner.java | 21 ++++--- .../devtools/build/lib/actions/BaseSpawnTest.java | 5 +- src/test/shell/bazel/bazel_test_test.sh | 25 +++++++++ 8 files changed, 121 insertions(+), 26 deletions(-) diff --git a/src/main/java/com/google/devtools/build/lib/actions/BaseSpawn.java b/src/main/java/com/google/devtools/build/lib/actions/BaseSpawn.java index 0a0955538e..8e34389185 100644 --- a/src/main/java/com/google/devtools/build/lib/actions/BaseSpawn.java +++ b/src/main/java/com/google/devtools/build/lib/actions/BaseSpawn.java @@ -17,6 +17,7 @@ package com.google.devtools.build.lib.actions; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import com.google.devtools.build.lib.actions.extra.EnvironmentVariable; import com.google.devtools.build.lib.actions.extra.SpawnInfo; @@ -41,6 +42,7 @@ public class BaseSpawn implements Spawn { private final ImmutableMap environment; private final ImmutableMap executionInfo; private final ImmutableMap runfilesManifests; + private final ImmutableSet optionalOutputFiles; private final RunfilesSupplier runfilesSupplier; private final ActionMetadata action; private final ResourceSet localResources; @@ -49,13 +51,15 @@ public class BaseSpawn implements Spawn { // policy on runfilesManifests and runfilesSupplier being non-empty (ie: are overlapping mappings // allowed?). @VisibleForTesting - BaseSpawn(List arguments, + BaseSpawn( + List arguments, Map environment, Map executionInfo, Map runfilesManifests, RunfilesSupplier runfilesSupplier, ActionMetadata action, - ResourceSet localResources) { + ResourceSet localResources, + Collection optionalOutputFiles) { this.arguments = ImmutableList.copyOf(arguments); this.environment = ImmutableMap.copyOf(environment); this.executionInfo = ImmutableMap.copyOf(executionInfo); @@ -63,6 +67,7 @@ public class BaseSpawn implements Spawn { this.runfilesSupplier = runfilesSupplier; this.action = action; this.localResources = localResources; + this.optionalOutputFiles = ImmutableSet.copyOf(optionalOutputFiles); } /** @@ -75,8 +80,15 @@ public class BaseSpawn implements Spawn { RunfilesSupplier runfilesSupplier, ActionMetadata action, ResourceSet localResources) { - this(arguments, environment, executionInfo, ImmutableMap.of(), - runfilesSupplier, action, localResources); + this( + arguments, + environment, + executionInfo, + ImmutableMap.of(), + runfilesSupplier, + action, + localResources, + ImmutableSet.of()); } /** @@ -89,8 +101,15 @@ public class BaseSpawn implements Spawn { Map runfilesManifests, ActionMetadata action, ResourceSet localResources) { - this(arguments, environment, executionInfo, runfilesManifests, EmptyRunfilesSupplier.INSTANCE, - action, localResources); + this( + arguments, + environment, + executionInfo, + runfilesManifests, + EmptyRunfilesSupplier.INSTANCE, + action, + localResources, + ImmutableSet.of()); } /** @@ -101,8 +120,32 @@ public class BaseSpawn implements Spawn { Map executionInfo, ActionMetadata action, ResourceSet localResources) { - this(arguments, environment, executionInfo, - ImmutableMap.of(), action, localResources); + this( + arguments, + environment, + executionInfo, + ImmutableMap.of(), + action, + localResources); + } + + public BaseSpawn( + List arguments, + Map environment, + Map executionInfo, + RunfilesSupplier runfilesSupplier, + ActionMetadata action, + ResourceSet localResources, + Collection optionalOutputFiles) { + this( + arguments, + environment, + executionInfo, + ImmutableMap.of(), + runfilesSupplier, + action, + localResources, + optionalOutputFiles); } public static PathFragment runfilesForFragment(PathFragment pathFragment) { @@ -209,6 +252,11 @@ public class BaseSpawn implements Spawn { return action.getOutputs(); } + @Override + public Collection getOptionalOutputFiles() { + return optionalOutputFiles; + } + @Override public ActionMetadata getResourceOwner() { return action; diff --git a/src/main/java/com/google/devtools/build/lib/actions/DelegateSpawn.java b/src/main/java/com/google/devtools/build/lib/actions/DelegateSpawn.java index 2c0a0ad5ca..acb9cd64d4 100644 --- a/src/main/java/com/google/devtools/build/lib/actions/DelegateSpawn.java +++ b/src/main/java/com/google/devtools/build/lib/actions/DelegateSpawn.java @@ -94,6 +94,11 @@ public class DelegateSpawn implements Spawn { return spawn.getOutputFiles(); } + @Override + public Collection getOptionalOutputFiles() { + return spawn.getOptionalOutputFiles(); + } + @Override public ActionMetadata getResourceOwner() { return spawn.getResourceOwner(); diff --git a/src/main/java/com/google/devtools/build/lib/actions/Spawn.java b/src/main/java/com/google/devtools/build/lib/actions/Spawn.java index d027f70570..b4ed5c79fa 100644 --- a/src/main/java/com/google/devtools/build/lib/actions/Spawn.java +++ b/src/main/java/com/google/devtools/build/lib/actions/Spawn.java @@ -120,6 +120,12 @@ public interface Spawn { */ Collection getOutputFiles(); + /** + * Instructs the spawn strategy to try to fetch these optional output files in addition to the + * usual output artifacts. The PathFragments should be relative to the exec root. + */ + Collection getOptionalOutputFiles(); + /** * Returns the resource owner for local fallback. */ diff --git a/src/main/java/com/google/devtools/build/lib/rules/test/StandaloneTestStrategy.java b/src/main/java/com/google/devtools/build/lib/rules/test/StandaloneTestStrategy.java index 5d7739f664..bb5ffa7cb9 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/test/StandaloneTestStrategy.java +++ b/src/main/java/com/google/devtools/build/lib/rules/test/StandaloneTestStrategy.java @@ -14,6 +14,7 @@ package com.google.devtools.build.lib.rules.test; +import com.google.common.collect.ImmutableSet; import com.google.devtools.build.lib.actions.ActionExecutionContext; import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.actions.BaseSpawn; @@ -79,8 +80,8 @@ public class StandaloneTestStrategy extends TestStrategy { .getChild(getTmpDirName(action.getExecutionSettings().getExecutable().getExecPath())); Path workingDirectory = runfilesDir.getRelative(action.getRunfilesPrefix()); - TestRunnerAction.ResolvedPaths resolvedPaths = - action.resolve(actionExecutionContext.getExecutor().getExecRoot()); + Path execRoot = actionExecutionContext.getExecutor().getExecRoot(); + TestRunnerAction.ResolvedPaths resolvedPaths = action.resolve(execRoot); Map env = getEnv(action, runfilesDir, testTmpDir, resolvedPaths); Map info = new HashMap<>(); @@ -100,9 +101,8 @@ public class StandaloneTestStrategy extends TestStrategy { new RunfilesSupplierImpl( runfilesDir.asFragment(), action.getExecutionSettings().getRunfiles()), action, - action - .getTestProperties() - .getLocalResourceUsage(executionOptions.usingLocalTestJobs())); + action.getTestProperties().getLocalResourceUsage(executionOptions.usingLocalTestJobs()), + ImmutableSet.of(resolvedPaths.getXmlOutputPath().relativeTo(execRoot))); Executor executor = actionExecutionContext.getExecutor(); diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/LinuxSandboxedStrategy.java b/src/main/java/com/google/devtools/build/lib/sandbox/LinuxSandboxedStrategy.java index eea7f170b1..132b457365 100644 --- a/src/main/java/com/google/devtools/build/lib/sandbox/LinuxSandboxedStrategy.java +++ b/src/main/java/com/google/devtools/build/lib/sandbox/LinuxSandboxedStrategy.java @@ -130,6 +130,15 @@ public class LinuxSandboxedStrategy implements SpawnActionContext { int timeout = getTimeout(spawn); + ImmutableSet.Builder outputFiles = ImmutableSet.builder(); + for (PathFragment optionalOutput : spawn.getOptionalOutputFiles()) { + Preconditions.checkArgument(!optionalOutput.isAbsolute()); + outputFiles.add(optionalOutput); + } + for (ActionInput output : spawn.getOutputFiles()) { + outputFiles.add(new PathFragment(output.getExecPathString())); + } + try { final NamespaceSandboxRunner runner = new NamespaceSandboxRunner( @@ -140,7 +149,7 @@ public class LinuxSandboxedStrategy implements SpawnActionContext { spawn.getEnvironment(), execRoot.getPathFile(), outErr, - spawn.getOutputFiles(), + outputFiles.build(), timeout, !spawn.getExecutionInfo().containsKey("requires-network")); } finally { diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/NamespaceSandboxRunner.java b/src/main/java/com/google/devtools/build/lib/sandbox/NamespaceSandboxRunner.java index 7fae775e33..239d3acef6 100644 --- a/src/main/java/com/google/devtools/build/lib/sandbox/NamespaceSandboxRunner.java +++ b/src/main/java/com/google/devtools/build/lib/sandbox/NamespaceSandboxRunner.java @@ -18,7 +18,6 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.io.ByteStreams; import com.google.common.io.Files; -import com.google.devtools.build.lib.actions.ActionInput; import com.google.devtools.build.lib.actions.ExecException; import com.google.devtools.build.lib.actions.UserExecException; import com.google.devtools.build.lib.analysis.config.BinTools; @@ -115,6 +114,7 @@ public class NamespaceSandboxRunner { * @param env - environment to run sandbox in * @param cwd - current working directory * @param outErr - error output to capture sandbox's and command's stderr + * @param outputs - files to extract from the sandbox, paths are relative to the exec root * @throws ExecException */ public void run( @@ -122,7 +122,7 @@ public class NamespaceSandboxRunner { ImmutableMap env, File cwd, FileOutErr outErr, - Collection outputs, + Collection outputs, int timeout, boolean blockNetwork) throws IOException, ExecException { @@ -205,21 +205,20 @@ public class NamespaceSandboxRunner { copyOutputs(outputs); } - private void createFileSystem(Collection outputs) throws IOException { + private void createFileSystem(Collection outputs) throws IOException { FileSystemUtils.createDirectoryAndParents(sandboxPath); // Prepare the output directories in the sandbox. - for (ActionInput output : outputs) { - PathFragment parentDirectory = - new PathFragment(output.getExecPathString()).getParentDirectory(); - FileSystemUtils.createDirectoryAndParents(sandboxExecRoot.getRelative(parentDirectory)); + for (PathFragment output : outputs) { + FileSystemUtils.createDirectoryAndParents( + sandboxExecRoot.getRelative(output.getParentDirectory())); } } - private void copyOutputs(Collection outputs) throws IOException { - for (ActionInput output : outputs) { - Path source = sandboxExecRoot.getRelative(output.getExecPathString()); - Path target = execRoot.getRelative(output.getExecPathString()); + private void copyOutputs(Collection outputs) throws IOException { + for (PathFragment output : outputs) { + Path source = sandboxExecRoot.getRelative(output); + Path target = execRoot.getRelative(output); FileSystemUtils.createDirectoryAndParents(target.getParentDirectory()); if (source.isFile() || source.isSymbolicLink()) { Files.move(source.getPathFile(), target.getPathFile()); diff --git a/src/test/java/com/google/devtools/build/lib/actions/BaseSpawnTest.java b/src/test/java/com/google/devtools/build/lib/actions/BaseSpawnTest.java index 72fc7e9d25..07abe5283a 100644 --- a/src/test/java/com/google/devtools/build/lib/actions/BaseSpawnTest.java +++ b/src/test/java/com/google/devtools/build/lib/actions/BaseSpawnTest.java @@ -18,6 +18,7 @@ import static com.google.common.truth.Truth.assertThat; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; import com.google.devtools.build.lib.analysis.Runfiles; import com.google.devtools.build.lib.analysis.RunfilesSupplierImpl; import com.google.devtools.build.lib.testutil.Scratch; @@ -130,7 +131,9 @@ public class BaseSpawnTest { ImmutableMap.of(), runfilesManifests, runfilesSupplier, - null, null); + null, + null, + ImmutableSet.of()); } private static Artifact mkArtifact(String path, Root rootDir) { diff --git a/src/test/shell/bazel/bazel_test_test.sh b/src/test/shell/bazel/bazel_test_test.sh index 9e7f609fe8..92c57e8c4b 100755 --- a/src/test/shell/bazel/bazel_test_test.sh +++ b/src/test/shell/bazel/bazel_test_test.sh @@ -243,4 +243,29 @@ EOF done } +# Tests that the test.xml is extracted from the sandbox correctly. +function test_xml_is_present() { + mkdir -p dir + + cat <<'EOF' > dir/test.sh +#!/bin/sh +echo HELLO > $XML_OUTPUT_FILE +exit 0 +EOF + + chmod +x dir/test.sh + + cat <<'EOF' > dir/BUILD + sh_test( + name = "test", + srcs = [ "test.sh" ], + ) +EOF + + bazel test -s --test_output=streamed //dir:test &> $TEST_log || fail "expected success" + + xml_log=bazel-testlogs/dir/test/test.xml + [ -s $xml_log ] || fail "$xml_log was not present after test" +} + run_suite "test tests" -- cgit v1.2.3