aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/main/java/com/google/devtools/build/lib/sandbox/LinuxSandboxedStrategy.java39
-rw-r--r--src/main/java/com/google/devtools/build/lib/sandbox/NamespaceSandboxRunner.java45
-rw-r--r--src/main/java/com/google/devtools/build/lib/sandbox/SandboxActionContextProvider.java9
-rw-r--r--src/main/java/com/google/devtools/build/lib/sandbox/SandboxOptions.java10
-rw-r--r--src/main/java/com/google/devtools/build/lib/standalone/StandaloneSpawnStrategy.java5
-rw-r--r--src/test/java/BUILD7
-rw-r--r--src/test/java/com/google/devtools/build/lib/sandbox/LinuxSandboxedStrategyTest.java155
-rw-r--r--src/test/java/com/google/devtools/build/lib/sandbox/LinuxSandboxedStrategyTestCase.java126
-rw-r--r--src/test/java/com/google/devtools/build/lib/sandbox/LocalLinuxSandboxedStrategyTest.java93
-rw-r--r--src/test/java/com/google/devtools/build/lib/sandbox/SandboxLocalTests.java38
-rw-r--r--src/test/java/com/google/devtools/build/lib/sandbox/SandboxTests.java35
11 files changed, 432 insertions, 130 deletions
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 d1a1783e60..3baa7adbf7 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
@@ -16,7 +16,6 @@ package com.google.devtools.build.lib.sandbox;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
import com.google.common.base.Predicates;
-import com.google.common.base.Throwables;
import com.google.common.collect.ForwardingMap;
import com.google.common.collect.ImmutableMap;
import com.google.common.io.Files;
@@ -33,14 +32,8 @@ import com.google.devtools.build.lib.actions.SpawnActionContext;
import com.google.devtools.build.lib.actions.UserExecException;
import com.google.devtools.build.lib.analysis.BlazeDirectories;
import com.google.devtools.build.lib.analysis.config.RunUnder;
-import com.google.devtools.build.lib.events.Event;
-import com.google.devtools.build.lib.events.EventHandler;
import com.google.devtools.build.lib.rules.cpp.CppCompileAction;
import com.google.devtools.build.lib.rules.test.TestRunnerAction;
-import com.google.devtools.build.lib.runtime.BlazeRuntime;
-import com.google.devtools.build.lib.shell.AbnormalTerminationException;
-import com.google.devtools.build.lib.shell.CommandException;
-import com.google.devtools.build.lib.shell.TerminationStatus;
import com.google.devtools.build.lib.standalone.StandaloneSpawnStrategy;
import com.google.devtools.build.lib.syntax.Label;
import com.google.devtools.build.lib.unix.FilesystemUtils;
@@ -70,10 +63,11 @@ import java.util.concurrent.atomic.AtomicInteger;
public class LinuxSandboxedStrategy implements SpawnActionContext {
private final ExecutorService backgroundWorkers;
- private final BlazeRuntime blazeRuntime;
+ private final ImmutableMap<String, String> clientEnv;
private final BlazeDirectories blazeDirs;
private final Path execRoot;
private final boolean verboseFailures;
+ private final boolean sandboxDebug;
private final StandaloneSpawnStrategy standaloneStrategy;
private final UUID uuid = UUID.randomUUID();
private final AtomicInteger execCounter = new AtomicInteger();
@@ -112,12 +106,17 @@ public class LinuxSandboxedStrategy implements SpawnActionContext {
}
public LinuxSandboxedStrategy(
- BlazeRuntime blazeRuntime, boolean verboseFailures, ExecutorService backgroundWorkers) {
- this.blazeRuntime = blazeRuntime;
- this.blazeDirs = blazeRuntime.getDirectories();
+ Map<String, String> clientEnv,
+ BlazeDirectories blazeDirs,
+ ExecutorService backgroundWorkers,
+ boolean verboseFailures,
+ boolean sandboxDebug) {
+ this.clientEnv = ImmutableMap.copyOf(clientEnv);
+ this.blazeDirs = blazeDirs;
this.execRoot = blazeDirs.getExecRoot();
- this.verboseFailures = verboseFailures;
this.backgroundWorkers = backgroundWorkers;
+ this.verboseFailures = verboseFailures;
+ this.sandboxDebug = sandboxDebug;
this.standaloneStrategy = new StandaloneSpawnStrategy(blazeDirs.getExecRoot(), verboseFailures);
}
@@ -163,7 +162,7 @@ public class LinuxSandboxedStrategy implements SpawnActionContext {
try {
final NamespaceSandboxRunner runner =
- new NamespaceSandboxRunner(execRoot, sandboxPath, mounts, verboseFailures);
+ new NamespaceSandboxRunner(execRoot, sandboxPath, mounts, verboseFailures, sandboxDebug);
try {
runner.run(
spawn.getArguments(),
@@ -197,18 +196,8 @@ public class LinuxSandboxedStrategy implements SpawnActionContext {
}
});
}
- } catch (AbnormalTerminationException e) {
- TerminationStatus status = e.getResult().getTerminationStatus();
- boolean timedOut = !status.exited() && (status.getTerminatingSignal() == 14 /* SIGALRM */);
- throw new UserExecException("Error during execution of spawn", e, timedOut);
- } catch (CommandException e) {
- throw new UserExecException("Error during execution of spawn", e);
} catch (IOException e) {
- EventHandler handler = actionExecutionContext.getExecutor().getEventHandler();
- handler.handle(
- Event.error(
- "I/O error during sandboxed execution:\n" + Throwables.getStackTraceAsString(e)));
- throw new UserExecException("Could not execute spawn", e);
+ throw new UserExecException("I/O error during sandboxed execution", e);
}
}
@@ -477,7 +466,7 @@ public class LinuxSandboxedStrategy implements SpawnActionContext {
source = blazeDirs.getExecRoot().getRelative(sourceFragment);
} else {
List<Path> searchPath =
- SearchPath.parse(blazeDirs.getFileSystem(), blazeRuntime.getClientEnv().get("PATH"));
+ SearchPath.parse(blazeDirs.getFileSystem(), clientEnv.get("PATH"));
source = SearchPath.which(searchPath, runUnder.getCommand());
}
if (source != null) {
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 1667a03c54..1c2034a12d 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,11 +18,15 @@ import com.google.common.collect.ImmutableMap;
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.UserExecException;
import com.google.devtools.build.lib.analysis.config.BinTools;
import com.google.devtools.build.lib.runtime.BlazeRuntime;
+import com.google.devtools.build.lib.shell.AbnormalTerminationException;
import com.google.devtools.build.lib.shell.Command;
import com.google.devtools.build.lib.shell.CommandException;
+import com.google.devtools.build.lib.shell.TerminationStatus;
import com.google.devtools.build.lib.unix.FilesystemUtils;
+import com.google.devtools.build.lib.util.CommandFailureUtils;
import com.google.devtools.build.lib.util.OsUtils;
import com.google.devtools.build.lib.util.io.FileOutErr;
import com.google.devtools.build.lib.vfs.FileSystemUtils;
@@ -46,15 +50,21 @@ public class NamespaceSandboxRunner {
private final Path sandboxPath;
private final Path sandboxExecRoot;
private final ImmutableMap<Path, Path> mounts;
- private final boolean debug;
+ private final boolean verboseFailures;
+ private final boolean sandboxDebug;
public NamespaceSandboxRunner(
- Path execRoot, Path sandboxPath, ImmutableMap<Path, Path> mounts, boolean debug) {
+ Path execRoot,
+ Path sandboxPath,
+ ImmutableMap<Path, Path> mounts,
+ boolean verboseFailures,
+ boolean sandboxDebug) {
this.execRoot = execRoot;
this.sandboxPath = sandboxPath;
this.sandboxExecRoot = sandboxPath.getRelative(execRoot.asFragment().relativeTo("/"));
this.mounts = mounts;
- this.debug = debug;
+ this.verboseFailures = verboseFailures;
+ this.sandboxDebug = sandboxDebug;
}
static boolean isSupported(BlazeRuntime runtime) {
@@ -99,14 +109,14 @@ public class NamespaceSandboxRunner {
FileOutErr outErr,
Collection<? extends ActionInput> outputs,
int timeout)
- throws IOException, CommandException {
+ throws IOException, UserExecException {
createFileSystem(outputs);
List<String> args = new ArrayList<>();
args.add(execRoot.getRelative("_bin/namespace-sandbox").getPathString());
- if (debug) {
+ if (sandboxDebug) {
args.add("-D");
}
@@ -137,12 +147,25 @@ public class NamespaceSandboxRunner {
Command cmd = new Command(args.toArray(new String[0]), env, cwd);
- cmd.execute(
- /* stdin */ new byte[] {},
- Command.NO_OBSERVER,
- outErr.getOutputStream(),
- outErr.getErrorStream(),
- /* killSubprocessOnInterrupt */ true);
+ try {
+ cmd.execute(
+ /* stdin */ new byte[] {},
+ Command.NO_OBSERVER,
+ outErr.getOutputStream(),
+ outErr.getErrorStream(),
+ /* killSubprocessOnInterrupt */ true);
+ } catch (CommandException e) {
+ boolean timedOut = false;
+ if (e instanceof AbnormalTerminationException) {
+ TerminationStatus status =
+ ((AbnormalTerminationException) e).getResult().getTerminationStatus();
+ timedOut = !status.exited() && (status.getTerminatingSignal() == 14 /* SIGALRM */);
+ }
+ String message =
+ CommandFailureUtils.describeCommandFailure(
+ verboseFailures, spawnArguments, env, cwd.getPath());
+ throw new UserExecException(message, e, timedOut);
+ }
copyOutputs(outputs);
}
diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/SandboxActionContextProvider.java b/src/main/java/com/google/devtools/build/lib/sandbox/SandboxActionContextProvider.java
index 20b64c87ca..61cd2cdbd1 100644
--- a/src/main/java/com/google/devtools/build/lib/sandbox/SandboxActionContextProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/sandbox/SandboxActionContextProvider.java
@@ -35,10 +35,17 @@ public class SandboxActionContextProvider extends ActionContextProvider {
public SandboxActionContextProvider(
BlazeRuntime runtime, BuildRequest buildRequest, ExecutorService backgroundWorkers) {
boolean verboseFailures = buildRequest.getOptions(ExecutionOptions.class).verboseFailures;
+ boolean sandboxDebug = buildRequest.getOptions(SandboxOptions.class).sandboxDebug;
Builder<ActionContext> strategies = ImmutableList.builder();
if (OS.getCurrent() == OS.LINUX) {
- strategies.add(new LinuxSandboxedStrategy(runtime, verboseFailures, backgroundWorkers));
+ strategies.add(
+ new LinuxSandboxedStrategy(
+ runtime.getClientEnv(),
+ runtime.getDirectories(),
+ backgroundWorkers,
+ verboseFailures,
+ sandboxDebug));
}
this.strategies = strategies.build();
diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/SandboxOptions.java b/src/main/java/com/google/devtools/build/lib/sandbox/SandboxOptions.java
index ad4fa50dc3..4c13ddb7ec 100644
--- a/src/main/java/com/google/devtools/build/lib/sandbox/SandboxOptions.java
+++ b/src/main/java/com/google/devtools/build/lib/sandbox/SandboxOptions.java
@@ -28,4 +28,14 @@ public class SandboxOptions extends OptionsBase {
help = "Do not print a warning when sandboxed execution is not supported on this system."
)
public boolean ignoreUnsupportedSandboxing;
+
+ @Option(
+ name = "sandbox_debug",
+ defaultValue = "false",
+ category = "strategy",
+ help =
+ "Let the sandbox print debug information on execution. This might help developers of "
+ + "Bazel or Skylark rules with debugging failures due to missing input files, etc."
+ )
+ public boolean sandboxDebug;
}
diff --git a/src/main/java/com/google/devtools/build/lib/standalone/StandaloneSpawnStrategy.java b/src/main/java/com/google/devtools/build/lib/standalone/StandaloneSpawnStrategy.java
index ed034d5e49..ae03d191ad 100644
--- a/src/main/java/com/google/devtools/build/lib/standalone/StandaloneSpawnStrategy.java
+++ b/src/main/java/com/google/devtools/build/lib/standalone/StandaloneSpawnStrategy.java
@@ -41,7 +41,6 @@ import java.util.List;
@ExecutionStrategy(name = { "standalone" }, contextType = SpawnActionContext.class)
public class StandaloneSpawnStrategy implements SpawnActionContext {
private final boolean verboseFailures;
-
private final Path processWrapper;
public StandaloneSpawnStrategy(Path execRoot, boolean verboseFailures) {
@@ -70,7 +69,7 @@ public class StandaloneSpawnStrategy implements SpawnActionContext {
try {
timeout = Integer.parseInt(timeoutStr);
} catch (NumberFormatException e) {
- throw new UserExecException("could not parse timeout: " + e);
+ throw new UserExecException("could not parse timeout: ", e);
}
}
@@ -115,7 +114,7 @@ public class StandaloneSpawnStrategy implements SpawnActionContext {
} catch (CommandException e) {
String message = CommandFailureUtils.describeCommandFailure(
verboseFailures, spawn.getArguments(), spawn.getEnvironment(), cwd);
- throw new UserExecException(String.format("%s: %s", message, e));
+ throw new UserExecException(message, e);
}
}
diff --git a/src/test/java/BUILD b/src/test/java/BUILD
index 8315e1ccc0..9f3ead75c8 100644
--- a/src/test/java/BUILD
+++ b/src/test/java/BUILD
@@ -586,8 +586,15 @@ java_test(
args = ["com.google.devtools.build.lib.AllTests"],
data = [":embedded_scripts"],
deps = [
+ ":actions_testutil",
":analysis_testutil",
+ ":foundations_testutil",
":testutil",
+ "//src/main/java:actions",
+ "//src/main/java:analysis-exec-rules-skyframe",
+ "//src/main/java:events",
+ "//src/main/java:options",
+ "//src/main/java:shell",
"//src/main/java:vfs",
"//src/main/java/com/google/devtools/build/lib/sandbox",
"//third_party:guava",
diff --git a/src/test/java/com/google/devtools/build/lib/sandbox/LinuxSandboxedStrategyTest.java b/src/test/java/com/google/devtools/build/lib/sandbox/LinuxSandboxedStrategyTest.java
index 74333e3d27..f91bb0dbb8 100644
--- a/src/test/java/com/google/devtools/build/lib/sandbox/LinuxSandboxedStrategyTest.java
+++ b/src/test/java/com/google/devtools/build/lib/sandbox/LinuxSandboxedStrategyTest.java
@@ -20,20 +20,14 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import com.google.devtools.build.lib.sandbox.LinuxSandboxedStrategy.MountMap;
-import com.google.devtools.build.lib.testutil.TestUtils;
-import com.google.devtools.build.lib.vfs.FileSystem;
import com.google.devtools.build.lib.vfs.FileSystemUtils;
import com.google.devtools.build.lib.vfs.Path;
import com.google.devtools.build.lib.vfs.PathFragment;
-import com.google.devtools.build.lib.vfs.UnixFileSystem;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
-import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.ArrayList;
@@ -53,28 +47,7 @@ import java.util.Map.Entry;
* tree of files given only the set of input files.
*/
@RunWith(JUnit4.class)
-public class LinuxSandboxedStrategyTest {
- private FileSystem testFS;
- private Path workingDir;
- private Path fakeSandboxDir;
-
- @Before
- public void setUp() throws Exception {
- testFS = new UnixFileSystem();
- workingDir = testFS.getPath(new File(TestUtils.tmpDir()).getCanonicalPath());
- fakeSandboxDir = workingDir.getRelative("sandbox");
- fakeSandboxDir.createDirectory();
- }
-
- @After
- public void tearDown() throws Exception {
- FileSystemUtils.deleteTreesBelow(workingDir);
- }
-
- private Path getSandboxPath(Path entry) {
- return fakeSandboxDir.getRelative(entry.asFragment().relativeTo("/"));
- }
-
+public class LinuxSandboxedStrategyTest extends LinuxSandboxedStrategyTestCase {
/**
* Strips the working directory (which can be very long) from the file names in the input map, to
* make assertion failures easier to read.
@@ -82,42 +55,30 @@ public class LinuxSandboxedStrategyTest {
private ImmutableMap<String, String> userFriendlyMap(Map<Path, Path> input) {
ImmutableMap.Builder<String, String> userFriendlyMap = ImmutableMap.builder();
for (Entry<Path, Path> entry : input.entrySet()) {
- String key = entry.getKey().getPathString().replace(workingDir.getPathString(), "");
- String value = entry.getValue().getPathString().replace(workingDir.getPathString(), "");
+ String key = entry.getKey().getPathString().replace(workspaceDir.getPathString(), "");
+ String value = entry.getValue().getPathString().replace(workspaceDir.getPathString(), "");
userFriendlyMap.put(key, value);
}
return userFriendlyMap.build();
}
- private void createTreeStructure(Map<String, String> linksAndFiles) throws IOException {
- for (Entry<String, String> entry : linksAndFiles.entrySet()) {
- Path filePath = workingDir.getRelative(entry.getKey());
- String linkTarget = entry.getValue();
-
- FileSystemUtils.createDirectoryAndParents(filePath.getParentDirectory());
-
- if (!linkTarget.isEmpty()) {
- filePath.createSymbolicLink(new PathFragment(linkTarget));
- } else if (filePath.getPathString().endsWith("/")) {
- filePath.createDirectory();
- } else {
- FileSystemUtils.createEmptyFile(filePath);
- }
- }
- }
-
/**
* Takes a map of file specifications, creates the necessary files / symlinks / dirs,
* mounts files listed in customMount at their canonical location in the sandbox and returns the
* output of {@code LinuxSandboxedStrategy#fixMounts} for it.
*/
+ private ImmutableMap<String, String> userFriendlyMounts(
+ Map<String, String> linksAndFiles, List<String> customMounts) throws IOException {
+ return userFriendlyMap(mounts(linksAndFiles, customMounts));
+ }
+
private ImmutableMap<Path, Path> mounts(
Map<String, String> linksAndFiles, List<String> customMounts) throws IOException {
createTreeStructure(linksAndFiles);
ImmutableMap.Builder<Path, Path> mounts = ImmutableMap.builder();
for (String customMount : customMounts) {
- Path customMountPath = workingDir.getRelative(customMount);
+ Path customMountPath = workspaceDir.getRelative(customMount);
mounts.put(getSandboxPath(customMountPath), customMountPath);
}
return LinuxSandboxedStrategy.validateMounts(
@@ -126,45 +87,57 @@ public class LinuxSandboxedStrategyTest {
fakeSandboxDir, LinuxSandboxedStrategy.withRecursedDirs(mounts.build())));
}
- private ImmutableMap<String, String> userFriendlyMounts(
- Map<String, String> linksAndFiles, List<String> customMounts) throws IOException {
- return userFriendlyMap(mounts(linksAndFiles, customMounts));
- }
-
/**
* Takes a map of file specifications, creates the necessary files / symlinks / dirs,
* mounts the first file of the specification at its canonical location in the sandbox and returns
* the output of {@code LinuxSandboxedStrategy#fixMounts} for it.
*/
- private Map<Path, Path> mounts(Map<String, String> linksAndFiles) throws IOException {
- return mounts(
- linksAndFiles, ImmutableList.of(Iterables.getFirst(linksAndFiles.keySet(), null)));
- }
-
private Map<String, String> userFriendlyMounts(Map<String, String> linksAndFiles)
throws IOException {
return userFriendlyMap(mounts(linksAndFiles));
}
+ private Map<Path, Path> mounts(Map<String, String> linksAndFiles) throws IOException {
+ return mounts(
+ linksAndFiles, ImmutableList.of(Iterables.getFirst(linksAndFiles.keySet(), null)));
+ }
+
/**
* Returns a map of mount entries for a list files, which can be used to assert that all
* expected mounts have been made by the LinuxSandboxedStrategy.
*/
+ private ImmutableMap<String, String> userFriendlyAsserts(List<String> asserts) {
+ return userFriendlyMap(asserts(asserts));
+ }
+
private ImmutableMap<Path, Path> asserts(List<String> asserts) {
ImmutableMap.Builder<Path, Path> pathifiedAsserts = ImmutableMap.builder();
for (String fileName : asserts) {
- Path inputPath = workingDir.getRelative(fileName);
+ Path inputPath = workspaceDir.getRelative(fileName);
pathifiedAsserts.put(getSandboxPath(inputPath), inputPath);
}
return pathifiedAsserts.build();
}
- private ImmutableMap<String, String> userFriendlyAsserts(List<String> asserts) {
- return userFriendlyMap(asserts(asserts));
+ private void createTreeStructure(Map<String, String> linksAndFiles) throws IOException {
+ for (Entry<String, String> entry : linksAndFiles.entrySet()) {
+ Path filePath = workspaceDir.getRelative(entry.getKey());
+ String linkTarget = entry.getValue();
+
+ FileSystemUtils.createDirectoryAndParents(filePath.getParentDirectory());
+
+ if (!linkTarget.isEmpty()) {
+ filePath.createSymbolicLink(new PathFragment(linkTarget));
+ } else if (filePath.getPathString().endsWith("/")) {
+ filePath.createDirectory();
+ } else {
+ FileSystemUtils.createEmptyFile(filePath);
+ }
+ }
}
@Test
- public void resolvesRelativeFileToFileSymlinkInSameDir() throws IOException {
+ public void testResolvesRelativeFileToFileSymlinkInSameDir() throws IOException {
Map<String, String> testFiles = new LinkedHashMap<>();
testFiles.put("symlink.txt", "goal.txt");
testFiles.put("goal.txt", "");
@@ -177,7 +150,7 @@ public class LinuxSandboxedStrategyTest {
}
@Test
- public void resolvesRelativeFileToFileSymlinkInSubDir() throws IOException {
+ public void testResolvesRelativeFileToFileSymlinkInSubDir() throws IOException {
Map<String, String> testFiles =
ImmutableMap.of(
"symlink.txt", "x/goal.txt",
@@ -188,7 +161,7 @@ public class LinuxSandboxedStrategyTest {
}
@Test
- public void resolvesRelativeFileToFileSymlinkInParentDir() throws IOException {
+ public void testResolvesRelativeFileToFileSymlinkInParentDir() throws IOException {
Map<String, String> testFiles =
ImmutableMap.of(
"x/symlink.txt", "../goal.txt",
@@ -200,7 +173,7 @@ public class LinuxSandboxedStrategyTest {
}
@Test
- public void recursesSubDirs() throws IOException {
+ public void testRecursesSubDirs() throws IOException {
ImmutableList<String> inputFile = ImmutableList.of("a/b");
Map<String, String> testFiles =
@@ -219,7 +192,7 @@ public class LinuxSandboxedStrategyTest {
* Test that the algorithm correctly identifies and refuses symlink loops.
*/
@Test
- public void catchesSymlinkLoop() throws IOException {
+ public void testCatchesSymlinkLoop() throws IOException {
try {
mounts(
ImmutableMap.of(
@@ -231,7 +204,7 @@ public class LinuxSandboxedStrategyTest {
.hasMessage(
String.format(
"%s (Too many levels of symbolic links)",
- workingDir.getRelative("a").getPathString()));
+ workspaceDir.getRelative("a").getPathString()));
}
}
@@ -240,7 +213,7 @@ public class LinuxSandboxedStrategyTest {
* directories (e.g. "a -> dir/file/file").
*/
@Test
- public void catchesIllegalSymlink() throws IOException {
+ public void testCatchesIllegalSymlink() throws IOException {
try {
mounts(
ImmutableMap.of(
@@ -250,19 +223,20 @@ public class LinuxSandboxedStrategyTest {
} catch (IOException e) {
assertThat(e)
.hasMessage(
- String.format("%s (Not a directory)", workingDir.getRelative("a/c").getPathString()));
+ String.format(
+ "%s (Not a directory)", workspaceDir.getRelative("a/c").getPathString()));
}
}
@Test
public void testParseManifestFile() throws IOException {
- Path targetDir = workingDir.getRelative("runfiles");
+ Path targetDir = workspaceDir.getRelative("runfiles");
targetDir.createDirectory();
- Path testFile = workingDir.getRelative("testfile");
+ Path testFile = workspaceDir.getRelative("testfile");
FileSystemUtils.createEmptyFile(testFile);
- Path manifestFile = workingDir.getRelative("MANIFEST");
+ Path manifestFile = workspaceDir.getRelative("MANIFEST");
FileSystemUtils.writeContent(
manifestFile,
Charset.defaultCharset(),
@@ -279,47 +253,47 @@ public class LinuxSandboxedStrategyTest {
fakeSandboxDir.getRelative("runfiles/x/testfile"),
testFile,
fakeSandboxDir.getRelative("runfiles/x/emptyfile"),
- testFS.getPath("/dev/null"))));
+ fileSystem.getPath("/dev/null"))));
}
@Test
public void testMountMapWithNormalMounts() throws IOException {
// Allowed: Just two normal mounts (a -> sandbox/a, b -> sandbox/b)
MountMap<Path, Path> mounts = new MountMap<>();
- mounts.put(fakeSandboxDir.getRelative("a"), workingDir.getRelative("a"));
- mounts.put(fakeSandboxDir.getRelative("b"), workingDir.getRelative("b"));
+ mounts.put(fakeSandboxDir.getRelative("a"), workspaceDir.getRelative("a"));
+ mounts.put(fakeSandboxDir.getRelative("b"), workspaceDir.getRelative("b"));
assertThat(mounts)
.isEqualTo(
ImmutableMap.of(
- fakeSandboxDir.getRelative("a"), workingDir.getRelative("a"),
- fakeSandboxDir.getRelative("b"), workingDir.getRelative("b")));
+ fakeSandboxDir.getRelative("a"), workspaceDir.getRelative("a"),
+ fakeSandboxDir.getRelative("b"), workspaceDir.getRelative("b")));
}
@Test
public void testMountMapWithSameMountTwice() throws IOException {
// Allowed: Mount same thing twice (a -> sandbox/a, a -> sandbox/a, b -> sandbox/b)
MountMap<Path, Path> mounts = new MountMap<>();
- mounts.put(fakeSandboxDir.getRelative("a"), workingDir.getRelative("a"));
- mounts.put(fakeSandboxDir.getRelative("a"), workingDir.getRelative("a"));
- mounts.put(fakeSandboxDir.getRelative("b"), workingDir.getRelative("b"));
+ mounts.put(fakeSandboxDir.getRelative("a"), workspaceDir.getRelative("a"));
+ mounts.put(fakeSandboxDir.getRelative("a"), workspaceDir.getRelative("a"));
+ mounts.put(fakeSandboxDir.getRelative("b"), workspaceDir.getRelative("b"));
assertThat(mounts)
.isEqualTo(
ImmutableMap.of(
- fakeSandboxDir.getRelative("a"), workingDir.getRelative("a"),
- fakeSandboxDir.getRelative("b"), workingDir.getRelative("b")));
+ fakeSandboxDir.getRelative("a"), workspaceDir.getRelative("a"),
+ fakeSandboxDir.getRelative("b"), workspaceDir.getRelative("b")));
}
@Test
public void testMountMapWithOneThingTwoTargets() throws IOException {
// Allowed: Mount one thing in two targets (x -> sandbox/a, x -> sandbox/b)
MountMap<Path, Path> mounts = new MountMap<>();
- mounts.put(fakeSandboxDir.getRelative("a"), workingDir.getRelative("x"));
- mounts.put(fakeSandboxDir.getRelative("b"), workingDir.getRelative("x"));
+ mounts.put(fakeSandboxDir.getRelative("a"), workspaceDir.getRelative("x"));
+ mounts.put(fakeSandboxDir.getRelative("b"), workspaceDir.getRelative("x"));
assertThat(mounts)
.isEqualTo(
ImmutableMap.of(
- fakeSandboxDir.getRelative("a"), workingDir.getRelative("x"),
- fakeSandboxDir.getRelative("b"), workingDir.getRelative("x")));
+ fakeSandboxDir.getRelative("a"), workspaceDir.getRelative("x"),
+ fakeSandboxDir.getRelative("b"), workspaceDir.getRelative("x")));
}
@Test
@@ -327,17 +301,18 @@ public class LinuxSandboxedStrategyTest {
// Forbidden: Mount two things onto the same target (x -> sandbox/a, y -> sandbox/a)
try {
MountMap<Path, Path> mounts = new MountMap<>();
- mounts.put(fakeSandboxDir.getRelative("x"), workingDir.getRelative("a"));
- mounts.put(fakeSandboxDir.getRelative("x"), workingDir.getRelative("b"));
+ mounts.put(fakeSandboxDir.getRelative("x"), workspaceDir.getRelative("a"));
+ mounts.put(fakeSandboxDir.getRelative("x"), workspaceDir.getRelative("b"));
fail();
} catch (IllegalArgumentException e) {
assertThat(e)
.hasMessage(
String.format(
"Cannot mount both '%s' and '%s' onto '%s'",
- workingDir.getRelative("a"),
- workingDir.getRelative("b"),
+ workspaceDir.getRelative("a"),
+ workspaceDir.getRelative("b"),
fakeSandboxDir.getRelative("x")));
}
}
+
}
diff --git a/src/test/java/com/google/devtools/build/lib/sandbox/LinuxSandboxedStrategyTestCase.java b/src/test/java/com/google/devtools/build/lib/sandbox/LinuxSandboxedStrategyTestCase.java
new file mode 100644
index 0000000000..7fb6c8bf4d
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/sandbox/LinuxSandboxedStrategyTestCase.java
@@ -0,0 +1,126 @@
+// Copyright 2015 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package com.google.devtools.build.lib.sandbox;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.eventbus.EventBus;
+import com.google.common.util.concurrent.MoreExecutors;
+import com.google.devtools.build.lib.actions.ActionContextProvider;
+import com.google.devtools.build.lib.actions.BlazeExecutor;
+import com.google.devtools.build.lib.actions.Executor.ActionContext;
+import com.google.devtools.build.lib.actions.SpawnActionContext;
+import com.google.devtools.build.lib.analysis.BlazeDirectories;
+import com.google.devtools.build.lib.events.PrintingEventHandler;
+import com.google.devtools.build.lib.events.Reporter;
+import com.google.devtools.build.lib.exec.ExecutionOptions;
+import com.google.devtools.build.lib.testutil.BlazeTestUtils;
+import com.google.devtools.build.lib.testutil.TestFileOutErr;
+import com.google.devtools.build.lib.testutil.TestUtils;
+import com.google.devtools.build.lib.util.BlazeClock;
+import com.google.devtools.build.lib.vfs.FileSystem;
+import com.google.devtools.build.lib.vfs.FileSystemUtils;
+import com.google.devtools.build.lib.vfs.Path;
+import com.google.devtools.build.lib.vfs.util.FileSystems;
+import com.google.devtools.common.options.OptionsParser;
+
+import org.junit.Before;
+
+import java.io.IOException;
+
+/**
+ * Common parts of all {@link LinuxSandboxedStrategy} tests.
+ */
+public class LinuxSandboxedStrategyTestCase {
+ private Reporter reporter = new Reporter(PrintingEventHandler.ERRORS_AND_WARNINGS_TO_STDERR);
+ private Path outputBase;
+
+ protected FileSystem fileSystem;
+ protected Path workspaceDir;
+ protected Path fakeSandboxDir;
+ protected Path fakeSandboxExecRoot;
+
+ protected BlazeExecutor executor;
+ protected BlazeDirectories blazeDirs;
+
+ protected TestFileOutErr outErr = new TestFileOutErr();
+
+ protected String out() {
+ return outErr.outAsLatin1();
+ }
+
+ protected String err() {
+ return outErr.errAsLatin1();
+ }
+
+ protected Path getSandboxPath(Path entry) {
+ return fakeSandboxDir.getRelative(entry.asFragment().relativeTo("/"));
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ Path testRoot = createTestRoot();
+
+ workspaceDir = testRoot.getRelative("workspace");
+ workspaceDir.createDirectory();
+
+ outputBase = testRoot.getRelative("outputBase");
+ outputBase.createDirectory();
+
+ fakeSandboxDir = testRoot.getRelative("sandbox");
+ fakeSandboxDir.createDirectory();
+
+ blazeDirs = new BlazeDirectories(outputBase, outputBase, workspaceDir);
+ BlazeTestUtils.getIntegrationBinTools(blazeDirs);
+
+ OptionsParser optionsParser =
+ OptionsParser.newOptionsParser(ExecutionOptions.class, SandboxOptions.class);
+ optionsParser.parse("--verbose_failures");
+
+ EventBus bus = new EventBus();
+
+ this.executor =
+ new BlazeExecutor(
+ blazeDirs.getExecRoot(),
+ blazeDirs.getOutputPath(),
+ reporter,
+ bus,
+ BlazeClock.instance(),
+ optionsParser,
+ /* verboseFailures */ true,
+ /* showSubcommands */ false,
+ ImmutableList.<ActionContext>of(),
+ ImmutableMap.<String, SpawnActionContext>of(
+ "",
+ new LinuxSandboxedStrategy(
+ ImmutableMap.<String, String>of(),
+ blazeDirs,
+ MoreExecutors.newDirectExecutorService(),
+ true,
+ false)),
+ ImmutableList.<ActionContextProvider>of());
+ }
+
+ private Path createTestRoot() throws IOException {
+ fileSystem = FileSystems.initDefaultAsNative();
+ Path testRoot = fileSystem.getPath(TestUtils.tmpDir());
+ try {
+ FileSystemUtils.deleteTreesBelow(testRoot);
+ } catch (IOException e) {
+ System.err.println("Failed to remove directory " + testRoot + ": " + e.getMessage());
+ throw e;
+ }
+ return testRoot;
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/lib/sandbox/LocalLinuxSandboxedStrategyTest.java b/src/test/java/com/google/devtools/build/lib/sandbox/LocalLinuxSandboxedStrategyTest.java
new file mode 100644
index 0000000000..7563d1fadb
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/sandbox/LocalLinuxSandboxedStrategyTest.java
@@ -0,0 +1,93 @@
+// Copyright 2015 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package com.google.devtools.build.lib.sandbox;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.fail;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.devtools.build.lib.actions.ActionExecutionContext;
+import com.google.devtools.build.lib.actions.ActionMetadata;
+import com.google.devtools.build.lib.actions.BaseSpawn;
+import com.google.devtools.build.lib.actions.ResourceSet;
+import com.google.devtools.build.lib.actions.Spawn;
+import com.google.devtools.build.lib.actions.UserExecException;
+import com.google.devtools.build.lib.actions.util.ActionsTestUtil;
+import com.google.devtools.build.lib.exec.SingleBuildFileCache;
+import com.google.devtools.build.lib.shell.BadExitStatusException;
+import com.google.devtools.build.lib.testutil.TestSpec;
+import com.google.devtools.build.lib.util.CommandFailureUtils;
+import com.google.devtools.build.lib.util.OS;
+import com.google.devtools.build.lib.vfs.Path;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.Arrays;
+import java.util.Map;
+
+/**
+ * Tests for {@code LinuxSandboxedStrategy} that must run locally, because they need to actually
+ * run the namespace-sandbox binary.
+ */
+@TestSpec(localOnly = true, supportedOs = OS.LINUX)
+@RunWith(JUnit4.class)
+public class LocalLinuxSandboxedStrategyTest extends LinuxSandboxedStrategyTestCase {
+ protected Spawn createSpawn(String... arguments) {
+ Map<String, String> environment = ImmutableMap.<String, String>of();
+ Map<String, String> executionInfo = ImmutableMap.<String, String>of();
+ ActionMetadata action = new ActionsTestUtil.NullAction();
+ ResourceSet localResources = ResourceSet.ZERO;
+ return new BaseSpawn(
+ Arrays.asList(arguments), environment, executionInfo, action, localResources);
+ }
+
+ protected ActionExecutionContext createContext() {
+ Path execRoot = executor.getExecRoot();
+ return new ActionExecutionContext(
+ executor,
+ new SingleBuildFileCache(execRoot.getPathString(), execRoot.getFileSystem()),
+ null,
+ outErr,
+ null);
+ }
+
+ @Test
+ public void testExecutionSuccess() throws Exception {
+ Spawn spawn = createSpawn("/bin/sh", "-c", "echo Hello, world.; touch dummy");
+ executor.getSpawnActionContext(spawn.getMnemonic()).exec(spawn, createContext());
+ assertThat(out()).isEqualTo("Hello, world.\n");
+ assertThat(err()).isEmpty();
+ }
+
+ @Test
+ public void testExecutionFailurePrintsCorrectMessage() throws Exception {
+ Spawn spawn = createSpawn("/bin/sh", "-c", "echo ERROR >&2; exit 1");
+ try {
+ executor.getSpawnActionContext(spawn.getMnemonic()).exec(spawn, createContext());
+ fail();
+ } catch (UserExecException e) {
+ assertThat(err()).isEqualTo("ERROR\n");
+ assertThat(e.getMessage())
+ .startsWith(
+ CommandFailureUtils.describeCommandFailure(
+ true,
+ spawn.getArguments(),
+ spawn.getEnvironment(),
+ blazeDirs.getExecRoot().toString()));
+ assertThat(e.getCause()).isInstanceOf(BadExitStatusException.class);
+ }
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/lib/sandbox/SandboxLocalTests.java b/src/test/java/com/google/devtools/build/lib/sandbox/SandboxLocalTests.java
new file mode 100644
index 0000000000..5a72adeeac
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/sandbox/SandboxLocalTests.java
@@ -0,0 +1,38 @@
+// Copyright 2015 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package com.google.devtools.build.lib.sandbox;
+
+import com.google.common.base.Predicates;
+import com.google.devtools.build.lib.testutil.BlazeTestSuiteBuilder;
+import com.google.devtools.build.lib.testutil.CustomSuite;
+
+import org.junit.runner.RunWith;
+
+import java.util.Set;
+
+/**
+ * Test suite that runs all tests that are local-only.
+ */
+@RunWith(CustomSuite.class)
+public class SandboxLocalTests extends BlazeTestSuiteBuilder {
+ public static Set<Class<?>> suite() {
+ return new SandboxLocalTests()
+ .getBuilder()
+ .matchClasses(
+ Predicates.and(
+ BlazeTestSuiteBuilder.TEST_IS_LOCAL_ONLY,
+ BlazeTestSuiteBuilder.TEST_SUPPORTS_CURRENT_OS))
+ .create();
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/lib/sandbox/SandboxTests.java b/src/test/java/com/google/devtools/build/lib/sandbox/SandboxTests.java
new file mode 100644
index 0000000000..ee676cc244
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/sandbox/SandboxTests.java
@@ -0,0 +1,35 @@
+// Copyright 2015 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package com.google.devtools.build.lib.sandbox;
+
+import com.google.common.base.Predicates;
+import com.google.devtools.build.lib.testutil.BlazeTestSuiteBuilder;
+import com.google.devtools.build.lib.testutil.CustomSuite;
+
+import org.junit.runner.RunWith;
+
+import java.util.Set;
+
+/**
+ * Test suite that runs all tests that are not local-only.
+ */
+@RunWith(CustomSuite.class)
+public class SandboxTests extends BlazeTestSuiteBuilder {
+ public static Set<Class<?>> suite() {
+ return new SandboxTests()
+ .getBuilder()
+ .matchClasses(Predicates.not(BlazeTestSuiteBuilder.TEST_IS_LOCAL_ONLY))
+ .create();
+ }
+}