aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/test/java/com/google/devtools
diff options
context:
space:
mode:
authorGravatar Michajlo Matijkiw <michajlo@google.com>2016-02-10 16:26:54 +0000
committerGravatar Dmitry Lomov <dslomov@google.com>2016-02-11 11:48:34 +0000
commita0eefb52f529b73c6cb92f0a762853646ea2eae6 (patch)
treea1fa72ad1cab1cc543edbc4c292784464471585f /src/test/java/com/google/devtools
parent466873e272d040f466150469ceb172e80a6a67f4 (diff)
-- MOS_MIGRATED_REVID=114329043
Diffstat (limited to 'src/test/java/com/google/devtools')
-rw-r--r--src/test/java/com/google/devtools/build/lib/actions/util/TestAction.java2
-rw-r--r--src/test/java/com/google/devtools/build/lib/skyframe/TreeArtifactBuildTest.java773
2 files changed, 1 insertions, 774 deletions
diff --git a/src/test/java/com/google/devtools/build/lib/actions/util/TestAction.java b/src/test/java/com/google/devtools/build/lib/actions/util/TestAction.java
index 1877b7252f..4b5485dba4 100644
--- a/src/test/java/com/google/devtools/build/lib/actions/util/TestAction.java
+++ b/src/test/java/com/google/devtools/build/lib/actions/util/TestAction.java
@@ -45,7 +45,7 @@ public class TestAction extends AbstractAction {
private static final ResourceSet RESOURCES =
ResourceSet.createWithRamCpuIo(/*memoryMb=*/1.0, /*cpu=*/0.1, /*io=*/0.0);
- protected final Callable<Void> effect;
+ private final Callable<Void> effect;
/** Use this constructor if the effect can't throw exceptions. */
public TestAction(Runnable effect,
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/TreeArtifactBuildTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/TreeArtifactBuildTest.java
deleted file mode 100644
index 18d54e96c1..0000000000
--- a/src/test/java/com/google/devtools/build/lib/skyframe/TreeArtifactBuildTest.java
+++ /dev/null
@@ -1,773 +0,0 @@
-// Copyright 2016 The Bazel Authors. 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.skyframe;
-
-import static com.google.common.base.Throwables.getRootCause;
-import static com.google.common.truth.Truth.assertThat;
-import static com.google.devtools.build.lib.actions.ActionInputHelper.artifactFile;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import com.google.common.base.Function;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Collections2;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
-import com.google.common.hash.Hashing;
-import com.google.common.util.concurrent.Runnables;
-import com.google.devtools.build.lib.actions.ActionExecutionContext;
-import com.google.devtools.build.lib.actions.ActionExecutionException;
-import com.google.devtools.build.lib.actions.ActionInput;
-import com.google.devtools.build.lib.actions.ActionInputHelper;
-import com.google.devtools.build.lib.actions.Artifact;
-import com.google.devtools.build.lib.actions.Artifact.SpecialArtifact;
-import com.google.devtools.build.lib.actions.Artifact.SpecialArtifactType;
-import com.google.devtools.build.lib.actions.ArtifactFile;
-import com.google.devtools.build.lib.actions.BuildFailedException;
-import com.google.devtools.build.lib.actions.Root;
-import com.google.devtools.build.lib.actions.TestExecException;
-import com.google.devtools.build.lib.actions.cache.InjectedStat;
-import com.google.devtools.build.lib.actions.cache.MetadataHandler;
-import com.google.devtools.build.lib.actions.util.TestAction;
-import com.google.devtools.build.lib.testutil.TestUtils;
-import com.google.devtools.build.lib.util.AbruptExitException;
-import com.google.devtools.build.lib.vfs.FileStatus;
-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.Symlinks;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-import java.io.IOException;
-import java.nio.charset.Charset;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-
-import javax.annotation.Nullable;
-
-/** Timestamp builder tests for TreeArtifacts. */
-@RunWith(JUnit4.class)
-public class TreeArtifactBuildTest extends TimestampBuilderTestCase {
- // Common Artifacts, ArtifactFiles, and Buttons. These aren't all used in all tests, but they're
- // used often enough that we can save ourselves a lot of copy-pasted code by creating them
- // in setUp().
-
- Artifact in;
-
- Artifact outOne;
- ArtifactFile outOneFileOne;
- ArtifactFile outOneFileTwo;
- Button buttonOne = new Button();
-
- Artifact outTwo;
- ArtifactFile outTwoFileOne;
- ArtifactFile outTwoFileTwo;
- Button buttonTwo = new Button();
-
- @Before
- public void setUp() throws Exception {
- in = createSourceArtifact("input");
- writeFile(in, "input_content");
-
- outOne = createTreeArtifact("outputOne");
- outOneFileOne = artifactFile(outOne, "out_one_file_one");
- outOneFileTwo = artifactFile(outOne, "out_one_file_two");
-
- outTwo = createTreeArtifact("outputTwo");
- outTwoFileOne = artifactFile(outTwo, "out_one_file_one");
- outTwoFileTwo = artifactFile(outTwo, "out_one_file_two");
- }
-
- /** Simple smoke test. If this isn't passing, something is very wrong... */
- @Test
- public void testTreeArtifactSimpleCase() throws Exception {
- TouchingTestAction action = new TouchingTestAction(outOneFileOne, outOneFileTwo);
- registerAction(action);
- buildArtifact(action.getSoleOutput());
-
- assertTrue(outOneFileOne.getPath().exists());
- assertTrue(outOneFileTwo.getPath().exists());
- }
-
- /** Simple test for the case with dependencies. */
- @Test
- public void testDependentTreeArtifacts() throws Exception {
- TouchingTestAction actionOne = new TouchingTestAction(outOneFileOne, outOneFileTwo);
- registerAction(actionOne);
-
- CopyTreeAction actionTwo = new CopyTreeAction(
- ImmutableList.of(outOneFileOne, outOneFileTwo),
- ImmutableList.of(outTwoFileOne, outTwoFileTwo));
- registerAction(actionTwo);
-
- buildArtifact(outTwo);
-
- assertTrue(outOneFileOne.getPath().exists());
- assertTrue(outOneFileTwo.getPath().exists());
- assertTrue(outTwoFileOne.getPath().exists());
- assertTrue(outTwoFileTwo.getPath().exists());
- }
-
- /** Unchanged TreeArtifact outputs should not cause reexecution. */
- @Test
- public void testCacheCheckingForTreeArtifactsDoesNotCauseReexecution() throws Exception {
- Artifact outOne = createTreeArtifact("outputOne");
- Button buttonOne = new Button();
-
- Artifact outTwo = createTreeArtifact("outputTwo");
- Button buttonTwo = new Button();
-
- TouchingTestAction actionOne = new TouchingTestAction(
- buttonOne, outOne, "file_one", "file_two");
- registerAction(actionOne);
-
- CopyTreeAction actionTwo = new CopyTreeAction(
- buttonTwo, outOne, outTwo, "file_one", "file_two");
- registerAction(actionTwo);
-
- buttonOne.pressed = buttonTwo.pressed = false;
- buildArtifact(outTwo);
- assertTrue(buttonOne.pressed); // built
- assertTrue(buttonTwo.pressed); // built
-
- buttonOne.pressed = buttonTwo.pressed = false;
- buildArtifact(outTwo);
- assertFalse(buttonOne.pressed); // not built
- assertFalse(buttonTwo.pressed); // not built
- }
-
- /**
- * Test rebuilding TreeArtifacts for inputs, outputs, and dependents.
- * Also a test for caching.
- */
- @Test
- public void testTransitiveReexecutionForTreeArtifacts() throws Exception {
- WriteInputToFilesAction actionOne = new WriteInputToFilesAction(
- buttonOne,
- in,
- outOneFileOne, outOneFileTwo);
- registerAction(actionOne);
-
- CopyTreeAction actionTwo = new CopyTreeAction(
- buttonTwo,
- ImmutableList.of(outOneFileOne, outOneFileTwo),
- ImmutableList.of(outTwoFileOne, outTwoFileTwo));
- registerAction(actionTwo);
-
- buttonOne.pressed = buttonTwo.pressed = false;
- buildArtifact(outTwo);
- assertTrue(buttonOne.pressed); // built
- assertTrue(buttonTwo.pressed); // built
-
- buttonOne.pressed = buttonTwo.pressed = false;
- writeFile(in, "modified_input");
- buildArtifact(outTwo);
- assertTrue(buttonOne.pressed); // built
- assertTrue(buttonTwo.pressed); // not built
-
- buttonOne.pressed = buttonTwo.pressed = false;
- writeFile(outOneFileOne, "modified_output");
- buildArtifact(outTwo);
- assertTrue(buttonOne.pressed); // built
- assertFalse(buttonTwo.pressed); // should have been cached
-
- buttonOne.pressed = buttonTwo.pressed = false;
- writeFile(outTwoFileOne, "more_modified_output");
- buildArtifact(outTwo);
- assertFalse(buttonOne.pressed); // not built
- assertTrue(buttonTwo.pressed); // built
- }
-
- /** Tests that changing a TreeArtifact directory should cause reexeuction. */
- @Test
- public void testDirectoryContentsCachingForTreeArtifacts() throws Exception {
- WriteInputToFilesAction actionOne = new WriteInputToFilesAction(
- buttonOne,
- in,
- outOneFileOne, outOneFileTwo);
- registerAction(actionOne);
-
- CopyTreeAction actionTwo = new CopyTreeAction(
- buttonTwo,
- ImmutableList.of(outOneFileOne, outOneFileTwo),
- ImmutableList.of(outTwoFileOne, outTwoFileTwo));
- registerAction(actionTwo);
-
- buttonOne.pressed = buttonTwo.pressed = false;
- buildArtifact(outTwo);
- // just a smoke test--if these aren't built we have bigger problems!
- assertTrue(buttonOne.pressed);
- assertTrue(buttonTwo.pressed);
-
- // Adding a file to a directory should cause reexecution.
- buttonOne.pressed = buttonTwo.pressed = false;
- Path spuriousOutputOne = outOne.getPath().getRelative("spuriousOutput");
- touchFile(spuriousOutputOne);
- buildArtifact(outTwo);
- // Should re-execute, and delete spurious output
- assertFalse(spuriousOutputOne.exists());
- assertTrue(buttonOne.pressed);
- assertFalse(buttonTwo.pressed); // should have been cached
-
- buttonOne.pressed = buttonTwo.pressed = false;
- Path spuriousOutputTwo = outTwo.getPath().getRelative("anotherSpuriousOutput");
- touchFile(spuriousOutputTwo);
- buildArtifact(outTwo);
- assertFalse(spuriousOutputTwo.exists());
- assertFalse(buttonOne.pressed);
- assertTrue(buttonTwo.pressed);
-
- // Deleting should cause reexecution.
- buttonOne.pressed = buttonTwo.pressed = false;
- deleteFile(outOneFileOne);
- buildArtifact(outTwo);
- assertTrue(outOneFileOne.getPath().exists());
- assertTrue(buttonOne.pressed);
- assertFalse(buttonTwo.pressed); // should have been cached
-
- buttonOne.pressed = buttonTwo.pressed = false;
- deleteFile(outTwoFileOne);
- buildArtifact(outTwo);
- assertTrue(outTwoFileOne.getPath().exists());
- assertFalse(buttonOne.pressed);
- assertTrue(buttonTwo.pressed);
- }
-
- /**
- * TreeArtifacts don't care about mtime, even when the file is empty.
- * However, actions taking input non-Tree artifacts still care about mtime
- * (although this behavior should go away).
- */
- @Test
- public void testMTimeForTreeArtifactsDoesNotMatter() throws Exception {
- // For this test, we only touch the input file.
- Artifact in = createSourceArtifact("touchable_input");
- touchFile(in);
-
- WriteInputToFilesAction actionOne = new WriteInputToFilesAction(
- buttonOne,
- in,
- outOneFileOne, outOneFileTwo);
- registerAction(actionOne);
-
- CopyTreeAction actionTwo = new CopyTreeAction(
- buttonTwo,
- ImmutableList.of(outOneFileOne, outOneFileTwo),
- ImmutableList.of(outTwoFileOne, outTwoFileTwo));
- registerAction(actionTwo);
-
- buttonOne.pressed = buttonTwo.pressed = false;
- buildArtifact(outTwo);
- assertTrue(buttonOne.pressed); // built
- assertTrue(buttonTwo.pressed); // built
-
- buttonOne.pressed = buttonTwo.pressed = false;
- touchFile(in);
- buildArtifact(outTwo);
- // Per existing behavior, mtime matters for empty file Artifacts.
- assertTrue(buttonOne.pressed);
- // But this should be cached.
- assertFalse(buttonTwo.pressed);
-
- // None of the below following should result in anything being built.
- buttonOne.pressed = buttonTwo.pressed = false;
- touchFile(outOneFileOne);
- buildArtifact(outTwo);
- // Nothing should be built.
- assertFalse(buttonOne.pressed);
- assertFalse(buttonTwo.pressed);
-
- buttonOne.pressed = buttonTwo.pressed = false;
- touchFile(outOneFileTwo);
- buildArtifact(outTwo);
- // Nothing should be built.
- assertFalse(buttonOne.pressed);
- assertFalse(buttonTwo.pressed);
- }
-
- /** Tests that the declared order of TreeArtifact contents does not matter. */
- @Test
- public void testOrderIndependenceOfTreeArtifactContents() throws Exception {
- WriteInputToFilesAction actionOne = new WriteInputToFilesAction(
- in,
- // The design of WritingTestAction is s.t.
- // these files will be registered in the given order.
- outOneFileTwo, outOneFileOne);
- registerAction(actionOne);
-
- CopyTreeAction actionTwo = new CopyTreeAction(
- ImmutableList.of(outOneFileOne, outOneFileTwo),
- ImmutableList.of(outTwoFileOne, outTwoFileTwo));
- registerAction(actionTwo);
-
- buildArtifact(outTwo);
- }
-
- @Test
- public void testActionExpansion() throws Exception {
- WriteInputToFilesAction action = new WriteInputToFilesAction(in, outOneFileOne, outOneFileTwo);
-
- CopyTreeAction actionTwo = new CopyTreeAction(
- ImmutableList.of(outOneFileOne, outOneFileTwo),
- ImmutableList.of(outTwoFileOne, outTwoFileTwo)) {
- @Override
- public void executeTestBehavior(ActionExecutionContext actionExecutionContext)
- throws ActionExecutionException {
- super.executeTestBehavior(actionExecutionContext);
-
- Collection<ActionInput> expanded =
- ActionInputHelper.expandArtifacts(ImmutableList.of(outOne),
- actionExecutionContext.getArtifactExpander());
- // Only files registered should show up here.
- assertThat(expanded).containsExactly(outOneFileOne, outOneFileTwo);
- }
- };
-
- registerAction(action);
- registerAction(actionTwo);
-
- buildArtifact(outTwo); // should not fail
- }
-
- @Test
- public void testInvalidOutputRegistrations() throws Exception {
- TreeArtifactTestAction failureOne = new TreeArtifactTestAction(
- Runnables.doNothing(), outOneFileOne, outOneFileTwo) {
- @Override
- public void executeTestBehavior(ActionExecutionContext actionExecutionContext)
- throws ActionExecutionException {
- try {
- writeFile(outOneFileOne, "one");
- writeFile(outOneFileTwo, "two");
- // In this test case, we only register one output. This will fail.
- registerOutput(actionExecutionContext, "one");
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
- };
-
- registerAction(failureOne);
- try {
- buildArtifact(outOne);
- fail(); // Should have thrown
- } catch (Exception e) {
- assertThat(getRootCause(e).getMessage()).contains("not present on disk");
- }
-
- TreeArtifactTestAction failureTwo = new TreeArtifactTestAction(
- Runnables.doNothing(), outTwoFileOne, outTwoFileTwo) {
- @Override
- public void executeTestBehavior(ActionExecutionContext actionExecutionContext)
- throws ActionExecutionException {
- try {
- writeFile(outTwoFileOne, "one");
- writeFile(outTwoFileTwo, "two");
- // In this test case, register too many outputs. This will fail.
- registerOutput(actionExecutionContext, "one");
- registerOutput(actionExecutionContext, "two");
- registerOutput(actionExecutionContext, "three");
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
- };
-
- registerAction(failureTwo);
- try {
- buildArtifact(outTwo);
- fail(); // Should have thrown
- } catch (Exception e) {
- assertThat(getRootCause(e).getMessage()).contains("not present on disk");
- }
- }
-
- private static void checkDirectoryPermissions(Path path) throws IOException {
- assertTrue(path.isDirectory());
- assertTrue(path.isExecutable());
- assertTrue(path.isReadable());
- assertFalse(path.isWritable());
- }
-
- private static void checkFilePermissions(Path path) throws IOException {
- assertFalse(path.isDirectory());
- assertTrue(path.isExecutable());
- assertTrue(path.isReadable());
- assertFalse(path.isWritable());
- }
-
- @Test
- public void testOutputsAreReadOnlyAndExecutable() throws Exception {
- final Artifact out = createTreeArtifact("output");
-
- TreeArtifactTestAction action = new TreeArtifactTestAction(out) {
- @Override
- public void execute(ActionExecutionContext actionExecutionContext)
- throws ActionExecutionException {
- try {
- writeFile(out.getPath().getChild("one"), "one");
- writeFile(out.getPath().getChild("two"), "two");
- writeFile(out.getPath().getChild("three").getChild("four"), "three/four");
- registerOutput(actionExecutionContext, "one");
- registerOutput(actionExecutionContext, "two");
- registerOutput(actionExecutionContext, "three/four");
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
- };
-
- registerAction(action);
-
- buildArtifact(action.getSoleOutput());
-
- checkDirectoryPermissions(out.getPath());
- checkFilePermissions(out.getPath().getChild("one"));
- checkFilePermissions(out.getPath().getChild("two"));
- checkDirectoryPermissions(out.getPath().getChild("three"));
- checkFilePermissions(out.getPath().getChild("three").getChild("four"));
- }
-
- // This is more a smoke test than anything, because it turns out that:
- // 1) there is no easy way to turn fast digests on/off for these test cases, and
- // 2) injectDigest() doesn't really complain if you inject bad digests or digests
- // for nonexistent files. Instead some weird error shows up down the line.
- // In fact, there are no tests for injectDigest anywhere in the codebase.
- // So all we're really testing here is that injectDigest() doesn't throw a weird exception.
- // TODO(bazel-team): write real tests for injectDigest, here and elsewhere.
- @Test
- public void testDigestInjection() throws Exception {
- TreeArtifactTestAction action = new TreeArtifactTestAction(outOne) {
- @Override
- public void execute(ActionExecutionContext actionExecutionContext)
- throws ActionExecutionException {
- try {
- writeFile(outOneFileOne, "one");
- writeFile(outOneFileTwo, "two");
-
- MetadataHandler md = actionExecutionContext.getMetadataHandler();
- FileStatus stat = outOneFileOne.getPath().stat(Symlinks.NOFOLLOW);
- md.injectDigest(outOneFileOne,
- new InjectedStat(stat.getLastModifiedTime(), stat.getSize(), stat.getNodeId()),
- Hashing.md5().hashString("one", Charset.forName("UTF-8")).asBytes());
-
- stat = outOneFileTwo.getPath().stat(Symlinks.NOFOLLOW);
- md.injectDigest(outOneFileTwo,
- new InjectedStat(stat.getLastModifiedTime(), stat.getSize(), stat.getNodeId()),
- Hashing.md5().hashString("two", Charset.forName("UTF-8")).asBytes());
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
- };
-
- registerAction(action);
- buildArtifact(action.getSoleOutput());
- }
-
- /**
- * A generic test action that takes at most one input TreeArtifact,
- * exactly one output TreeArtifact, and some path fragment inputs/outputs.
- */
- private abstract static class TreeArtifactTestAction extends TestAction {
- final Iterable<ArtifactFile> inputFiles;
- final Iterable<ArtifactFile> outputFiles;
-
- TreeArtifactTestAction(final Artifact output, final String... subOutputs) {
- this(Runnables.doNothing(),
- null,
- ImmutableList.<ArtifactFile>of(),
- output,
- Collections2.transform(
- Arrays.asList(subOutputs),
- new Function<String, ArtifactFile>() {
- @Nullable
- @Override
- public ArtifactFile apply(String s) {
- return ActionInputHelper.artifactFile(output, s);
- }
- }));
- }
-
- TreeArtifactTestAction(Runnable effect, ArtifactFile... outputFiles) {
- this(effect, Arrays.asList(outputFiles));
- }
-
- TreeArtifactTestAction(Runnable effect, Collection<ArtifactFile> outputFiles) {
- this(effect, null, ImmutableList.<ArtifactFile>of(),
- outputFiles.iterator().next().getParent(), outputFiles);
- }
-
- TreeArtifactTestAction(Runnable effect, Artifact inputFile,
- Collection<ArtifactFile> outputFiles) {
- this(effect, inputFile, ImmutableList.<ArtifactFile>of(),
- outputFiles.iterator().next().getParent(), outputFiles);
- }
-
- TreeArtifactTestAction(Runnable effect, Collection<ArtifactFile> inputFiles,
- Collection<ArtifactFile> outputFiles) {
- this(effect, inputFiles.iterator().next().getParent(), inputFiles,
- outputFiles.iterator().next().getParent(), outputFiles);
- }
-
- TreeArtifactTestAction(
- Runnable effect,
- @Nullable Artifact input,
- Collection<ArtifactFile> inputFiles,
- Artifact output,
- Collection<ArtifactFile> outputFiles) {
- super(effect,
- input == null ? ImmutableList.<Artifact>of() : ImmutableList.of(input),
- ImmutableList.of(output));
- Preconditions.checkArgument(
- inputFiles.isEmpty() || (input != null && input.isTreeArtifact()));
- Preconditions.checkArgument(output == null || output.isTreeArtifact());
- this.inputFiles = ImmutableList.copyOf(inputFiles);
- this.outputFiles = ImmutableList.copyOf(outputFiles);
- for (ArtifactFile inputFile : inputFiles) {
- Preconditions.checkState(inputFile.getParent().equals(input));
- }
- for (ArtifactFile outputFile : outputFiles) {
- Preconditions.checkState(outputFile.getParent().equals(output));
- }
- }
-
- @Override
- public void execute(ActionExecutionContext actionExecutionContext)
- throws ActionExecutionException {
- if (getInputs().iterator().hasNext()) {
- // Sanity check--verify all inputs exist.
- Artifact input = getSoleInput();
- if (!input.getPath().exists()) {
- throw new IllegalStateException("action's input Artifact does not exist: "
- + input.getPath());
- }
- for (ArtifactFile inputFile : inputFiles) {
- if (!inputFile.getPath().exists()) {
- throw new IllegalStateException("action's input does not exist: " + inputFile);
- }
- }
- }
-
- Artifact output = getSoleOutput();
- assertTrue(output.getPath().exists());
- try {
- effect.call();
- executeTestBehavior(actionExecutionContext);
- for (ArtifactFile outputFile : outputFiles) {
- actionExecutionContext.getMetadataHandler().addExpandedTreeOutput(outputFile);
- }
- } catch (RuntimeException e) {
- throw new RuntimeException(e);
- } catch (Exception e) {
- throw new ActionExecutionException("TestAction failed due to exception",
- e, this, false);
- }
- }
-
- void executeTestBehavior(ActionExecutionContext c) throws ActionExecutionException {
- // Default: do nothing
- }
-
- /** Checks there's exactly one input, and returns it. */
- // This prevents us from making testing mistakes, like
- // assuming there's only one input when this isn't actually true.
- Artifact getSoleInput() {
- Iterator<Artifact> it = getInputs().iterator();
- Artifact r = it.next();
- Preconditions.checkNotNull(r);
- Preconditions.checkState(!it.hasNext());
- return r;
- }
-
- /** Checks there's exactly one output, and returns it. */
- Artifact getSoleOutput() {
- Iterator<Artifact> it = getOutputs().iterator();
- Artifact r = it.next();
- Preconditions.checkNotNull(r);
- Preconditions.checkState(!it.hasNext());
- Preconditions.checkState(r.equals(getPrimaryOutput()));
- return r;
- }
-
- void registerOutput(ActionExecutionContext context, String outputName) throws IOException {
- context.getMetadataHandler().addExpandedTreeOutput(
- artifactFile(getSoleOutput(), new PathFragment(outputName)));
- }
-
- static List<ArtifactFile> asArtifactFiles(final Artifact parent, String... files) {
- return Lists.transform(
- Arrays.asList(files),
- new Function<String, ArtifactFile>() {
- @Nullable
- @Override
- public ArtifactFile apply(String s) {
- return ActionInputHelper.artifactFile(parent, s);
- }
- });
- }
- }
-
- /** An action that touches some output ArtifactFiles. Takes no inputs. */
- private static class TouchingTestAction extends TreeArtifactTestAction {
- TouchingTestAction(ArtifactFile... outputPaths) {
- super(Runnables.doNothing(), outputPaths);
- }
-
- TouchingTestAction(Runnable effect, Artifact output, String... outputPaths) {
- super(effect, asArtifactFiles(output, outputPaths));
- }
-
- @Override
- public void executeTestBehavior(ActionExecutionContext actionExecutionContext)
- throws ActionExecutionException {
- try {
- for (ArtifactFile file : outputFiles) {
- touchFile(file);
- }
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
- }
-
- /** Takes an input file and populates several copies inside a TreeArtifact. */
- private static class WriteInputToFilesAction extends TreeArtifactTestAction {
- WriteInputToFilesAction(Artifact input, ArtifactFile... outputs) {
- this(Runnables.doNothing(), input, outputs);
- }
-
- WriteInputToFilesAction(
- Runnable effect,
- Artifact input,
- ArtifactFile... outputs) {
- super(effect, input, Arrays.asList(outputs));
- Preconditions.checkArgument(!input.isTreeArtifact());
- }
-
- @Override
- public void executeTestBehavior(ActionExecutionContext actionExecutionContext)
- throws ActionExecutionException {
- try {
- for (ArtifactFile file : outputFiles) {
- FileSystemUtils.createDirectoryAndParents(file.getPath().getParentDirectory());
- FileSystemUtils.copyFile(getSoleInput().getPath(), file.getPath());
- }
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
- }
-
- /** Copies the given ArtifactFile inputs to the given outputs, in respective order. */
- private static class CopyTreeAction extends TreeArtifactTestAction {
-
- CopyTreeAction(Runnable effect, Artifact input, Artifact output, String... sourcesAndDests) {
- super(effect, input, asArtifactFiles(input, sourcesAndDests), output,
- asArtifactFiles(output, sourcesAndDests));
- }
-
- CopyTreeAction(
- Collection<ArtifactFile> inputPaths,
- Collection<ArtifactFile> outputPaths) {
- super(Runnables.doNothing(), inputPaths, outputPaths);
- }
-
- CopyTreeAction(
- Runnable effect,
- Collection<ArtifactFile> inputPaths,
- Collection<ArtifactFile> outputPaths) {
- super(effect, inputPaths, outputPaths);
- }
-
- @Override
- public void executeTestBehavior(ActionExecutionContext actionExecutionContext)
- throws ActionExecutionException {
- Iterator<ArtifactFile> inputIterator = inputFiles.iterator();
- Iterator<ArtifactFile> outputIterator = outputFiles.iterator();
-
- try {
- while (inputIterator.hasNext() || outputIterator.hasNext()) {
- ArtifactFile input = inputIterator.next();
- ArtifactFile output = outputIterator.next();
- FileSystemUtils.createDirectoryAndParents(output.getPath().getParentDirectory());
- FileSystemUtils.copyFile(input.getPath(), output.getPath());
- }
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
-
- // both iterators must be of the same size
- assertFalse(inputIterator.hasNext());
- assertFalse(inputIterator.hasNext());
- }
- }
-
- private Artifact createTreeArtifact(String name) {
- FileSystem fs = scratch.getFileSystem();
- Path execRoot = fs.getPath(TestUtils.tmpDir());
- PathFragment execPath = new PathFragment("out").getRelative(name);
- Path path = execRoot.getRelative(execPath);
- return new SpecialArtifact(
- path, Root.asDerivedRoot(execRoot, execRoot.getRelative("out")), execPath, ALL_OWNER,
- SpecialArtifactType.TREE);
- }
-
- private void buildArtifact(Artifact artifact)
- throws InterruptedException, BuildFailedException, TestExecException, AbruptExitException {
- buildArtifacts(cachingBuilder(), artifact);
- }
-
- private static void writeFile(Path path, String contents) throws IOException {
- FileSystemUtils.createDirectoryAndParents(path.getParentDirectory());
- // sometimes we write read-only files
- if (path.exists()) {
- path.setWritable(true);
- }
- FileSystemUtils.writeContentAsLatin1(path, contents);
- }
-
- private static void writeFile(ArtifactFile file, String contents) throws IOException {
- writeFile(file.getPath(), contents);
- }
-
- private static void touchFile(Path path) throws IOException {
- FileSystemUtils.createDirectoryAndParents(path.getParentDirectory());
- path.getParentDirectory().setWritable(true);
- FileSystemUtils.touchFile(path);
- }
-
- private static void touchFile(ArtifactFile file) throws IOException {
- touchFile(file.getPath());
- }
-
- private static void deleteFile(ArtifactFile file) throws IOException {
- Path path = file.getPath();
- // sometimes we write read-only files
- if (path.exists()) {
- path.setWritable(true);
- // work around the sticky bit (this might depend on the behavior of the OS?)
- path.getParentDirectory().setWritable(true);
- path.delete();
- }
- }
-}