blob: 02b80adbc6cdf5e4531c315d73794f42a42bfdaa [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.skyframe;
import static com.google.common.truth.Truth.assertThat;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
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.FileStateValue;
import com.google.devtools.build.lib.actions.FileValue;
import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider;
import com.google.devtools.build.lib.analysis.util.BuildViewTestCase;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.cmdline.RepositoryName;
import com.google.devtools.build.lib.events.NullEventHandler;
import com.google.devtools.build.lib.packages.NoSuchTargetException;
import com.google.devtools.build.lib.packages.Package;
import com.google.devtools.build.lib.packages.PackageFactory.EnvironmentExtension;
import com.google.devtools.build.lib.packages.Rule;
import com.google.devtools.build.lib.packages.WorkspaceFileValue;
import com.google.devtools.build.lib.packages.WorkspaceFileValue.WorkspaceFileKey;
import com.google.devtools.build.lib.pkgcache.PathPackageLocator;
import com.google.devtools.build.lib.rules.repository.ManagedDirectoriesKnowledge;
import com.google.devtools.build.lib.rules.repository.ManagedDirectoriesKnowledgeImpl;
import com.google.devtools.build.lib.rules.repository.ManagedDirectoriesKnowledgeImpl.ManagedDirectoriesListener;
import com.google.devtools.build.lib.rules.repository.RepositoryDelegatorFunction;
import com.google.devtools.build.lib.skyframe.util.SkyframeExecutorTestUtils;
import com.google.devtools.build.lib.syntax.StarlarkSemantics;
import com.google.devtools.build.lib.testutil.MoreAsserts;
import com.google.devtools.build.lib.testutil.TestRuleClassProvider;
import com.google.devtools.build.lib.vfs.ModifiedFileSet;
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.RootedPath;
import com.google.devtools.build.skyframe.EvaluationResult;
import com.google.devtools.build.skyframe.Injectable;
import com.google.devtools.build.skyframe.SkyFunction;
import com.google.devtools.build.skyframe.SkyFunctionName;
import com.google.devtools.build.skyframe.SkyKey;
import java.io.IOException;
import java.util.Objects;
import java.util.Set;
import javax.annotation.Nullable;
import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.mockito.Mockito;
import org.mockito.hamcrest.MockitoHamcrest;
/**
* Test for {@link WorkspaceFileFunction}.
*/
@RunWith(JUnit4.class)
public class WorkspaceFileFunctionTest extends BuildViewTestCase {
private WorkspaceFileFunction workspaceSkyFunc;
private ExternalPackageFunction externalSkyFunc;
private WorkspaceASTFunction astSkyFunc;
private FakeFileValue fakeWorkspaceFileValue;
private TestManagedDirectoriesKnowledge testManagedDirectoriesKnowledge;
static class FakeFileValue extends FileValue {
private boolean exists;
private long size;
FakeFileValue() {
super();
exists = true;
size = 0L;
}
@Override
public RootedPath realRootedPath() {
throw new UnsupportedOperationException();
}
@Override
public FileStateValue realFileStateValue() {
throw new UnsupportedOperationException();
}
@Override
public boolean exists() {
return exists;
}
@Override
public boolean isFile() {
return exists;
}
@Override
public ImmutableList<RootedPath> logicalChainDuringResolution() {
throw new UnsupportedOperationException();
}
void setExists(boolean exists) {
this.exists = exists;
}
@Override
public long getSize() {
return size;
}
void setSize(long size) {
this.size = size;
}
}
@Before
public final void setUp() throws Exception {
ConfiguredRuleClassProvider ruleClassProvider =
TestRuleClassProvider.getRuleClassProvider(true);
workspaceSkyFunc =
new WorkspaceFileFunction(
ruleClassProvider,
pkgFactory,
directories,
/*skylarkImportLookupFunctionForInlining=*/ null);
externalSkyFunc = new ExternalPackageFunction();
astSkyFunc = new WorkspaceASTFunction(ruleClassProvider);
fakeWorkspaceFileValue = new FakeFileValue();
}
@Override
protected ManagedDirectoriesKnowledge getManagedDirectoriesKnowledge() {
testManagedDirectoriesKnowledge = new TestManagedDirectoriesKnowledge();
return testManagedDirectoriesKnowledge;
}
@Override
protected Iterable<EnvironmentExtension> getEnvironmentExtensions() {
return ImmutableList.of();
}
private Label getLabelMapping(Package pkg, String name) throws NoSuchTargetException {
return (Label) ((Rule) pkg.getTarget(name)).getAttributeContainer().getAttr("actual");
}
private RootedPath createWorkspaceFile(String... contents) throws IOException {
Path workspacePath = scratch.overwriteFile("WORKSPACE", contents);
fakeWorkspaceFileValue.setSize(workspacePath.getFileSize());
return RootedPath.toRootedPath(
Root.fromPath(workspacePath.getParentDirectory()),
PathFragment.create(workspacePath.getBaseName()));
}
// Dummy hamcrest matcher that match the function name of a skykey
static class SkyKeyMatchers extends BaseMatcher<SkyKey> {
private final SkyFunctionName functionName;
public SkyKeyMatchers(SkyFunctionName functionName) {
this.functionName = functionName;
}
@Override
public boolean matches(Object item) {
if (item instanceof SkyKey) {
return ((SkyKey) item).functionName().equals(functionName);
}
return false;
}
@Override
public void describeTo(Description description) {}
}
private SkyFunction.Environment getEnv() throws InterruptedException {
PathPackageLocator locator = Mockito.mock(PathPackageLocator.class);
Mockito.when(locator.getPathEntries())
.thenReturn(ImmutableList.of(Root.fromPath(directories.getWorkspace())));
SkyFunction.Environment env = Mockito.mock(SkyFunction.Environment.class);
Mockito.when(env.getValue(MockitoHamcrest.argThat(new SkyKeyMatchers(FileValue.FILE))))
.then(
invocation -> {
SkyKey key = (SkyKey) invocation.getArguments()[0];
String path = ((RootedPath) key.argument()).getRootRelativePath().getPathString();
FakeFileValue result = new FakeFileValue();
result.setExists(path.equals("WORKSPACE"));
return result;
});
Mockito.when(
env.getValue(
MockitoHamcrest.argThat(new SkyKeyMatchers(WorkspaceFileValue.WORKSPACE_FILE))))
.then(
invocation -> {
SkyKey key = (SkyKey) invocation.getArguments()[0];
return workspaceSkyFunc.compute(key, getEnv());
});
Mockito.when(
env.getValue(MockitoHamcrest.argThat(new SkyKeyMatchers(SkyFunctions.WORKSPACE_AST))))
.then(
invocation -> {
SkyKey key = (SkyKey) invocation.getArguments()[0];
return astSkyFunc.compute(key, getEnv());
});
Mockito.when(
env.getValue(MockitoHamcrest.argThat(new SkyKeyMatchers(SkyFunctions.PRECOMPUTED))))
.then(
invocation -> {
SkyKey key = (SkyKey) invocation.getArguments()[0];
if (key.equals(PrecomputedValue.STARLARK_SEMANTICS.getKeyForTesting())) {
return new PrecomputedValue(StarlarkSemantics.DEFAULT_SEMANTICS);
} else if (key.equals(
RepositoryDelegatorFunction.RESOLVED_FILE_INSTEAD_OF_WORKSPACE
.getKeyForTesting())) {
return new PrecomputedValue(Optional.<RootedPath>absent());
} else if (key.equals(PrecomputedValue.PATH_PACKAGE_LOCATOR.getKeyForTesting())) {
return new PrecomputedValue(locator);
} else {
return null;
}
});
return env;
}
private EvaluationResult<WorkspaceFileValue> eval(SkyKey key) throws InterruptedException {
getSkyframeExecutor()
.invalidateFilesUnderPathForTesting(
reporter,
ModifiedFileSet.builder().modify(PathFragment.create("WORKSPACE")).build(),
Root.fromPath(rootDirectory));
return SkyframeExecutorTestUtils.evaluate(
getSkyframeExecutor(), key, /*keepGoing=*/ false, reporter);
}
@Test
public void testImportToChunkMapSimple() throws Exception {
scratch.file("a.bzl", "a = 'a'");
scratch.file("b.bzl", "b = 'b'");
scratch.file("BUILD", "");
RootedPath workspace =
createWorkspaceFile(
"WORKSPACE",
"workspace(name = 'good')",
"load('//:a.bzl', 'a')",
"x = 1 #for chunk break",
"load('//:b.bzl', 'b')");
SkyKey key1 = WorkspaceFileValue.key(workspace, 1);
EvaluationResult<WorkspaceFileValue> result1 = eval(key1);
WorkspaceFileValue value1 = result1.get(key1);
assertThat(value1.getImportToChunkMap()).containsEntry("//:a.bzl", 1);
SkyKey key2 = WorkspaceFileValue.key(workspace, 2);
EvaluationResult<WorkspaceFileValue> result2 = eval(key2);
WorkspaceFileValue value2 = result2.get(key2);
assertThat(value2.getImportToChunkMap()).containsEntry("//:a.bzl", 1);
assertThat(value2.getImportToChunkMap()).containsEntry("//:b.bzl", 2);
}
@Test
public void testImportToChunkMapDoesNotOverrideDuplicate() throws Exception {
scratch.file("a.bzl", "a = 'a'");
scratch.file("BUILD", "");
RootedPath workspace =
createWorkspaceFile(
"WORKSPACE",
"workspace(name = 'good')",
"load('//:a.bzl', 'a')",
"x = 1 #for chunk break",
"load('//:a.bzl', 'a')");
SkyKey key1 = WorkspaceFileValue.key(workspace, 1);
EvaluationResult<WorkspaceFileValue> result1 = eval(key1);
WorkspaceFileValue value1 = result1.get(key1);
assertThat(value1.getImportToChunkMap()).containsEntry("//:a.bzl", 1);
SkyKey key2 = WorkspaceFileValue.key(workspace, 2);
EvaluationResult<WorkspaceFileValue> result2 = eval(key2);
WorkspaceFileValue value2 = result2.get(key2);
assertThat(value2.getImportToChunkMap()).containsEntry("//:a.bzl", 1);
assertThat(value2.getImportToChunkMap()).doesNotContainEntry("//:a.bzl", 2);
}
@Test
public void testRepositoryMappingInChunks() throws Exception {
scratch.file("b.bzl", "b = 'b'");
scratch.file("BUILD", "");
RootedPath workspace =
createWorkspaceFile(
"workspace(name = 'good')",
"local_repository(name = 'a', path = '../a', repo_mapping = {'@x' : '@y'})",
"load('//:b.bzl', 'b')",
"local_repository(name = 'b', path = '../b', repo_mapping = {'@x' : '@y'})");
RepositoryName a = RepositoryName.create("@a");
RepositoryName b = RepositoryName.create("@b");
RepositoryName x = RepositoryName.create("@x");
RepositoryName y = RepositoryName.create("@y");
RepositoryName good = RepositoryName.create("@good");
RepositoryName main = RepositoryName.create("@");
SkyKey key0 = WorkspaceFileValue.key(workspace, 0);
EvaluationResult<WorkspaceFileValue> result0 = eval(key0);
WorkspaceFileValue value0 = result0.get(key0);
assertThat(value0.getRepositoryMapping()).containsEntry(a, ImmutableMap.of(x, y, good, main));
SkyKey key1 = WorkspaceFileValue.key(workspace, 1);
EvaluationResult<WorkspaceFileValue> result1 = eval(key1);
WorkspaceFileValue value1 = result1.get(key1);
assertThat(value1.getRepositoryMapping()).containsEntry(a, ImmutableMap.of(x, y, good, main));
assertThat(value1.getRepositoryMapping()).containsEntry(b, ImmutableMap.of(x, y, good, main));
}
@Test
public void setTestManagedDirectoriesKnowledge() throws Exception {
PrecomputedValue precomputedValue =
(PrecomputedValue)
getEnv().getValue(PrecomputedValue.STARLARK_SEMANTICS.getKeyForTesting());
StarlarkSemantics semantics =
(StarlarkSemantics) Preconditions.checkNotNull(precomputedValue).get();
Injectable injectable = getSkyframeExecutor().injectable();
try {
StarlarkSemantics semanticsWithManagedDirectories =
StarlarkSemantics.builderWithDefaults()
.experimentalAllowIncrementalRepositoryUpdates(true)
.build();
PrecomputedValue.STARLARK_SEMANTICS.set(injectable, semanticsWithManagedDirectories);
TestManagedDirectoriesListener listener = new TestManagedDirectoriesListener();
ManagedDirectoriesKnowledgeImpl knowledge = new ManagedDirectoriesKnowledgeImpl(listener);
RepositoryName one = RepositoryName.create("@repo1");
RepositoryName two = RepositoryName.create("@repo2");
RepositoryName three = RepositoryName.create("@repo3");
PathFragment pf1 = PathFragment.create("dir1");
PathFragment pf2 = PathFragment.create("dir2");
PathFragment pf3 = PathFragment.create("dir3");
assertThat(knowledge.getManagedDirectories(one)).isEmpty();
assertThat(knowledge.getOwnerRepository(pf1)).isNull();
WorkspaceFileValue workspaceFileValue = createWorkspaceFileValueForTest();
boolean isChanged = knowledge.workspaceHeaderReloaded(null, workspaceFileValue);
assertThat(isChanged).isTrue();
assertThat(listener.getRepositoryNames()).containsExactly(one, two);
assertThat(knowledge.getManagedDirectories(one)).containsExactly(pf1, pf2);
assertThat(knowledge.getManagedDirectories(two)).containsExactly(pf3);
assertThat(knowledge.getManagedDirectories(three)).isEmpty();
assertThat(knowledge.getOwnerRepository(pf1)).isEqualTo(one);
assertThat(knowledge.getOwnerRepository(pf2)).isEqualTo(one);
assertThat(knowledge.getOwnerRepository(pf3)).isEqualTo(two);
// Nothing changed, let's test the behavior.
listener.reset();
isChanged = knowledge.workspaceHeaderReloaded(workspaceFileValue, workspaceFileValue);
assertThat(isChanged).isFalse();
assertThat(listener.getRepositoryNames()).containsExactly(one, two);
assertThat(knowledge.getManagedDirectories(one)).containsExactly(pf1, pf2);
assertThat(knowledge.getManagedDirectories(two)).containsExactly(pf3);
assertThat(knowledge.getManagedDirectories(three)).isEmpty();
assertThat(knowledge.getOwnerRepository(pf1)).isEqualTo(one);
assertThat(knowledge.getOwnerRepository(pf2)).isEqualTo(one);
assertThat(knowledge.getOwnerRepository(pf3)).isEqualTo(two);
} finally {
PrecomputedValue.STARLARK_SEMANTICS.set(injectable, semantics);
}
}
@Test
public void testManagedDirectories() throws Exception {
PrecomputedValue precomputedValue =
(PrecomputedValue)
getEnv().getValue(PrecomputedValue.STARLARK_SEMANTICS.getKeyForTesting());
StarlarkSemantics semantics =
(StarlarkSemantics) Preconditions.checkNotNull(precomputedValue).get();
Injectable injectable = getSkyframeExecutor().injectable();
try {
StarlarkSemantics semanticsWithManagedDirectories =
StarlarkSemantics.builderWithDefaults()
.experimentalAllowIncrementalRepositoryUpdates(true)
.build();
PrecomputedValue.STARLARK_SEMANTICS.set(injectable, semanticsWithManagedDirectories);
createWorkspaceFileValueForTest();
assertManagedDirectoriesParsingError(
"{'@repo1': 'dir1', '@repo2': ['dir3']}",
"managed_directories attribute value should be of the type attr.string_list_dict(),"
+ " mapping repository name to the list of managed directories.");
assertManagedDirectoriesParsingError(
"{'@repo1': ['dir1'], '@repo2': ['dir1']}",
"managed_directories attribute should not contain multiple (or duplicate) repository"
+ " mappings for the same directory ('dir1').");
assertManagedDirectoriesParsingError(
"{'@repo1': ['']}", "Expected managed directory path to be non-empty string.");
assertManagedDirectoriesParsingError(
"{'@repo1': ['/abc']}",
"Expected managed directory path ('/abc') to be relative to the workspace root.");
assertManagedDirectoriesParsingError(
"{'@repo1': ['../abc']}",
"Expected managed directory path ('../abc') to be under the workspace root.");
assertManagedDirectoriesParsingError(
"{'@repo1': ['a/b', 'a/b']}",
"managed_directories attribute should not contain multiple (or duplicate)"
+ " repository mappings for the same directory ('a/b').");
assertManagedDirectoriesParsingError(
"{'@repo1': [], '@repo1': [] }", "Duplicated key \"@repo1\" when creating dictionary");
assertManagedDirectoriesParsingError(
"{'@repo1': ['a/b'], '@repo2': ['a/b/c/..'] }",
"managed_directories attribute should not contain multiple (or duplicate)"
+ " repository mappings for the same directory ('a/b/c/..').");
assertManagedDirectoriesParsingError(
"{'@repo1': ['a'], '@repo2': ['a/b'] }",
"managed_directories attribute value can not contain nested mappings."
+ " 'a/b' is a descendant of 'a'.");
assertManagedDirectoriesParsingError(
"{'@repo1': ['a/b'], '@repo2': ['a'] }",
"managed_directories attribute value can not contain nested mappings."
+ " 'a/b' is a descendant of 'a'.");
assertManagedDirectoriesParsingError(
"{'repo1': []}",
"Cannot parse repository name 'repo1'. Repository name should start with '@'.");
} finally {
PrecomputedValue.STARLARK_SEMANTICS.set(injectable, semantics);
}
}
private WorkspaceFileValue createWorkspaceFileValueForTest() throws Exception {
WorkspaceFileValue workspaceFileValue =
parseWorkspaceFileValue(
"workspace(",
" name = 'rr',",
" managed_directories = {'@repo1': ['dir1', 'dir2'], '@repo2': ['dir3/dir1/..']}",
")");
ImmutableMap<PathFragment, RepositoryName> managedDirectories =
workspaceFileValue.getManagedDirectories();
assertThat(managedDirectories).isNotNull();
assertThat(managedDirectories).hasSize(3);
assertThat(managedDirectories)
.containsExactly(
PathFragment.create("dir1"), RepositoryName.create("@repo1"),
PathFragment.create("dir2"), RepositoryName.create("@repo1"),
PathFragment.create("dir3"), RepositoryName.create("@repo2"));
return workspaceFileValue;
}
private void assertManagedDirectoriesParsingError(
String managedDirectoriesValue, String expectedError) throws Exception {
parseWorkspaceFileValueWithError(
expectedError,
"workspace(",
" name = 'rr',",
" managed_directories = " + managedDirectoriesValue,
")");
}
private WorkspaceFileValue parseWorkspaceFileValue(String... lines) throws Exception {
WorkspaceFileValue workspaceFileValue = parseWorkspaceFileValueImpl(lines);
Package pkg = workspaceFileValue.getPackage();
if (pkg.containsErrors()) {
throw new RuntimeException(
Preconditions.checkNotNull(Iterables.getFirst(pkg.getEvents(), null)).getMessage());
}
return workspaceFileValue;
}
private void parseWorkspaceFileValueWithError(String expectedError, String... lines)
throws Exception {
WorkspaceFileValue workspaceFileValue = parseWorkspaceFileValueImpl(lines);
Package pkg = workspaceFileValue.getPackage();
assertThat(pkg.containsErrors()).isTrue();
MoreAsserts.assertContainsEvent(pkg.getEvents(), expectedError);
}
private WorkspaceFileValue parseWorkspaceFileValueImpl(String[] lines)
throws IOException, InterruptedException {
RootedPath workspaceFile = createWorkspaceFile(lines);
WorkspaceFileKey key = WorkspaceFileValue.key(workspaceFile);
EvaluationResult<WorkspaceFileValue> result = eval(key);
return result.get(key);
}
@Test
public void testInvalidRepo() throws Exception {
RootedPath workspacePath = createWorkspaceFile("workspace(name = 'foo$')");
PackageValue value =
(PackageValue) externalSkyFunc
.compute(ExternalPackageFunction.key(workspacePath), getEnv());
Package pkg = value.getPackage();
assertThat(pkg.containsErrors()).isTrue();
MoreAsserts.assertContainsEvent(pkg.getEvents(), "foo$ is not a legal workspace name");
}
@Test
public void testBindFunction() throws Exception {
String[] lines = {"bind(name = 'foo/bar',", "actual = '//foo:bar')"};
RootedPath workspacePath = createWorkspaceFile(lines);
SkyKey key = ExternalPackageFunction.key(workspacePath);
PackageValue value = (PackageValue) externalSkyFunc.compute(key, getEnv());
Package pkg = value.getPackage();
assertThat(getLabelMapping(pkg, "foo/bar"))
.isEqualTo(Label.parseAbsolute("//foo:bar", ImmutableMap.of()));
MoreAsserts.assertNoEvents(pkg.getEvents());
}
@Test
public void testBindArgsReversed() throws Exception {
String[] lines = {"bind(actual = '//foo:bar', name = 'foo/bar')"};
RootedPath workspacePath = createWorkspaceFile(lines);
SkyKey key = ExternalPackageFunction.key(workspacePath);
PackageValue value = (PackageValue) externalSkyFunc.compute(key, getEnv());
Package pkg = value.getPackage();
assertThat(getLabelMapping(pkg, "foo/bar"))
.isEqualTo(Label.parseAbsolute("//foo:bar", ImmutableMap.of()));
MoreAsserts.assertNoEvents(pkg.getEvents());
}
@Test
public void testNonExternalBinding() throws Exception {
// name must be a valid label name.
String[] lines = {"bind(name = 'foo:bar', actual = '//bar/baz')"};
RootedPath workspacePath = createWorkspaceFile(lines);
PackageValue value =
(PackageValue) externalSkyFunc
.compute(ExternalPackageFunction.key(workspacePath), getEnv());
Package pkg = value.getPackage();
assertThat(pkg.containsErrors()).isTrue();
MoreAsserts.assertContainsEvent(pkg.getEvents(), "target names may not contain ':'");
}
@Test
public void testWorkspaceFileParsingError() throws Exception {
// //external:bar:baz is not a legal package.
String[] lines = {"bind(name = 'foo/bar', actual = '//external:bar:baz')"};
RootedPath workspacePath = createWorkspaceFile(lines);
PackageValue value =
(PackageValue) externalSkyFunc
.compute(ExternalPackageFunction.key(workspacePath), getEnv());
Package pkg = value.getPackage();
assertThat(pkg.containsErrors()).isTrue();
MoreAsserts.assertContainsEvent(pkg.getEvents(), "target names may not contain ':'");
}
@Test
public void testNoWorkspaceFile() throws Exception {
// Even though the WORKSPACE exists, Skyframe thinks it doesn't, so it doesn't.
String[] lines = {"bind(name = 'foo/bar', actual = '//foo:bar')"};
RootedPath workspacePath = createWorkspaceFile(lines);
fakeWorkspaceFileValue.setExists(false);
PackageValue value =
(PackageValue) externalSkyFunc
.compute(ExternalPackageFunction.key(workspacePath), getEnv());
Package pkg = value.getPackage();
assertThat(pkg.containsErrors()).isFalse();
MoreAsserts.assertNoEvents(pkg.getEvents());
}
@Test
public void testListBindFunction() throws Exception {
String[] lines = {
"L = ['foo', 'bar']", "bind(name = '%s/%s' % (L[0], L[1]),", "actual = '//foo:bar')"
};
RootedPath workspacePath = createWorkspaceFile(lines);
SkyKey key = ExternalPackageFunction.key(workspacePath);
PackageValue value = (PackageValue) externalSkyFunc.compute(key, getEnv());
Package pkg = value.getPackage();
assertThat(getLabelMapping(pkg, "foo/bar"))
.isEqualTo(Label.parseAbsolute("//foo:bar", ImmutableMap.of()));
MoreAsserts.assertNoEvents(pkg.getEvents());
}
@Test
public void testWorkspaceFileValueListener() throws Exception {
// Normally, syscalls cache is reset in the sync() method of the SkyframeExecutor, before
// diffing.
// But here we are calling only actual diffing part, exposed for testing:
// handleDiffsForTesting(), so we better turn off the syscalls cache.
skyframeExecutor.turnOffSyscallCacheForTesting();
createWorkspaceFile("workspace(name = 'old')");
skyframeExecutor.handleDiffsForTesting(NullEventHandler.INSTANCE);
assertThat(testManagedDirectoriesKnowledge.getLastWorkspaceName()).isEqualTo("old");
assertThat(testManagedDirectoriesKnowledge.getCnt()).isEqualTo(1);
createWorkspaceFile("workspace(name = 'changed')");
skyframeExecutor.handleDiffsForTesting(NullEventHandler.INSTANCE);
assertThat(testManagedDirectoriesKnowledge.getLastWorkspaceName()).isEqualTo("changed");
assertThat(testManagedDirectoriesKnowledge.getCnt()).isEqualTo(2);
}
@Test
public void testDoNotSymlinkInExecroot() throws Exception {
PrecomputedValue precomputedValue =
(PrecomputedValue)
getEnv().getValue(PrecomputedValue.STARLARK_SEMANTICS.getKeyForTesting());
StarlarkSemantics semantics =
(StarlarkSemantics) Preconditions.checkNotNull(precomputedValue).get();
Injectable injectable = getSkyframeExecutor().injectable();
try {
StarlarkSemantics semanticsWithNinjaActions =
StarlarkSemantics.builderWithDefaults().experimentalNinjaActions(true).build();
PrecomputedValue.STARLARK_SEMANTICS.set(injectable, semanticsWithNinjaActions);
assertThat(
parseWorkspaceFileValue("dont_symlink_directories_in_execroot(paths = [\"out\"])")
.getDoNotSymlinkInExecrootPaths())
.containsExactly("out");
assertThat(
parseWorkspaceFileValue(
"dont_symlink_directories_in_execroot(paths = [\"out\", \"one more with"
+ " space\"])")
.getDoNotSymlinkInExecrootPaths())
.containsExactly("out", "one more with space");
// Empty sequence is allowed.
assertThat(
parseWorkspaceFileValue("dont_symlink_directories_in_execroot(paths = [])")
.getDoNotSymlinkInExecrootPaths())
.isEmpty();
parseWorkspaceFileValueWithError(
"dont_symlink_directories_in_execroot should not "
+ "contain duplicate values: \"out\" is specified more then once.",
"dont_symlink_directories_in_execroot(paths = [\"out\", \"out\"])");
parseWorkspaceFileValueWithError(
"dont_symlink_directories_in_execroot can only accept "
+ "top level directories under workspace, \"out/subdir\" "
+ "can not be specified as an attribute.",
"dont_symlink_directories_in_execroot(paths = [\"out/subdir\"])");
parseWorkspaceFileValueWithError(
"Empty path can not be passed to " + "dont_symlink_directories_in_execroot.",
"dont_symlink_directories_in_execroot(paths = [\"\"])");
parseWorkspaceFileValueWithError(
"dont_symlink_directories_in_execroot can only "
+ "accept top level directories under workspace, \"/usr/local/bin\" "
+ "can not be specified as an attribute.",
"dont_symlink_directories_in_execroot(paths = [\"/usr/local/bin\"])");
} finally {
PrecomputedValue.STARLARK_SEMANTICS.set(injectable, semantics);
}
}
private static class TestManagedDirectoriesKnowledge implements ManagedDirectoriesKnowledge {
private String lastWorkspaceName;
private int cnt = 0;
@Nullable
@Override
public RepositoryName getOwnerRepository(PathFragment relativePathFragment) {
return null;
}
@Override
public ImmutableSet<PathFragment> getManagedDirectories(RepositoryName repositoryName) {
return null;
}
@Override
public boolean workspaceHeaderReloaded(
@Nullable WorkspaceFileValue oldValue, @Nullable WorkspaceFileValue newValue) {
if (Objects.equals(oldValue, newValue)) {
return false;
}
++cnt;
lastWorkspaceName = newValue != null ? newValue.getPackage().getWorkspaceName() : null;
return true;
}
private String getLastWorkspaceName() {
return lastWorkspaceName;
}
private int getCnt() {
return cnt;
}
}
private static class TestManagedDirectoriesListener implements ManagedDirectoriesListener {
@Nullable private Set<RepositoryName> repositoryNames;
@Override
public void onManagedDirectoriesRefreshed(Set<RepositoryName> repositoryNames) {
this.repositoryNames = repositoryNames;
}
@Nullable
public Set<RepositoryName> getRepositoryNames() {
return repositoryNames;
}
public void reset() {
repositoryNames = null;
}
}
}