diff options
author | 2016-02-09 03:06:34 +0000 | |
---|---|---|
committer | 2016-02-09 12:20:48 +0000 | |
commit | 8d5a7bbcf4e4cc59774312bc8abd0403c0655fce (patch) | |
tree | e9013bc151bbddb055d996769269871a3e094eaf /src/test/java/com/google/devtools/build/lib/skyframe | |
parent | 434e68ebae77b4fd89c05ac676f20406e1c5b368 (diff) |
Support for handling TreeArtifact metadata and returning TreeArtifacts from ArtifactFunction.
--
MOS_MIGRATED_REVID=114174899
Diffstat (limited to 'src/test/java/com/google/devtools/build/lib/skyframe')
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; + } + } +} |