blob: 097b679187ef7c8152441134a52fe18d19dffc88 [file] [log] [blame]
// Copyright 2017 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.exec;
import static com.google.common.truth.Truth.assertThat;
import static com.google.devtools.build.lib.actions.FilesetManifest.RelativeSymlinkBehavior.ERROR;
import static com.google.devtools.build.lib.actions.FilesetManifest.RelativeSymlinkBehavior.IGNORE;
import static com.google.devtools.build.lib.actions.FilesetManifest.RelativeSymlinkBehavior.RESOLVE;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.junit.Assert.assertThrows;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSortedSet;
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.ArchivedTreeArtifact;
import com.google.devtools.build.lib.actions.Artifact.ArtifactExpander;
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.Artifact.TreeFileArtifact;
import com.google.devtools.build.lib.actions.ArtifactRoot;
import com.google.devtools.build.lib.actions.ArtifactRoot.RootType;
import com.google.devtools.build.lib.actions.FilesetManifest;
import com.google.devtools.build.lib.actions.FilesetOutputSymlink;
import com.google.devtools.build.lib.actions.InputMetadataProvider;
import com.google.devtools.build.lib.actions.PathMapper;
import com.google.devtools.build.lib.actions.RunfilesTree;
import com.google.devtools.build.lib.actions.Spawn;
import com.google.devtools.build.lib.actions.cache.VirtualActionInput;
import com.google.devtools.build.lib.actions.util.ActionsTestUtil;
import com.google.devtools.build.lib.analysis.Runfiles;
import com.google.devtools.build.lib.analysis.util.AnalysisTestUtil;
import com.google.devtools.build.lib.exec.SpawnInputExpander.InputSink;
import com.google.devtools.build.lib.exec.util.FakeActionInputFileCache;
import com.google.devtools.build.lib.exec.util.SpawnBuilder;
import com.google.devtools.build.lib.vfs.DigestHashFunction;
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.Root;
import com.google.devtools.build.lib.vfs.inmemoryfs.InMemoryFileSystem;
import java.io.IOException;
import java.util.Map;
import javax.annotation.Nullable;
import org.junit.After;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Tests for {@link SpawnInputExpander}. */
@RunWith(JUnit4.class)
public final class SpawnInputExpanderTest {
private static final ArtifactExpander NO_ARTIFACT_EXPANDER =
artifact -> {
throw new AssertionError(artifact);
};
private final FileSystem fs = new InMemoryFileSystem(DigestHashFunction.SHA256);
private final Path execRoot = fs.getPath("/root");
private final ArtifactRoot rootDir = ArtifactRoot.asDerivedRoot(execRoot, RootType.Output, "out");
private SpawnInputExpander expander = new SpawnInputExpander(execRoot);
private final InputSink inputSink = mock(InputSink.class);
@After
public void checkInputSinkVerified() {
verifyNoMoreInteractions(inputSink);
}
@Test
public void testRunfilesSingleFile() throws Exception {
Artifact artifact =
ActionsTestUtil.createArtifact(
ArtifactRoot.asSourceRoot(Root.fromPath(fs.getPath("/root"))),
fs.getPath("/root/dir/file"));
Runfiles runfiles = new Runfiles.Builder("workspace").addArtifact(artifact).build();
RunfilesTree runfilesTree =
AnalysisTestUtil.createRunfilesTree(PathFragment.create("runfiles"), runfiles);
expander.addSingleRunfilesTreeToInputs(
runfilesTree,
inputSink,
NO_ARTIFACT_EXPANDER,
PathMapper.NOOP,
PathFragment.EMPTY_FRAGMENT);
verify(inputSink)
.acceptMapping(
PathFragment.create("runfiles/workspace/dir/file"), artifact, /* owner= */ null);
}
@Test
public void testRunfilesWithFileset() throws Exception {
Artifact fileset = createFilesetArtifact("foo/biz/fs_out");
Runfiles runfiles = new Runfiles.Builder("workspace").addArtifact(fileset).build();
RunfilesTree runfilesTree =
AnalysisTestUtil.createRunfilesTree(PathFragment.create("runfiles"), runfiles);
ArtifactExpander filesetExpander =
new ArtifactExpander() {
@Override
public ImmutableSortedSet<TreeFileArtifact> expandTreeArtifact(Artifact treeArtifact) {
throw new IllegalStateException("Unexpected tree expansion");
}
@Override
public ImmutableList<FilesetOutputSymlink> expandFileset(Artifact artifact) {
return ImmutableList.of(
FilesetOutputSymlink.createForTesting(
PathFragment.create("zizz"),
PathFragment.create("/foo/fake_exec/xyz/zizz"),
PathFragment.create("/foo/fake_exec/")));
}
};
expander.addSingleRunfilesTreeToInputs(
runfilesTree, inputSink, filesetExpander, PathMapper.NOOP, PathFragment.EMPTY_FRAGMENT);
verify(inputSink)
.acceptMapping(
PathFragment.create("runfiles/workspace/foo/biz/fs_out/zizz"),
ActionInputHelper.fromPath("/root/xyz/zizz"),
fileset);
}
@Test
public void testRunfilesDirectoryNonStrict() throws Exception {
Artifact artifact =
ActionsTestUtil.createArtifact(
ArtifactRoot.asSourceRoot(Root.fromPath(fs.getPath("/root"))),
fs.getPath("/root/dir/file"));
Runfiles runfiles = new Runfiles.Builder("workspace").addArtifact(artifact).build();
RunfilesTree runfilesTree =
AnalysisTestUtil.createRunfilesTree(PathFragment.create("runfiles"), runfiles);
expander.addSingleRunfilesTreeToInputs(
runfilesTree,
inputSink,
NO_ARTIFACT_EXPANDER,
PathMapper.NOOP,
PathFragment.EMPTY_FRAGMENT);
verify(inputSink)
.acceptMapping(
PathFragment.create("runfiles/workspace/dir/file"), artifact, /* owner= */ null);
}
@Test
public void testRunfilesTwoFiles() throws Exception {
Artifact artifact1 =
ActionsTestUtil.createArtifact(
ArtifactRoot.asSourceRoot(Root.fromPath(fs.getPath("/root"))),
fs.getPath("/root/dir/file"));
Artifact artifact2 =
ActionsTestUtil.createArtifact(
ArtifactRoot.asSourceRoot(Root.fromPath(fs.getPath("/root"))),
fs.getPath("/root/dir/baz"));
Runfiles runfiles =
new Runfiles.Builder("workspace").addArtifact(artifact1).addArtifact(artifact2).build();
RunfilesTree runfilesTree =
AnalysisTestUtil.createRunfilesTree(PathFragment.create("runfiles"), runfiles);
expander.addSingleRunfilesTreeToInputs(
runfilesTree,
inputSink,
NO_ARTIFACT_EXPANDER,
PathMapper.NOOP,
PathFragment.EMPTY_FRAGMENT);
verify(inputSink)
.acceptMapping(
PathFragment.create("runfiles/workspace/dir/file"), artifact1, /* owner= */ null);
verify(inputSink)
.acceptMapping(
PathFragment.create("runfiles/workspace/dir/baz"), artifact2, /* owner= */ null);
}
@Test
public void testRunfilesTwoFiles_pathMapped() throws Exception {
Artifact artifact1 =
ActionsTestUtil.createArtifact(
ArtifactRoot.asSourceRoot(Root.fromPath(fs.getPath("/root"))),
fs.getPath("/root/dir/file"));
Artifact artifact2 =
ActionsTestUtil.createArtifact(
ArtifactRoot.asSourceRoot(Root.fromPath(fs.getPath("/root"))),
fs.getPath("/root/dir/baz"));
Runfiles runfiles =
new Runfiles.Builder("workspace").addArtifact(artifact1).addArtifact(artifact2).build();
RunfilesTree runfilesTree =
AnalysisTestUtil.createRunfilesTree(
PathFragment.create("bazel-out/k8-opt/bin/foo.runfiles"), runfiles);
expander.addSingleRunfilesTreeToInputs(
runfilesTree,
inputSink,
NO_ARTIFACT_EXPANDER,
execPath -> PathFragment.create(execPath.getPathString().replace("k8-opt/", "")),
PathFragment.EMPTY_FRAGMENT);
verify(inputSink)
.acceptMapping(
PathFragment.create("bazel-out/bin/foo.runfiles/workspace/dir/file"),
artifact1,
/* owner= */ null);
verify(inputSink)
.acceptMapping(
PathFragment.create("bazel-out/bin/foo.runfiles/workspace/dir/baz"),
artifact2,
/* owner= */ null);
}
@Test
public void testRunfilesSymlink() throws Exception {
Artifact artifact =
ActionsTestUtil.createArtifact(
ArtifactRoot.asSourceRoot(Root.fromPath(fs.getPath("/root"))),
fs.getPath("/root/dir/file"));
Runfiles runfiles =
new Runfiles.Builder("workspace")
.addSymlink(PathFragment.create("symlink"), artifact)
.build();
RunfilesTree runfilesTree =
AnalysisTestUtil.createRunfilesTree(PathFragment.create("runfiles"), runfiles);
expander.addSingleRunfilesTreeToInputs(
runfilesTree,
inputSink,
NO_ARTIFACT_EXPANDER,
PathMapper.NOOP,
PathFragment.EMPTY_FRAGMENT);
verify(inputSink)
.acceptMapping(
PathFragment.create("runfiles/workspace/symlink"), artifact, /* owner= */ null);
}
@Test
public void testRunfilesRootSymlink() throws Exception {
Artifact artifact =
ActionsTestUtil.createArtifact(
ArtifactRoot.asSourceRoot(Root.fromPath(fs.getPath("/root"))),
fs.getPath("/root/dir/file"));
Runfiles runfiles =
new Runfiles.Builder("workspace")
.addRootSymlink(PathFragment.create("symlink"), artifact)
.build();
RunfilesTree runfilesTree =
AnalysisTestUtil.createRunfilesTree(PathFragment.create("runfiles"), runfiles);
expander.addSingleRunfilesTreeToInputs(
runfilesTree,
inputSink,
NO_ARTIFACT_EXPANDER,
PathMapper.NOOP,
PathFragment.EMPTY_FRAGMENT);
verify(inputSink)
.acceptMapping(PathFragment.create("runfiles/symlink"), artifact, /* owner= */ null);
// If there's no other entry, Runfiles adds an empty file in the workspace to make sure the
// directory gets created.
verify(inputSink)
.acceptMapping(
PathFragment.create("runfiles/workspace/.runfile"),
VirtualActionInput.EMPTY_MARKER,
/* owner= */ null);
}
@Test
public void testRunfilesWithTreeArtifacts() throws Exception {
SpecialArtifact treeArtifact = createTreeArtifact("treeArtifact");
TreeFileArtifact file1 = TreeFileArtifact.createTreeOutput(treeArtifact, "file1");
TreeFileArtifact file2 = TreeFileArtifact.createTreeOutput(treeArtifact, "file2");
FileSystemUtils.writeContentAsLatin1(file1.getPath(), "foo");
FileSystemUtils.writeContentAsLatin1(file2.getPath(), "bar");
Runfiles runfiles = new Runfiles.Builder("workspace").addArtifact(treeArtifact).build();
ArtifactExpander artifactExpander =
artifact ->
artifact.equals(treeArtifact)
? ImmutableSortedSet.of(file1, file2)
: ImmutableSortedSet.of();
RunfilesTree runfilesTree =
AnalysisTestUtil.createRunfilesTree(PathFragment.create("runfiles"), runfiles);
expander.addSingleRunfilesTreeToInputs(
runfilesTree, inputSink, artifactExpander, PathMapper.NOOP, PathFragment.EMPTY_FRAGMENT);
verify(inputSink)
.acceptMapping(
PathFragment.create("runfiles/workspace/treeArtifact/file1"), file1, treeArtifact);
verify(inputSink)
.acceptMapping(
PathFragment.create("runfiles/workspace/treeArtifact/file2"), file2, treeArtifact);
}
@Test
public void testRunfilesWithTreeArtifacts_pathMapped() throws Exception {
SpecialArtifact treeArtifact = createTreeArtifact("treeArtifact");
TreeFileArtifact file1 = TreeFileArtifact.createTreeOutput(treeArtifact, "file1");
TreeFileArtifact file2 = TreeFileArtifact.createTreeOutput(treeArtifact, "file2");
FileSystemUtils.writeContentAsLatin1(file1.getPath(), "foo");
FileSystemUtils.writeContentAsLatin1(file2.getPath(), "bar");
Runfiles runfiles = new Runfiles.Builder("workspace").addArtifact(treeArtifact).build();
ArtifactExpander artifactExpander =
artifact ->
artifact.equals(treeArtifact)
? ImmutableSortedSet.of(file1, file2)
: ImmutableSortedSet.of();
RunfilesTree runfilesTree =
AnalysisTestUtil.createRunfilesTree(
PathFragment.create("bazel-out/k8-opt/bin/foo.runfiles"), runfiles);
PathMapper pathMapper =
execPath -> {
// Replace the config segment "k8-opt" in "bazel-bin/k8-opt/bin" with a hash of the full
// path to verify that the new paths are constructed by appending the child paths to the
// mapped parent path, not by mapping the child paths directly.
PathFragment runfilesPath = execPath.subFragment(3);
String runfilesPathHash =
DigestHashFunction.SHA256
.getHashFunction()
.hashString(runfilesPath.getPathString(), UTF_8)
.toString();
return execPath
.subFragment(0, 1)
.getRelative(runfilesPathHash.substring(0, 8))
.getRelative(execPath.subFragment(2));
};
expander.addSingleRunfilesTreeToInputs(
runfilesTree, inputSink, artifactExpander, pathMapper, PathFragment.EMPTY_FRAGMENT);
verify(inputSink)
.acceptMapping(
PathFragment.create("bazel-out/2c26b46b/bin/foo.runfiles/workspace/treeArtifact/file1"),
file1,
treeArtifact);
verify(inputSink)
.acceptMapping(
PathFragment.create("bazel-out/2c26b46b/bin/foo.runfiles/workspace/treeArtifact/file2"),
file2,
treeArtifact);
}
@Test
public void testRunfilesWithArchivedTreeArtifacts() throws Exception {
SpecialArtifact treeArtifact = createTreeArtifact("treeArtifact");
ArchivedTreeArtifact archivedTreeArtifact = ArchivedTreeArtifact.createForTree(treeArtifact);
Runfiles runfiles = new Runfiles.Builder("workspace").addArtifact(treeArtifact).build();
ArtifactExpander artifactExpander =
new ArtifactExpander() {
@Override
public ImmutableSortedSet<TreeFileArtifact> expandTreeArtifact(Artifact treeArtifact) {
throw new IllegalStateException("Should not do expansion for archived tree");
}
@Nullable
@Override
public ArchivedTreeArtifact getArchivedTreeArtifact(Artifact treeArtifact) {
return archivedTreeArtifact;
}
};
RunfilesTree runfilesTree =
AnalysisTestUtil.createRunfilesTree(PathFragment.create("runfiles"), runfiles);
expander = new SpawnInputExpander(execRoot, IGNORE, /* expandArchivedTreeArtifacts= */ false);
expander.addSingleRunfilesTreeToInputs(
runfilesTree, inputSink, artifactExpander, PathMapper.NOOP, PathFragment.EMPTY_FRAGMENT);
verify(inputSink)
.acceptMapping(
PathFragment.create("runfiles/workspace/treeArtifact"),
archivedTreeArtifact,
treeArtifact);
}
@Test
public void testRunfilesWithTreeArtifactsInSymlinks() throws Exception {
SpecialArtifact treeArtifact = createTreeArtifact("treeArtifact");
TreeFileArtifact file1 = TreeFileArtifact.createTreeOutput(treeArtifact, "file1");
TreeFileArtifact file2 = TreeFileArtifact.createTreeOutput(treeArtifact, "file2");
FileSystemUtils.writeContentAsLatin1(file1.getPath(), "foo");
FileSystemUtils.writeContentAsLatin1(file2.getPath(), "bar");
Runfiles runfiles =
new Runfiles.Builder("workspace")
.addSymlink(PathFragment.create("symlink"), treeArtifact)
.build();
ArtifactExpander artifactExpander =
artifact ->
artifact.equals(treeArtifact)
? ImmutableSortedSet.of(file1, file2)
: ImmutableSortedSet.of();
RunfilesTree runfilesTree =
AnalysisTestUtil.createRunfilesTree(PathFragment.create("runfiles"), runfiles);
expander.addSingleRunfilesTreeToInputs(
runfilesTree, inputSink, artifactExpander, PathMapper.NOOP, PathFragment.EMPTY_FRAGMENT);
verify(inputSink)
.acceptMapping(
PathFragment.create("runfiles/workspace/symlink/file1"), file1, treeArtifact);
verify(inputSink)
.acceptMapping(
PathFragment.create("runfiles/workspace/symlink/file2"), file2, treeArtifact);
}
@Test
public void testTreeArtifactsInInputs() throws Exception {
SpecialArtifact treeArtifact = createTreeArtifact("treeArtifact");
TreeFileArtifact file1 = TreeFileArtifact.createTreeOutput(treeArtifact, "file1");
TreeFileArtifact file2 = TreeFileArtifact.createTreeOutput(treeArtifact, "file2");
InputMetadataProvider inputMetadataProvider = new FakeActionInputFileCache();
FileSystemUtils.writeContentAsLatin1(file1.getPath(), "foo");
FileSystemUtils.writeContentAsLatin1(file2.getPath(), "bar");
ArtifactExpander artifactExpander =
artifact ->
artifact.equals(treeArtifact)
? ImmutableSortedSet.of(file1, file2)
: ImmutableSortedSet.of();
Spawn spawn = new SpawnBuilder("/bin/echo", "Hello World").withInput(treeArtifact).build();
Map<PathFragment, ActionInput> inputMappings =
expander.getInputMapping(
spawn, artifactExpander, inputMetadataProvider, PathFragment.EMPTY_FRAGMENT);
assertThat(inputMappings).hasSize(2);
assertThat(inputMappings).containsEntry(PathFragment.create("out/treeArtifact/file1"), file1);
assertThat(inputMappings).containsEntry(PathFragment.create("out/treeArtifact/file2"), file2);
}
private SpecialArtifact createTreeArtifact(String relPath) throws IOException {
SpecialArtifact treeArtifact = createSpecialArtifact(relPath, SpecialArtifactType.TREE);
treeArtifact.setGeneratingActionKey(ActionsTestUtil.NULL_ACTION_LOOKUP_DATA);
return treeArtifact;
}
private SpecialArtifact createFilesetArtifact(String relPath) throws IOException {
return createSpecialArtifact(relPath, SpecialArtifactType.FILESET);
}
private SpecialArtifact createSpecialArtifact(String relPath, SpecialArtifactType type)
throws IOException {
String outputSegment = "out";
Path outputDir = execRoot.getRelative(outputSegment);
Path outputPath = outputDir.getRelative(relPath);
outputPath.createDirectoryAndParents();
ArtifactRoot derivedRoot = ArtifactRoot.asDerivedRoot(execRoot, RootType.Output, outputSegment);
return SpecialArtifact.create(
derivedRoot,
derivedRoot.getExecPath().getRelative(derivedRoot.getRoot().relativize(outputPath)),
ActionsTestUtil.NULL_ARTIFACT_OWNER,
type);
}
@Test
public void testEmptyManifest() throws Exception {
Map<Artifact, ImmutableList<FilesetOutputSymlink>> filesetMappings =
ImmutableMap.of(createFileset("out"), ImmutableList.of());
expander.addFilesetManifests(filesetMappings, inputSink, PathFragment.EMPTY_FRAGMENT);
verifyNoInteractions(inputSink);
}
@Test
public void testManifestWithSingleFile() throws Exception {
Artifact fileset = createFileset("out");
Map<Artifact, ImmutableList<FilesetOutputSymlink>> filesetMappings =
ImmutableMap.of(fileset, ImmutableList.of(filesetSymlink("foo/bar", "/dir/file")));
expander.addFilesetManifests(filesetMappings, inputSink, PathFragment.EMPTY_FRAGMENT);
verify(inputSink)
.acceptMapping(
PathFragment.create("out/foo/bar"), ActionInputHelper.fromPath("/dir/file"), fileset);
}
@Test
public void testManifestWithTwoFiles() throws Exception {
Artifact fileset = createFileset("out");
Map<Artifact, ImmutableList<FilesetOutputSymlink>> filesetMappings =
ImmutableMap.of(
fileset,
ImmutableList.of(
filesetSymlink("foo/bar", "/dir/file"), filesetSymlink("foo/baz", "/dir/file")));
expander.addFilesetManifests(filesetMappings, inputSink, PathFragment.EMPTY_FRAGMENT);
verify(inputSink)
.acceptMapping(
PathFragment.create("out/foo/bar"), ActionInputHelper.fromPath("/dir/file"), fileset);
verify(inputSink)
.acceptMapping(
PathFragment.create("out/foo/baz"), ActionInputHelper.fromPath("/dir/file"), fileset);
}
@Test
public void testManifestWithDirectory() throws Exception {
Artifact fileset = createFileset("out");
Map<Artifact, ImmutableList<FilesetOutputSymlink>> filesetMappings =
ImmutableMap.of(fileset, ImmutableList.of(filesetSymlink("foo/bar", "/some")));
expander.addFilesetManifests(filesetMappings, inputSink, PathFragment.EMPTY_FRAGMENT);
verify(inputSink)
.acceptMapping(
PathFragment.create("out/foo/bar"), ActionInputHelper.fromPath("/some"), fileset);
}
private static FilesetOutputSymlink filesetSymlink(String from, String to) {
return FilesetOutputSymlink.createForTesting(
PathFragment.create(from), PathFragment.create(to), PathFragment.create("/root"));
}
private SpecialArtifact createFileset(String execPath) {
return SpecialArtifact.create(
rootDir,
PathFragment.create(execPath),
ActionsTestUtil.NULL_ARTIFACT_OWNER,
SpecialArtifactType.FILESET);
}
@Test
public void testManifestWithErrorOnRelativeSymlink() {
expander = new SpawnInputExpander(execRoot, ERROR);
Artifact fileset = createFileset("out");
ImmutableMap<Artifact, ImmutableList<FilesetOutputSymlink>> filesetMappings =
ImmutableMap.of(
fileset,
ImmutableList.of(
filesetSymlink("workspace/bar", "foo"),
filesetSymlink("workspace/foo", "/root/bar")));
FilesetManifest.ForbiddenRelativeSymlinkException e =
assertThrows(
FilesetManifest.ForbiddenRelativeSymlinkException.class,
() ->
expander.addFilesetManifests(
filesetMappings, inputSink, PathFragment.EMPTY_FRAGMENT));
assertThat(e).hasMessageThat().contains("Fileset symlink foo is not absolute");
}
@Test
public void testManifestWithIgnoredRelativeSymlink() throws Exception {
expander = new SpawnInputExpander(execRoot, IGNORE);
Artifact fileset = createFileset("out");
ImmutableMap<Artifact, ImmutableList<FilesetOutputSymlink>> filesetMappings =
ImmutableMap.of(
fileset,
ImmutableList.of(
filesetSymlink("workspace/bar", "foo"),
filesetSymlink("workspace/foo", "/root/bar")));
expander.addFilesetManifests(filesetMappings, inputSink, PathFragment.EMPTY_FRAGMENT);
verify(inputSink)
.acceptMapping(
PathFragment.create("out/workspace/foo"),
ActionInputHelper.fromPath("/root/bar"),
fileset);
}
@Test
public void testManifestWithResolvedRelativeSymlink() throws Exception {
expander = new SpawnInputExpander(execRoot, RESOLVE);
Artifact fileset = createFileset("out");
ImmutableMap<Artifact, ImmutableList<FilesetOutputSymlink>> filesetMappings =
ImmutableMap.of(
fileset,
ImmutableList.of(
filesetSymlink("workspace/bar", "foo"),
filesetSymlink("workspace/foo", "/root/bar")));
expander.addFilesetManifests(filesetMappings, inputSink, PathFragment.EMPTY_FRAGMENT);
verify(inputSink)
.acceptMapping(
PathFragment.create("out/workspace/bar"),
ActionInputHelper.fromPath("/root/bar"),
fileset);
verify(inputSink)
.acceptMapping(
PathFragment.create("out/workspace/foo"),
ActionInputHelper.fromPath("/root/bar"),
fileset);
}
}