blob: c0bec56609a70e5f60a7ecd1785d4a2080806107 [file] [log] [blame]
// 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.actions;
import static com.google.common.truth.Truth.assertThat;
import static com.google.devtools.build.lib.actions.util.ActionsTestUtil.NULL_ACTION_OWNER;
import static com.google.devtools.build.lib.actions.util.ActionsTestUtil.NULL_ARTIFACT_OWNER;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.fail;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
import com.google.devtools.build.lib.actions.util.ActionsTestUtil;
import com.google.devtools.build.lib.cmdline.PackageIdentifier;
import com.google.devtools.build.lib.cmdline.RepositoryName;
import com.google.devtools.build.lib.testutil.Scratch;
import com.google.devtools.build.lib.vfs.Path;
import com.google.devtools.build.lib.vfs.PathFragment;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import javax.annotation.Nullable;
/**
* Tests {@link ArtifactFactory}. Also see {@link ArtifactTest} for a test
* of individual artifacts.
*/
@RunWith(JUnit4.class)
public class ArtifactFactoryTest {
private static final RepositoryName MAIN = RepositoryName.MAIN;
private Scratch scratch = new Scratch();
private Path execRoot;
private Root clientRoot;
private Root clientRoRoot;
private Root alienRoot;
private Root outRoot;
private PathFragment fooPath;
private PackageIdentifier fooPackage;
private PathFragment fooRelative;
private PathFragment barPath;
private PackageIdentifier barPackage;
private PathFragment barRelative;
private PathFragment alienPath;
private PackageIdentifier alienPackage;
private PathFragment alienRelative;
private ArtifactFactory artifactFactory;
@Before
public final void createFiles() throws Exception {
execRoot = scratch.dir("/output/workspace");
clientRoot = Root.asSourceRoot(scratch.dir("/client/workspace"));
clientRoRoot = Root.asSourceRoot(scratch.dir("/client/RO/workspace"));
alienRoot = Root.asSourceRoot(scratch.dir("/client/workspace"));
outRoot = Root.asDerivedRoot(execRoot, execRoot.getRelative("out-root/x/bin"));
fooPath = new PathFragment("foo");
fooPackage = PackageIdentifier.createInMainRepo(fooPath);
fooRelative = fooPath.getRelative("foosource.txt");
barPath = new PathFragment("foo/bar");
barPackage = PackageIdentifier.createInMainRepo(barPath);
barRelative = barPath.getRelative("barsource.txt");
alienPath = new PathFragment("external/alien");
alienPackage = PackageIdentifier.create("@alien", alienPath);
alienRelative = alienPath.getRelative("alien.txt");
artifactFactory = new ArtifactFactory(execRoot, "bazel-out");
setupRoots();
}
private void setupRoots() {
Map<PackageIdentifier, Root> packageRootMap = new HashMap<>();
packageRootMap.put(fooPackage, clientRoot);
packageRootMap.put(barPackage, clientRoRoot);
packageRootMap.put(alienPackage, alienRoot);
artifactFactory.setPackageRoots(packageRootMap);
}
@Test
public void testGetSourceArtifactYieldsSameArtifact() throws Exception {
assertSame(artifactFactory.getSourceArtifact(fooRelative, clientRoot),
artifactFactory.getSourceArtifact(fooRelative, clientRoot));
}
@Test
public void testGetSourceArtifactUnnormalized() throws Exception {
assertSame(artifactFactory.getSourceArtifact(fooRelative, clientRoot),
artifactFactory.getSourceArtifact(new PathFragment("foo/./foosource.txt"),
clientRoot));
}
@Test
public void testResolveArtifact_noDerived_simpleSource() throws Exception {
assertSame(artifactFactory.getSourceArtifact(fooRelative, clientRoot),
artifactFactory.resolveSourceArtifact(fooRelative, MAIN));
assertSame(artifactFactory.getSourceArtifact(barRelative, clientRoRoot),
artifactFactory.resolveSourceArtifact(barRelative, MAIN));
}
@Test
public void testResolveArtifact_inExternalRepo() throws Exception {
assertSame(
artifactFactory.getSourceArtifact(alienRelative, alienRoot),
artifactFactory.resolveSourceArtifact(alienRelative, MAIN));
}
@Test
public void testResolveArtifact_noDerived_derivedRoot() throws Exception {
assertNull(artifactFactory.resolveSourceArtifact(
outRoot.getPath().getRelative(fooRelative).relativeTo(execRoot), MAIN));
assertNull(artifactFactory.resolveSourceArtifact(
outRoot.getPath().getRelative(barRelative).relativeTo(execRoot), MAIN));
}
@Test
public void testResolveArtifact_noDerived_simpleSource_other() throws Exception {
Artifact actual = artifactFactory.resolveSourceArtifact(fooRelative, MAIN);
assertSame(artifactFactory.getSourceArtifact(fooRelative, clientRoot), actual);
actual = artifactFactory.resolveSourceArtifact(barRelative, MAIN);
assertSame(artifactFactory.getSourceArtifact(barRelative, clientRoRoot), actual);
}
@Test
public void testResolveArtifactWithUpLevelFailsCleanly() throws Exception {
// We need a package in the root directory to make every exec path (even one with up-level
// references) be in a package.
Map<PackageIdentifier, Root> packageRoots = ImmutableMap.of(
PackageIdentifier.createInMainRepo(new PathFragment("")), clientRoot);
artifactFactory.setPackageRoots(packageRoots);
PathFragment outsideWorkspace = new PathFragment("../foo");
PathFragment insideWorkspace =
new PathFragment("../" + clientRoot.getPath().getBaseName() + "/foo");
assertNull(artifactFactory.resolveSourceArtifact(outsideWorkspace, MAIN));
assertNull("Up-level-containing paths that descend into the right workspace aren't allowed",
artifactFactory.resolveSourceArtifact(insideWorkspace, MAIN));
MockPackageRootResolver packageRootResolver = new MockPackageRootResolver();
packageRootResolver.setPackageRoots(packageRoots);
Map<PathFragment, Artifact> result = new HashMap<>();
result.put(insideWorkspace, null);
result.put(outsideWorkspace, null);
assertThat(
artifactFactory.resolveSourceArtifacts(ImmutableList.of(insideWorkspace, outsideWorkspace),
packageRootResolver).entrySet()).containsExactlyElementsIn(result.entrySet());
}
@Test
public void testClearResetsFactory() {
Artifact fooArtifact = artifactFactory.getSourceArtifact(fooRelative, clientRoot);
artifactFactory.clear();
setupRoots();
assertNotSame(fooArtifact, artifactFactory.getSourceArtifact(fooRelative, clientRoot));
}
@Test
public void testFindDerivedRoot() throws Exception {
assertThat(artifactFactory.isDerivedArtifact(fooRelative)).isFalse();
assertThat(artifactFactory.isDerivedArtifact(
new PathFragment("bazel-out/local-fastbuild/bin/foo"))).isTrue();
}
@Test
public void testSetGeneratingActionIdempotenceNewActionGraph() throws Exception {
Artifact a = artifactFactory.getDerivedArtifact(fooRelative, outRoot, NULL_ARTIFACT_OWNER);
Artifact b = artifactFactory.getDerivedArtifact(barRelative, outRoot, NULL_ARTIFACT_OWNER);
MutableActionGraph actionGraph = new MapBasedActionGraph();
Action originalAction = new ActionsTestUtil.NullAction(NULL_ACTION_OWNER, a);
actionGraph.registerAction(originalAction);
// Creating a second Action referring to the Artifact should create a conflict.
try {
Action action = new ActionsTestUtil.NullAction(NULL_ACTION_OWNER, a, b);
actionGraph.registerAction(action);
fail();
} catch (ActionConflictException e) {
assertSame(a, e.getArtifact());
assertSame(originalAction, actionGraph.getGeneratingAction(a));
}
}
@Test
public void testGetDerivedArtifact() throws Exception {
PathFragment toolPath = new PathFragment("_bin/tool");
Artifact artifact = artifactFactory.getDerivedArtifact(toolPath, execRoot);
assertEquals(toolPath, artifact.getExecPath());
assertEquals(Root.asDerivedRoot(execRoot), artifact.getRoot());
assertEquals(execRoot.getRelative(toolPath), artifact.getPath());
assertNull(artifact.getOwner());
}
@Test
public void testGetDerivedArtifactFailsForAbsolutePath() throws Exception {
try {
artifactFactory.getDerivedArtifact(new PathFragment("/_bin/b"), execRoot);
fail();
} catch (IllegalArgumentException e) {
// Expected exception
}
}
private static class MockPackageRootResolver implements PackageRootResolver {
private Map<PathFragment, Root> packageRoots = Maps.newHashMap();
public void setPackageRoots(Map<PackageIdentifier, Root> packageRoots) {
for (Entry<PackageIdentifier, Root> packageRoot : packageRoots.entrySet()) {
this.packageRoots.put(packageRoot.getKey().getPackageFragment(), packageRoot.getValue());
}
}
@Override
public Map<PathFragment, Root> findPackageRootsForFiles(Iterable<PathFragment> execPaths) {
Map<PathFragment, Root> result = new HashMap<>();
for (PathFragment execPath : execPaths) {
for (PathFragment dir = execPath.getParentDirectory(); dir != null;
dir = dir.getParentDirectory()) {
if (packageRoots.get(dir) != null) {
result.put(execPath, packageRoots.get(dir));
}
}
if (result.get(execPath) == null) {
result.put(execPath, null);
}
}
return result;
}
@Override
@Nullable
public Map<PathFragment, Root> findPackageRoots(Iterable<PathFragment> execPaths)
throws PackageRootResolutionException {
return null; // unused
}
}
}