diff options
author | Michajlo Matijkiw <michajlo@google.com> | 2016-02-10 16:26:54 +0000 |
---|---|---|
committer | Dmitry Lomov <dslomov@google.com> | 2016-02-11 11:48:34 +0000 |
commit | a0eefb52f529b73c6cb92f0a762853646ea2eae6 (patch) | |
tree | a1fa72ad1cab1cc543edbc4c292784464471585f /src/test/java/com/google/devtools | |
parent | 466873e272d040f466150469ceb172e80a6a67f4 (diff) |
Rollback of commit df03e10f6552566982399b8779fe7bc7a17d75dc.
--
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.java | 2 | ||||
-rw-r--r-- | src/test/java/com/google/devtools/build/lib/skyframe/TreeArtifactBuildTest.java | 773 |
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(); - } - } -} |