blob: ee03f739f7cb0580bd6dde76be23c61b2040c8b0 [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 org.junit.Assert.fail;
import com.google.common.collect.Maps;
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.EmptyRunfilesSupplier;
import com.google.devtools.build.lib.actions.Root;
import com.google.devtools.build.lib.actions.RunfilesSupplier;
import com.google.devtools.build.lib.analysis.Runfiles;
import com.google.devtools.build.lib.analysis.RunfilesSupplierImpl;
import com.google.devtools.build.lib.exec.util.FakeActionInputFileCache;
import com.google.devtools.build.lib.skyframe.FileArtifactValue;
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.inmemoryfs.InMemoryFileSystem;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/**
* Tests for {@link SpawnInputExpander}.
*/
@RunWith(JUnit4.class)
public class SpawnInputExpanderTest {
private static final byte[] FAKE_DIGEST = new byte[] {1, 2, 3, 4};
private FileSystem fs;
private SpawnInputExpander expander;
private Map<PathFragment, ActionInput> inputMappings;
@Before
public final void createSpawnInputExpander() throws Exception {
fs = new InMemoryFileSystem();
expander = new SpawnInputExpander(/*strict=*/true);
inputMappings = Maps.newHashMap();
}
private void scratchFile(String file, String... lines) throws Exception {
Path path = fs.getPath(file);
FileSystemUtils.createDirectoryAndParents(path.getParentDirectory());
FileSystemUtils.writeLinesAs(path, StandardCharsets.UTF_8, lines);
}
@Test
public void testEmptyRunfiles() throws Exception {
RunfilesSupplier supplier = EmptyRunfilesSupplier.INSTANCE;
expander.addRunfilesToInputs(inputMappings, supplier, null);
assertThat(inputMappings).isEmpty();
}
@Test
public void testRunfilesSingleFile() throws Exception {
Artifact artifact =
new Artifact(fs.getPath("/root/dir/file"), Root.asSourceRoot(fs.getPath("/root")));
Runfiles runfiles = new Runfiles.Builder("workspace").addArtifact(artifact).build();
RunfilesSupplier supplier = new RunfilesSupplierImpl(PathFragment.create("runfiles"), runfiles);
FakeActionInputFileCache mockCache = new FakeActionInputFileCache();
mockCache.put(artifact, FileArtifactValue.createNormalFile(FAKE_DIGEST, 0));
expander.addRunfilesToInputs(inputMappings, supplier, mockCache);
assertThat(inputMappings).hasSize(1);
assertThat(inputMappings)
.containsEntry(PathFragment.create("runfiles/workspace/dir/file"), artifact);
}
@Test
public void testRunfilesDirectoryStrict() throws Exception {
Artifact artifact =
new Artifact(fs.getPath("/root/dir/file"), Root.asSourceRoot(fs.getPath("/root")));
Runfiles runfiles = new Runfiles.Builder("workspace").addArtifact(artifact).build();
RunfilesSupplier supplier = new RunfilesSupplierImpl(PathFragment.create("runfiles"), runfiles);
FakeActionInputFileCache mockCache = new FakeActionInputFileCache();
mockCache.put(artifact, FileArtifactValue.createDirectory(-1));
try {
expander.addRunfilesToInputs(inputMappings, supplier, mockCache);
fail();
} catch (IOException expected) {
assertThat(expected.getMessage().contains("Not a file: /root/dir/file")).isTrue();
}
}
@Test
public void testRunfilesDirectoryNonStrict() throws Exception {
Artifact artifact =
new Artifact(fs.getPath("/root/dir/file"), Root.asSourceRoot(fs.getPath("/root")));
Runfiles runfiles = new Runfiles.Builder("workspace").addArtifact(artifact).build();
RunfilesSupplier supplier = new RunfilesSupplierImpl(PathFragment.create("runfiles"), runfiles);
FakeActionInputFileCache mockCache = new FakeActionInputFileCache();
mockCache.put(artifact, FileArtifactValue.createDirectory(-1));
expander = new SpawnInputExpander(/*strict=*/false);
expander.addRunfilesToInputs(inputMappings, supplier, mockCache);
assertThat(inputMappings).hasSize(1);
assertThat(inputMappings)
.containsEntry(PathFragment.create("runfiles/workspace/dir/file"), artifact);
}
@Test
public void testRunfilesTwoFiles() throws Exception {
Artifact artifact1 =
new Artifact(fs.getPath("/root/dir/file"), Root.asSourceRoot(fs.getPath("/root")));
Artifact artifact2 =
new Artifact(fs.getPath("/root/dir/baz"), Root.asSourceRoot(fs.getPath("/root")));
Runfiles runfiles = new Runfiles.Builder("workspace")
.addArtifact(artifact1)
.addArtifact(artifact2)
.build();
RunfilesSupplier supplier = new RunfilesSupplierImpl(PathFragment.create("runfiles"), runfiles);
FakeActionInputFileCache mockCache = new FakeActionInputFileCache();
mockCache.put(artifact1, FileArtifactValue.createNormalFile(FAKE_DIGEST, 1));
mockCache.put(artifact2, FileArtifactValue.createNormalFile(FAKE_DIGEST, 2));
expander.addRunfilesToInputs(inputMappings, supplier, mockCache);
assertThat(inputMappings).hasSize(2);
assertThat(inputMappings)
.containsEntry(PathFragment.create("runfiles/workspace/dir/file"), artifact1);
assertThat(inputMappings)
.containsEntry(PathFragment.create("runfiles/workspace/dir/baz"), artifact2);
}
@Test
public void testRunfilesSymlink() throws Exception {
Artifact artifact =
new Artifact(fs.getPath("/root/dir/file"), Root.asSourceRoot(fs.getPath("/root")));
Runfiles runfiles = new Runfiles.Builder("workspace")
.addSymlink(PathFragment.create("symlink"), artifact).build();
RunfilesSupplier supplier = new RunfilesSupplierImpl(PathFragment.create("runfiles"), runfiles);
FakeActionInputFileCache mockCache = new FakeActionInputFileCache();
mockCache.put(artifact, FileArtifactValue.createNormalFile(FAKE_DIGEST, 1));
expander.addRunfilesToInputs(inputMappings, supplier, mockCache);
assertThat(inputMappings).hasSize(1);
assertThat(inputMappings)
.containsEntry(PathFragment.create("runfiles/workspace/symlink"), artifact);
}
@Test
public void testRunfilesRootSymlink() throws Exception {
Artifact artifact =
new Artifact(fs.getPath("/root/dir/file"), Root.asSourceRoot(fs.getPath("/root")));
Runfiles runfiles = new Runfiles.Builder("workspace")
.addRootSymlink(PathFragment.create("symlink"), artifact).build();
RunfilesSupplier supplier = new RunfilesSupplierImpl(PathFragment.create("runfiles"), runfiles);
FakeActionInputFileCache mockCache = new FakeActionInputFileCache();
mockCache.put(artifact, FileArtifactValue.createNormalFile(FAKE_DIGEST, 1));
expander.addRunfilesToInputs(inputMappings, supplier, mockCache);
assertThat(inputMappings).hasSize(2);
assertThat(inputMappings).containsEntry(PathFragment.create("runfiles/symlink"), artifact);
// If there's no other entry, Runfiles adds an empty file in the workspace to make sure the
// directory gets created.
assertThat(inputMappings)
.containsEntry(
PathFragment.create("runfiles/workspace/.runfile"), SpawnInputExpander.EMPTY_FILE);
}
@Test
public void testEmptyManifest() throws Exception {
// See AnalysisUtils for the mapping from "foo" to "_foo/MANIFEST".
scratchFile("/root/out/_foo/MANIFEST");
Root outputRoot = Root.asDerivedRoot(fs.getPath("/root"), fs.getPath("/root/out"), true);
Artifact artifact = new Artifact(fs.getPath("/root/out/foo"), outputRoot);
expander.parseFilesetManifest(inputMappings, artifact, "workspace");
assertThat(inputMappings).isEmpty();
}
@Test
public void testManifestWithSingleFile() throws Exception {
// See AnalysisUtils for the mapping from "foo" to "_foo/MANIFEST".
scratchFile(
"/root/out/_foo/MANIFEST",
"workspace/bar /dir/file",
"<some digest>");
Root outputRoot = Root.asDerivedRoot(fs.getPath("/root"), fs.getPath("/root/out"), true);
Artifact artifact = new Artifact(fs.getPath("/root/out/foo"), outputRoot);
expander.parseFilesetManifest(inputMappings, artifact, "workspace");
assertThat(inputMappings).hasSize(1);
assertThat(inputMappings)
.containsEntry(PathFragment.create("out/foo/bar"), ActionInputHelper.fromPath("/dir/file"));
}
@Test
public void testManifestWithTwoFiles() throws Exception {
// See AnalysisUtils for the mapping from "foo" to "_foo/MANIFEST".
scratchFile(
"/root/out/_foo/MANIFEST",
"workspace/bar /dir/file",
"<some digest>",
"workspace/baz /dir/file",
"<some digest>");
Root outputRoot = Root.asDerivedRoot(fs.getPath("/root"), fs.getPath("/root/out"), true);
Artifact artifact = new Artifact(fs.getPath("/root/out/foo"), outputRoot);
expander.parseFilesetManifest(inputMappings, artifact, "workspace");
assertThat(inputMappings).hasSize(2);
assertThat(inputMappings)
.containsEntry(PathFragment.create("out/foo/bar"), ActionInputHelper.fromPath("/dir/file"));
assertThat(inputMappings)
.containsEntry(PathFragment.create("out/foo/baz"), ActionInputHelper.fromPath("/dir/file"));
}
@Test
public void testManifestWithDirectory() throws Exception {
// See AnalysisUtils for the mapping from "foo" to "_foo/MANIFEST".
scratchFile(
"/root/out/_foo/MANIFEST",
"workspace/bar /some",
"<some digest>");
Root outputRoot = Root.asDerivedRoot(fs.getPath("/root"), fs.getPath("/root/out"), true);
Artifact artifact = new Artifact(fs.getPath("/root/out/foo"), outputRoot);
expander.parseFilesetManifest(inputMappings, artifact, "workspace");
assertThat(inputMappings).hasSize(1);
assertThat(inputMappings)
.containsEntry(
PathFragment.create("out/foo/bar"), ActionInputHelper.fromPath("/some"));
}
}