aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/test
diff options
context:
space:
mode:
Diffstat (limited to 'src/test')
-rw-r--r--src/test/java/com/google/devtools/build/lib/skyframe/ArtifactFunctionTest.java118
-rw-r--r--src/test/java/com/google/devtools/build/lib/skyframe/ArtifactFunctionTestCase.java158
-rw-r--r--src/test/java/com/google/devtools/build/lib/skyframe/FilesystemValueCheckerTest.java8
-rw-r--r--src/test/java/com/google/devtools/build/lib/skyframe/TreeArtifactMetadataTest.java254
4 files changed, 431 insertions, 107 deletions
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/ArtifactFunctionTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/ArtifactFunctionTest.java
index 10d05ff96e..2d5a9b3782 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/ArtifactFunctionTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/ArtifactFunctionTest.java
@@ -33,28 +33,14 @@ import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.actions.MissingInputFileException;
import com.google.devtools.build.lib.actions.Root;
import com.google.devtools.build.lib.actions.util.TestAction.DummyAction;
-import com.google.devtools.build.lib.analysis.BlazeDirectories;
import com.google.devtools.build.lib.events.NullEventHandler;
-import com.google.devtools.build.lib.packages.PackageFactory;
-import com.google.devtools.build.lib.pkgcache.PathPackageLocator;
-import com.google.devtools.build.lib.skyframe.ActionLookupValue.ActionLookupKey;
-import com.google.devtools.build.lib.testutil.TestRuleClassProvider;
-import com.google.devtools.build.lib.testutil.TestUtils;
-import com.google.devtools.build.lib.util.BlazeClock;
import com.google.devtools.build.lib.util.Pair;
-import com.google.devtools.build.lib.util.io.TimestampGranularityMonitor;
import com.google.devtools.build.lib.vfs.FileStatus;
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.inmemoryfs.InMemoryFileSystem;
import com.google.devtools.build.skyframe.EvaluationResult;
-import com.google.devtools.build.skyframe.InMemoryMemoizingEvaluator;
-import com.google.devtools.build.skyframe.MemoizingEvaluator;
-import com.google.devtools.build.skyframe.RecordingDifferencer;
-import com.google.devtools.build.skyframe.SequentialBuildDriver;
import com.google.devtools.build.skyframe.SkyFunction;
-import com.google.devtools.build.skyframe.SkyFunctionName;
import com.google.devtools.build.skyframe.SkyKey;
import com.google.devtools.build.skyframe.SkyValue;
@@ -68,78 +54,27 @@ import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.Arrays;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
-import java.util.Set;
-import java.util.UUID;
-import java.util.concurrent.atomic.AtomicReference;
/**
* Tests for {@link ArtifactFunction}.
*/
// Doesn't actually need any particular Skyframe, but is only relevant to Skyframe full mode.
@RunWith(JUnit4.class)
-public class ArtifactFunctionTest {
- private static final SkyKey OWNER_KEY = new SkyKey(SkyFunctions.ACTION_LOOKUP, "OWNER");
- private static final ActionLookupKey ALL_OWNER = new SingletonActionLookupKey();
+public class ArtifactFunctionTest extends ArtifactFunctionTestCase {
private PathFragment allowedMissingInput = null;
- private Predicate<PathFragment> allowedMissingInputsPredicate = new Predicate<PathFragment>() {
- @Override
- public boolean apply(PathFragment input) {
- return input.equals(allowedMissingInput);
- }
- };
-
- private Set<Action> actions;
- private boolean fastDigest = false;
- private RecordingDifferencer differencer = new RecordingDifferencer();
- private SequentialBuildDriver driver;
- private MemoizingEvaluator evaluator;
- private Path root;
- private TimestampGranularityMonitor tsgm = new TimestampGranularityMonitor(BlazeClock.instance());
@Before
public final void setUp() throws Exception {
- setupRoot(new CustomInMemoryFs());
- AtomicReference<PathPackageLocator> pkgLocator = new AtomicReference<>(new PathPackageLocator(
- root.getFileSystem().getPath("/outputbase"), ImmutableList.of(root)));
- ExternalFilesHelper externalFilesHelper = new ExternalFilesHelper(pkgLocator, false);
- differencer = new RecordingDifferencer();
- evaluator =
- new InMemoryMemoizingEvaluator(
- ImmutableMap.<SkyFunctionName, SkyFunction>builder()
- .put(SkyFunctions.FILE_STATE, new FileStateFunction(tsgm, externalFilesHelper))
- .put(SkyFunctions.FILE, new FileFunction(pkgLocator))
- .put(SkyFunctions.ARTIFACT, new ArtifactFunction(allowedMissingInputsPredicate))
- .put(SkyFunctions.ACTION_EXECUTION, new SimpleActionExecutionFunction())
- .put(
- SkyFunctions.PACKAGE,
- new PackageFunction(null, null, null, null, null, null, null))
- .put(SkyFunctions.PACKAGE_LOOKUP, new PackageLookupFunction(null))
- .put(
- SkyFunctions.WORKSPACE_AST,
- new WorkspaceASTFunction(TestRuleClassProvider.getRuleClassProvider()))
- .put(
- SkyFunctions.WORKSPACE_FILE,
- new WorkspaceFileFunction(
- TestRuleClassProvider.getRuleClassProvider(),
- new PackageFactory(TestRuleClassProvider.getRuleClassProvider()),
- new BlazeDirectories(root, root, root)))
- .put(SkyFunctions.EXTERNAL_PACKAGE, new ExternalPackageFunction())
- .build(),
- differencer);
- driver = new SequentialBuildDriver(evaluator);
- PrecomputedValue.BUILD_ID.set(differencer, UUID.randomUUID());
- PrecomputedValue.PATH_PACKAGE_LOCATOR.set(differencer, pkgLocator.get());
- actions = new HashSet<>();
- }
-
- private void setupRoot(CustomInMemoryFs fs) throws IOException {
- root = fs.getPath(TestUtils.tmpDir());
- FileSystemUtils.createDirectoryAndParents(root);
- FileSystemUtils.createEmptyFile(root.getRelative("WORKSPACE"));
+ delegateActionExecutionFunction = new SimpleActionExecutionFunction();
+ allowedMissingInputsPredicate = new Predicate<PathFragment>() {
+ @Override
+ public boolean apply(PathFragment input) {
+ return input.equals(allowedMissingInput);
+ }
+ };
}
private void assertFileArtifactValueMatches(boolean expectDigest) throws Throwable {
@@ -452,23 +387,6 @@ public class ArtifactFunctionTest {
NullEventHandler.INSTANCE);
}
- private static void writeFile(Path path, String contents) throws IOException {
- FileSystemUtils.createDirectoryAndParents(path.getParentDirectory());
- FileSystemUtils.writeContentAsLatin1(path, contents);
- }
-
- private static class SingletonActionLookupKey extends ActionLookupKey {
- @Override
- SkyKey getSkyKey() {
- return OWNER_KEY;
- }
-
- @Override
- SkyFunctionName getType() {
- throw new UnsupportedOperationException();
- }
- }
-
/** Value Builder for actions that just stats and stores the output file (which must exist). */
private class SimpleActionExecutionFunction implements SkyFunction {
@Override
@@ -479,7 +397,7 @@ public class ArtifactFunctionTest {
FileArtifactValue value;
if (action.getActionType() == MiddlemanType.NORMAL) {
try {
- FileValue fileValue = ActionMetadataHandler.fileValueFromArtifact(output, null, tsgm);
+ FileValue fileValue = ActionMetadataHandler.fileValueFromArtifactFile(output, null, tsgm);
artifactData.put(output, fileValue);
value = FileArtifactValue.create(output, fileValue);
} catch (IOException e) {
@@ -488,7 +406,10 @@ public class ArtifactFunctionTest {
} else {
value = FileArtifactValue.DEFAULT_MIDDLEMAN;
}
- return new ActionExecutionValue(artifactData, ImmutableMap.of(output, value));
+ return new ActionExecutionValue(
+ artifactData,
+ ImmutableMap.<Artifact, TreeArtifactValue>of(),
+ ImmutableMap.of(output, value));
}
@Override
@@ -496,17 +417,4 @@ public class ArtifactFunctionTest {
return null;
}
}
-
- /** InMemoryFileSystem that can pretend to do a fast digest. */
- private class CustomInMemoryFs extends InMemoryFileSystem {
- @Override
- protected String getFastDigestFunctionType(Path path) {
- return fastDigest ? "MD5" : null;
- }
-
- @Override
- protected byte[] getFastDigest(Path path) throws IOException {
- return fastDigest ? getMD5Digest(path) : null;
- }
- }
}
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/ArtifactFunctionTestCase.java b/src/test/java/com/google/devtools/build/lib/skyframe/ArtifactFunctionTestCase.java
new file mode 100644
index 0000000000..2f75f40fdf
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/ArtifactFunctionTestCase.java
@@ -0,0 +1,158 @@
+// Copyright 2015 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 com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.devtools.build.lib.actions.Action;
+import com.google.devtools.build.lib.analysis.BlazeDirectories;
+import com.google.devtools.build.lib.packages.PackageFactory;
+import com.google.devtools.build.lib.pkgcache.PathPackageLocator;
+import com.google.devtools.build.lib.skyframe.ActionLookupValue.ActionLookupKey;
+import com.google.devtools.build.lib.testutil.TestRuleClassProvider;
+import com.google.devtools.build.lib.testutil.TestUtils;
+import com.google.devtools.build.lib.util.BlazeClock;
+import com.google.devtools.build.lib.util.io.TimestampGranularityMonitor;
+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.inmemoryfs.InMemoryFileSystem;
+import com.google.devtools.build.skyframe.InMemoryMemoizingEvaluator;
+import com.google.devtools.build.skyframe.MemoizingEvaluator;
+import com.google.devtools.build.skyframe.RecordingDifferencer;
+import com.google.devtools.build.skyframe.SequentialBuildDriver;
+import com.google.devtools.build.skyframe.SkyFunction;
+import com.google.devtools.build.skyframe.SkyFunctionException;
+import com.google.devtools.build.skyframe.SkyFunctionName;
+import com.google.devtools.build.skyframe.SkyKey;
+import com.google.devtools.build.skyframe.SkyValue;
+
+import org.junit.Before;
+
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.UUID;
+import java.util.concurrent.atomic.AtomicReference;
+
+abstract class ArtifactFunctionTestCase {
+ protected static final SkyKey OWNER_KEY = new SkyKey(SkyFunctions.ACTION_LOOKUP, "OWNER");
+ protected static final ActionLookupKey ALL_OWNER = new SingletonActionLookupKey();
+
+ protected Predicate<PathFragment> allowedMissingInputsPredicate = Predicates.alwaysFalse();
+
+ protected Set<Action> actions;
+ protected boolean fastDigest = false;
+ protected RecordingDifferencer differencer = new RecordingDifferencer();
+ protected SequentialBuildDriver driver;
+ protected MemoizingEvaluator evaluator;
+ protected Path root;
+ protected TimestampGranularityMonitor tsgm =
+ new TimestampGranularityMonitor(BlazeClock.instance());
+
+ /**
+ * The test action execution function. The Skyframe evaluator's action execution function
+ * delegates to this one.
+ */
+ protected SkyFunction delegateActionExecutionFunction;
+
+ @Before
+ public void baseSetUp() throws Exception {
+ setupRoot(new CustomInMemoryFs());
+ AtomicReference<PathPackageLocator> pkgLocator = new AtomicReference<>(new PathPackageLocator(
+ root.getFileSystem().getPath("/outputbase"), ImmutableList.of(root)));
+ ExternalFilesHelper externalFilesHelper = new ExternalFilesHelper(pkgLocator, false);
+ differencer = new RecordingDifferencer();
+ evaluator =
+ new InMemoryMemoizingEvaluator(
+ ImmutableMap.<SkyFunctionName, SkyFunction>builder()
+ .put(SkyFunctions.FILE_STATE, new FileStateFunction(tsgm, externalFilesHelper))
+ .put(SkyFunctions.FILE, new FileFunction(pkgLocator))
+ .put(SkyFunctions.ARTIFACT,
+ new ArtifactFunction(allowedMissingInputsPredicate))
+ .put(SkyFunctions.ACTION_EXECUTION, new SimpleActionExecutionFunction())
+ .put(
+ SkyFunctions.PACKAGE,
+ new PackageFunction(null, null, null, null, null, null, null))
+ .put(SkyFunctions.PACKAGE_LOOKUP, new PackageLookupFunction(null))
+ .put(
+ SkyFunctions.WORKSPACE_AST,
+ new WorkspaceASTFunction(TestRuleClassProvider.getRuleClassProvider()))
+ .put(
+ SkyFunctions.WORKSPACE_FILE,
+ new WorkspaceFileFunction(
+ TestRuleClassProvider.getRuleClassProvider(),
+ new PackageFactory(TestRuleClassProvider.getRuleClassProvider()),
+ new BlazeDirectories(root, root, root)))
+ .put(SkyFunctions.EXTERNAL_PACKAGE, new ExternalPackageFunction())
+ .build(),
+ differencer);
+ driver = new SequentialBuildDriver(evaluator);
+ PrecomputedValue.BUILD_ID.set(differencer, UUID.randomUUID());
+ PrecomputedValue.PATH_PACKAGE_LOCATOR.set(differencer, pkgLocator.get());
+ actions = new HashSet<>();
+ }
+
+ protected void setupRoot(CustomInMemoryFs fs) throws IOException {
+ root = fs.getPath(TestUtils.tmpDir());
+ FileSystemUtils.createDirectoryAndParents(root);
+ FileSystemUtils.createEmptyFile(root.getRelative("WORKSPACE"));
+ }
+
+ protected static void writeFile(Path path, String contents) throws IOException {
+ FileSystemUtils.createDirectoryAndParents(path.getParentDirectory());
+ FileSystemUtils.writeContentAsLatin1(path, contents);
+ }
+
+ /** ActionExecutionFunction that delegates to our delegate. */
+ private class SimpleActionExecutionFunction implements SkyFunction {
+ @Override
+ public SkyValue compute(SkyKey skyKey, Environment env)
+ throws SkyFunctionException, InterruptedException {
+ return delegateActionExecutionFunction.compute(skyKey, env);
+ }
+
+ @Override
+ public String extractTag(SkyKey skyKey) {
+ return delegateActionExecutionFunction.extractTag(skyKey);
+ }
+ }
+
+ private static class SingletonActionLookupKey extends ActionLookupKey {
+ @Override
+ SkyKey getSkyKey() {
+ return OWNER_KEY;
+ }
+
+ @Override
+ SkyFunctionName getType() {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ /** InMemoryFileSystem that can pretend to do a fast digest. */
+ protected class CustomInMemoryFs extends InMemoryFileSystem {
+ @Override
+ protected String getFastDigestFunctionType(Path path) {
+ return fastDigest ? "MD5" : null;
+ }
+
+ @Override
+ protected byte[] getFastDigest(Path path) throws IOException {
+ return fastDigest ? getMD5Digest(path) : null;
+ }
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/FilesystemValueCheckerTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/FilesystemValueCheckerTest.java
index 95cb020ab6..d695780c00 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/FilesystemValueCheckerTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/FilesystemValueCheckerTest.java
@@ -453,12 +453,16 @@ public class FilesystemValueCheckerTest {
Path path = output.getPath();
FileStatusWithDigest stat =
forceDigest ? statWithDigest(path, path.statIfFound(Symlinks.NOFOLLOW)) : null;
- artifactData.put(output, ActionMetadataHandler.fileValueFromArtifact(output, stat, tsgm));
+ artifactData.put(output,
+ ActionMetadataHandler.fileValueFromArtifactFile(output, stat, tsgm));
} catch (IOException e) {
throw new IllegalStateException(e);
}
}
- return new ActionExecutionValue(artifactData, ImmutableMap.<Artifact, FileArtifactValue>of());
+ return new ActionExecutionValue(
+ artifactData,
+ ImmutableMap.<Artifact, TreeArtifactValue>of(),
+ ImmutableMap.<Artifact, FileArtifactValue>of());
}
@Test
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/TreeArtifactMetadataTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/TreeArtifactMetadataTest.java
new file mode 100644
index 0000000000..a57576cc5d
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/TreeArtifactMetadataTest.java
@@ -0,0 +1,254 @@
+// 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.truth.Truth.assertThat;
+import static com.google.devtools.build.lib.actions.ActionInputHelper.asArtifactFiles;
+import static org.junit.Assert.fail;
+
+import com.google.common.base.Throwables;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import com.google.devtools.build.lib.actions.Action;
+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.MissingInputFileException;
+import com.google.devtools.build.lib.actions.Root;
+import com.google.devtools.build.lib.actions.cache.Digest;
+import com.google.devtools.build.lib.actions.cache.DigestUtils;
+import com.google.devtools.build.lib.actions.cache.Metadata;
+import com.google.devtools.build.lib.actions.util.TestAction.DummyAction;
+import com.google.devtools.build.lib.events.NullEventHandler;
+import com.google.devtools.build.lib.vfs.FileStatus;
+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.skyframe.EvaluationResult;
+import com.google.devtools.build.skyframe.SkyFunction;
+import com.google.devtools.build.skyframe.SkyFunctionException;
+import com.google.devtools.build.skyframe.SkyFunctionException.Transience;
+import com.google.devtools.build.skyframe.SkyKey;
+import com.google.devtools.build.skyframe.SkyValue;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Test the behavior of ActionMetadataHandler and ArtifactFunction
+ * with respect to TreeArtifacts.
+ */
+@RunWith(JUnit4.class)
+public class TreeArtifactMetadataTest extends ArtifactFunctionTestCase {
+
+ // A list of subpaths for the SetArtifact created by our custom ActionExecutionFunction.
+ private List<PathFragment> testTreeArtifactContents;
+
+ @Before
+ public final void setUp() throws Exception {
+ delegateActionExecutionFunction = new TreeArtifactExecutionFunction();
+ }
+
+ private TreeArtifactValue evaluateTreeArtifact(Artifact treeArtifact,
+ Iterable<PathFragment> children)
+ throws Exception {
+ testTreeArtifactContents = ImmutableList.copyOf(children);
+ for (PathFragment child : children) {
+ file(treeArtifact.getPath().getRelative(child), child.toString());
+ }
+ return (TreeArtifactValue) evaluateArtifactValue(treeArtifact, /*mandatory=*/ true);
+ }
+
+ private TreeArtifactValue doTestTreeArtifacts(Iterable<PathFragment> children) throws Exception {
+ Artifact output = createTreeArtifact("output");
+ return doTestTreeArtifacts(output, children);
+ }
+
+ private TreeArtifactValue doTestTreeArtifacts(Artifact tree,
+ Iterable<PathFragment> children)
+ throws Exception {
+ TreeArtifactValue value = evaluateTreeArtifact(tree, children);
+ assertThat(value.getChildPaths()).containsExactlyElementsIn(ImmutableSet.copyOf(children));
+ assertThat(value.getChildren(tree)).containsExactlyElementsIn(
+ asArtifactFiles(tree, children));
+
+ // Assertions about digest. As of this writing this logic is essentially the same
+ // as that in TreeArtifact, but it's good practice to unit test anyway to guard against
+ // breaking changes.
+ Map<String, Metadata> digestBuilder = new HashMap<>();
+ for (PathFragment child : children) {
+ Metadata subdigest = new Metadata(tree.getPath().getRelative(child).getMD5Digest());
+ digestBuilder.put(child.getPathString(), subdigest);
+ }
+ assertThat(Digest.fromMetadata(digestBuilder).asMetadata().digest).isEqualTo(value.getDigest());
+ return value;
+ }
+
+ @Test
+ public void testEmptyTreeArtifacts() throws Exception {
+ TreeArtifactValue value = doTestTreeArtifacts(ImmutableList.<PathFragment>of());
+ // Additional test, only for this test method: we expect the Metadata is equal to
+ // the digest [0, 0, ...]
+ assertThat(value.getMetadata().digest).isEqualTo(value.getDigest());
+ // Java zero-fills arrays.
+ assertThat(value.getDigest()).isEqualTo(new byte[16]);
+ }
+
+ @Test
+ public void testTreeArtifactsWithDigests() throws Exception {
+ fastDigest = true;
+ doTestTreeArtifacts(ImmutableList.of(new PathFragment("one")));
+ }
+
+ @Test
+ public void testTreeArtifactsWithoutDigests() throws Exception {
+ fastDigest = false;
+ doTestTreeArtifacts(ImmutableList.of(new PathFragment("one")));
+ }
+
+ @Test
+ public void testTreeArtifactMultipleDigests() throws Exception {
+ doTestTreeArtifacts(ImmutableList.of(new PathFragment("one"), new PathFragment("two")));
+ }
+
+ @Test
+ public void testIdenticalTreeArtifactsProduceTheSameDigests() throws Exception {
+ // Make sure different root dirs for set artifacts don't produce different digests.
+ Artifact one = createTreeArtifact("outOne");
+ Artifact two = createTreeArtifact("outTwo");
+ ImmutableList<PathFragment> children =
+ ImmutableList.of(new PathFragment("one"), new PathFragment("two"));
+ TreeArtifactValue valueOne = evaluateTreeArtifact(one, children);
+ TreeArtifactValue valueTwo = evaluateTreeArtifact(two, children);
+ assertThat(valueOne.getDigest()).isEqualTo(valueTwo.getDigest());
+ }
+
+ /**
+ * Tests that ArtifactFunction rethrows transitive {@link IOException}s as
+ * {@link MissingInputFileException}s.
+ */
+ @Test
+ public void testIOExceptionEndToEnd() throws Throwable {
+ final IOException exception = new IOException("boop");
+ setupRoot(
+ new CustomInMemoryFs() {
+ @Override
+ public FileStatus stat(Path path, boolean followSymlinks) throws IOException {
+ if (path.getBaseName().equals("one")) {
+ throw exception;
+ }
+ return super.stat(path, followSymlinks);
+ }
+ });
+ try {
+ Artifact artifact = createTreeArtifact("outOne");
+ TreeArtifactValue value = evaluateTreeArtifact(artifact,
+ ImmutableList.of(new PathFragment("one")));
+ fail("MissingInputFileException expected, got " + value);
+ } catch (Exception e) {
+ assertThat(Throwables.getRootCause(e).getMessage()).contains(exception.getMessage());
+ }
+ }
+
+ private void file(Path path, String contents) throws Exception {
+ FileSystemUtils.createDirectoryAndParents(path.getParentDirectory());
+ writeFile(path, contents);
+ }
+
+ private Artifact createTreeArtifact(String path) throws IOException {
+ PathFragment execPath = new PathFragment("out").getRelative(path);
+ Path fullPath = root.getRelative(execPath);
+ Artifact output =
+ new SpecialArtifact(
+ fullPath, Root.asDerivedRoot(root, root.getRelative("out")), execPath, ALL_OWNER,
+ SpecialArtifactType.TREE);
+ actions.add(new DummyAction(ImmutableList.<Artifact>of(), output));
+ FileSystemUtils.createDirectoryAndParents(fullPath);
+ return output;
+ }
+
+ private ArtifactValue evaluateArtifactValue(Artifact artifact, boolean mandatory)
+ throws Exception {
+ SkyKey key = ArtifactValue.key(artifact, mandatory);
+ EvaluationResult<ArtifactValue> result = evaluate(key);
+ if (result.hasError()) {
+ throw result.getError().getException();
+ }
+ return result.get(key);
+ }
+
+ private void setGeneratingActions() {
+ if (evaluator.getExistingValueForTesting(OWNER_KEY) == null) {
+ differencer.inject(ImmutableMap.of(OWNER_KEY, new ActionLookupValue(actions)));
+ }
+ }
+
+ private <E extends SkyValue> EvaluationResult<E> evaluate(SkyKey... keys)
+ throws InterruptedException {
+ setGeneratingActions();
+ return driver.evaluate(
+ Arrays.asList(keys), /*keepGoing=*/
+ false,
+ SkyframeExecutor.DEFAULT_THREAD_COUNT,
+ NullEventHandler.INSTANCE);
+ }
+
+ private class TreeArtifactExecutionFunction implements SkyFunction {
+ @Override
+ public SkyValue compute(SkyKey skyKey, Environment env) throws SkyFunctionException {
+ Map<ArtifactFile, FileValue> fileData = new HashMap<>();
+ Map<PathFragment, FileArtifactValue> treeArtifactData = new HashMap<>();
+ Action action = (Action) skyKey.argument();
+ Artifact output = Iterables.getOnlyElement(action.getOutputs());
+ for (PathFragment subpath : testTreeArtifactContents) {
+ try {
+ ArtifactFile suboutput = ActionInputHelper.artifactFile(output, subpath);
+ FileValue fileValue = ActionMetadataHandler.fileValueFromArtifactFile(
+ suboutput, null, tsgm);
+ fileData.put(suboutput, fileValue);
+ // Ignore FileValue digests--correctness of these digests is not part of this tests.
+ byte[] digest = DigestUtils.getDigestOrFail(suboutput.getPath(), 1);
+ treeArtifactData.put(suboutput.getParentRelativePath(),
+ FileArtifactValue.createWithDigest(suboutput.getPath(), digest, fileValue.getSize()));
+ } catch (IOException e) {
+ throw new SkyFunctionException(e, Transience.TRANSIENT) {};
+ }
+ }
+
+ TreeArtifactValue treeArtifactValue = TreeArtifactValue.create(treeArtifactData);
+
+ return new ActionExecutionValue(
+ fileData,
+ ImmutableMap.of(output, treeArtifactValue),
+ ImmutableMap.<Artifact, FileArtifactValue>of());
+ }
+
+ @Override
+ public String extractTag(SkyKey skyKey) {
+ return null;
+ }
+ }
+}