blob: d05e7b6500af5a4936be8263e70e848f0f77de1c [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.pkgcache;
import static com.google.common.truth.Truth.assertThat;
import com.google.common.collect.ImmutableList;
import com.google.devtools.build.lib.cmdline.PackageIdentifier;
import com.google.devtools.build.lib.skyframe.BazelSkyframeExecutorConstants;
import com.google.devtools.build.lib.testutil.FoundationTestCase;
import com.google.devtools.build.lib.vfs.FileSystemUtils;
import com.google.devtools.build.lib.vfs.Path;
import com.google.devtools.build.lib.vfs.Root;
import com.google.devtools.build.lib.vfs.SyscallCache;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/**
* Test package-path logic.
*/
@RunWith(JUnit4.class)
public class PathPackageLocatorTest extends FoundationTestCase {
private Path buildBazelFile1A;
private Path buildFile1B;
private Path buildFile2C;
private Path buildFile2CD;
private Path buildFile2F;
private Path buildFile2FGH;
private Path buildBazelFile3A;
private Path buildFile3B;
private Path buildFile3CI;
private Path rootDir1;
private Path rootDir1WorkspaceFile;
private Path rootDir2;
private Path rootDir3ParentParent;
private Path rootDir3;
private Path rootDir4Parent;
private Path rootDir4;
private Path rootDir5;
private PathPackageLocator locator;
private PathPackageLocator locatorWithSymlinks;
protected PathPackageLocator getLocator() {
return locator;
}
@Before
public final void createFiles() throws Exception {
// Root 1:
// WORKSPACE
// /A/BUILD.bazel // This is the actual buildfile for this package.
// /A/BUILD // This is a dummy buildfile and isn't used.
// /B/BUILD
// /C/I/BUILD
// /C/D
// /C/E
// /F/G // This is a file, not a directory.
//
// Root 2:
// WORKSPACE
// /B/BUILD
// /C/BUILD
// /C/D/BUILD
// /F/BUILD
// /F/G
// /F/G/H/BUILD
// /I/BUILD // This is a directory, not a file.
//
// Root 3:
// /usr/local/google/jrluser-foo/READONLY -> root4
//
// Root 4 (not used as a package root, but root 3 points to this)
// /A -> root1/A
// /B/BUILD -> root1/B/BUILD
// /C/I/BUILD -> root1/C/I/BUILD
// /C/D -> root1/C/D
// /C/E -> root1/C/E
// /F/G -> root1/F/G
// /H/I -> root5/H/I
//
// Root 5 (pointed to by Root 4)
// Note: the following BUILD file will be found if explicitly specified, but it
// would not be found if using wildcards. That is because isDirectory
// will return false since the symlink target is not in the workspace.
// /H/I/BUILD
rootDir1 = scratch.resolve("/home/user/src-foo/workspace");
rootDir2 = scratch.resolve("/somewhere/1234567/build/workspace");
rootDir3ParentParent = scratch.resolve("/usr/local/google/jrluser-foo");
rootDir3 = rootDir3ParentParent.getRelative("READONLY/workspace");
rootDir4Parent = scratch.resolve("/usr/local/symlinks/client_symlink_jrluser-foo");
rootDir4 = rootDir4Parent.getRelative("workspace");
rootDir5 = scratch.resolve("/foo/bar");
rootDir1WorkspaceFile = scratch.file(rootDir1 + "/WORKSPACE");
buildBazelFile1A = createBuildFile(rootDir1, "A", true);
buildFile1B = createBuildFile(rootDir1, "B");
createBuildFile(rootDir1, "C/I");
scratch.file(rootDir1.getPathString() + "/F/G");
rootDir1.getRelative("C").createDirectory();
rootDir1.getRelative("C/D").createDirectory();
rootDir1.getRelative("C/E").createDirectory();
// Workspace file in rootDir2.
scratch.file(rootDir2 + "/WORKSPACE");
createBuildFile(rootDir2, "B");
buildFile2C = createBuildFile(rootDir2, "C");
buildFile2CD = createBuildFile(rootDir2, "C/D");
buildFile2F = createBuildFile(rootDir2, "F");
buildFile2FGH = createBuildFile(rootDir2, "F/G/H");
scratch.file(rootDir2.getPathString() + "/C/I");
// Root3 just needs a symlink to 4
FileSystemUtils.ensureSymbolicLink(
rootDir3ParentParent.getRelative("READONLY"), rootDir4Parent);
buildBazelFile3A = rootDir3.getRelative("A/BUILD.bazel");
buildFile3B = rootDir3.getRelative("B/BUILD");
buildFile3CI = rootDir3.getRelative("C/I/BUILD");
// Root4
FileSystemUtils.ensureSymbolicLink(
rootDir4.getRelative("A"), rootDir1.getRelative("A"));
FileSystemUtils.ensureSymbolicLink(
rootDir4.getRelative("B/BUILD"), rootDir1.getRelative("B/BUILD"));
FileSystemUtils.ensureSymbolicLink(
rootDir4.getRelative("C/I/BUILD"), rootDir1.getRelative("C/I/BUILD"));
FileSystemUtils.ensureSymbolicLink(
rootDir4.getRelative("C/D/BUILD"), rootDir1.getRelative("C/D/BUILD"));
FileSystemUtils.ensureSymbolicLink(
rootDir4.getRelative("C/E/BUILD"), rootDir1.getRelative("C/E/BUILD"));
FileSystemUtils.ensureSymbolicLink(
rootDir4.getRelative("F/G/BUILD"), rootDir1.getRelative("F/G/BUILD"));
FileSystemUtils.ensureSymbolicLink(
rootDir4.getRelative("H/I"), rootDir5.getRelative("H/I"));
// Root5
createBuildFile(rootDir5, "H/I");
locator =
new PathPackageLocator(
outputBase,
ImmutableList.of(Root.fromPath(rootDir1), Root.fromPath(rootDir2)),
BazelSkyframeExecutorConstants.BUILD_FILES_BY_PRIORITY);
locatorWithSymlinks =
new PathPackageLocator(
outputBase,
ImmutableList.of(Root.fromPath(rootDir3)),
BazelSkyframeExecutorConstants.BUILD_FILES_BY_PRIORITY);
}
private Path createBuildFile(Path workspace, String packageName) throws IOException {
return createBuildFile(workspace, packageName, false);
}
private Path createBuildFile(Path workspace, String packageName, boolean dotBazel)
throws IOException {
String buildFileName = dotBazel ? "BUILD.bazel" : "BUILD";
return scratch.file(workspace + "/" + packageName + "/" + buildFileName);
}
private void checkNoPackage(String packageName) {
checkNoPackage(getLocator(), packageName);
}
private static void checkNoPackage(PathPackageLocator locator, String packageName) {
assertThat(
locator.getPackageBuildFileNullable(
PackageIdentifier.createInMainRepo(packageName), SyscallCache.NO_CACHE))
.isNull();
}
@Test
public void testGetPackageBuildFile() throws Exception {
assertThat(
locator.getPackageBuildFileNullable(
PackageIdentifier.createInMainRepo("A"), SyscallCache.NO_CACHE))
.isEqualTo(buildBazelFile1A);
assertThat(
locator.getPackageBuildFileNullable(
PackageIdentifier.createInMainRepo("A"), SyscallCache.NO_CACHE))
.isEqualTo(buildBazelFile1A);
assertThat(
locator.getPackageBuildFileNullable(
PackageIdentifier.createInMainRepo("B"), SyscallCache.NO_CACHE))
.isEqualTo(buildFile1B);
assertThat(
locator.getPackageBuildFileNullable(
PackageIdentifier.createInMainRepo("B"), SyscallCache.NO_CACHE))
.isEqualTo(buildFile1B);
assertThat(
locator.getPackageBuildFileNullable(
PackageIdentifier.createInMainRepo("C"), SyscallCache.NO_CACHE))
.isEqualTo(buildFile2C);
assertThat(
locator.getPackageBuildFileNullable(
PackageIdentifier.createInMainRepo("C"), SyscallCache.NO_CACHE))
.isEqualTo(buildFile2C);
assertThat(
locator.getPackageBuildFileNullable(
PackageIdentifier.createInMainRepo("C/D"), SyscallCache.NO_CACHE))
.isEqualTo(buildFile2CD);
assertThat(
locator.getPackageBuildFileNullable(
PackageIdentifier.createInMainRepo("C/D"), SyscallCache.NO_CACHE))
.isEqualTo(buildFile2CD);
checkNoPackage("C/E");
assertThat(
locator.getPackageBuildFileNullable(
PackageIdentifier.createInMainRepo("C/E"), SyscallCache.NO_CACHE))
.isNull();
assertThat(
locator.getPackageBuildFileNullable(
PackageIdentifier.createInMainRepo("F"), SyscallCache.NO_CACHE))
.isEqualTo(buildFile2F);
checkNoPackage("F/G");
assertThat(
locator.getPackageBuildFileNullable(
PackageIdentifier.createInMainRepo("F/G"), SyscallCache.NO_CACHE))
.isNull();
assertThat(
locator.getPackageBuildFileNullable(
PackageIdentifier.createInMainRepo("F/G/H"), SyscallCache.NO_CACHE))
.isEqualTo(buildFile2FGH);
assertThat(
locator.getPackageBuildFileNullable(
PackageIdentifier.createInMainRepo("F/G/H"), SyscallCache.NO_CACHE))
.isEqualTo(buildFile2FGH);
checkNoPackage("I");
}
@Test
public void testGetPackageBuildFileWithSymlinks() throws Exception {
assertThat(
locatorWithSymlinks.getPackageBuildFileNullable(
PackageIdentifier.createInMainRepo("A"), SyscallCache.NO_CACHE))
.isEqualTo(buildBazelFile3A);
assertThat(
locatorWithSymlinks.getPackageBuildFileNullable(
PackageIdentifier.createInMainRepo("B"), SyscallCache.NO_CACHE))
.isEqualTo(buildFile3B);
assertThat(
locatorWithSymlinks.getPackageBuildFileNullable(
PackageIdentifier.createInMainRepo("C/I"), SyscallCache.NO_CACHE))
.isEqualTo(buildFile3CI);
checkNoPackage(locatorWithSymlinks, "C/D");
}
@Test
public void testGetWorkspaceFile() throws Exception {
assertThat(locator.getWorkspaceFile(SyscallCache.NO_CACHE)).isEqualTo(rootDir1WorkspaceFile);
}
private Path setLocator(String root) {
Path nonExistentRoot = scratch.resolve(root);
this.locator =
PathPackageLocator.create(
/*outputBase=*/ null,
Arrays.asList(root),
reporter,
/*workspace=*/ FileSystemUtils.getWorkingDirectory(),
/* clientWorkingDirectory= */ FileSystemUtils.getWorkingDirectory(
scratch.getFileSystem()),
BazelSkyframeExecutorConstants.BUILD_FILES_BY_PRIORITY);
return nonExistentRoot;
}
@Test
public void nonexistentRoot() throws Exception {
Path nonExistentRoot1 = setLocator("/non/existent/1/workspace");
createBuildFile(nonExistentRoot1, "X");
// Now let's create the root:
// The package isn't found
checkNoPackage("X");
}
@Test
public void testPathResolution() throws Exception {
Path workspace = scratch.dir("/some/path/to/workspace");
Path clientPath = workspace.getRelative("somewhere/below/workspace");
scratch.dir(clientPath.getPathString());
Path belowClient = clientPath.getRelative("below/client");
scratch.dir(belowClient.getPathString());
List<String> pathElements = ImmutableList.of(
"./below/client", // Client-relative
".", // Client-relative
"%workspace%/somewhere", // Workspace-relative
// Absolute
clientPath.getRelative("below").getPathString());
assertThat(
PathPackageLocator.create(
/*outputBase=*/ null,
pathElements,
reporter,
workspace.asFragment(),
clientPath,
BazelSkyframeExecutorConstants.BUILD_FILES_BY_PRIORITY)
.getPathEntries())
.containsExactly(
Root.fromPath(belowClient),
Root.fromPath(clientPath),
Root.fromPath(workspace.getRelative("somewhere")),
Root.fromPath(clientPath.getRelative("below")))
.inOrder();
}
@Test
public void testRelativePathWarning() throws Exception {
Path workspace = scratch.dir("/some/path/to/workspace");
// No warning if workspace == cwd.
PathPackageLocator.create(
/*outputBase=*/ null,
ImmutableList.of("./foo"),
reporter,
workspace.asFragment(),
workspace,
BazelSkyframeExecutorConstants.BUILD_FILES_BY_PRIORITY);
assertThat(eventCollector.count()).isSameInstanceAs(0);
PathPackageLocator.create(
/*outputBase=*/ null,
ImmutableList.of("./foo"),
reporter,
workspace.asFragment(),
workspace.getRelative("foo"),
BazelSkyframeExecutorConstants.BUILD_FILES_BY_PRIORITY);
assertThat(eventCollector.count()).isSameInstanceAs(1);
assertContainsEvent("The package path element 'foo' will be taken relative");
}
/** Regression test for bug: "IllegalArgumentException in PathPackageLocator.create()" */
@Test
public void testDollarSigns() throws Exception {
Path workspace = scratch.dir("/some/path/to/workspace$1");
PathPackageLocator.create(
/*outputBase=*/ null,
ImmutableList.of("%workspace%/blabla"),
reporter,
workspace.asFragment(),
workspace.getRelative("foo"),
BazelSkyframeExecutorConstants.BUILD_FILES_BY_PRIORITY);
}
}