blob: db71edaf9613c47c03e861cce96a83ef76e7f960 [file] [log] [blame]
Kristina Chodorow335f0672015-11-16 23:19:13 +00001// Copyright 2015 The Bazel Authors. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package com.google.devtools.build.lib.skyframe;
16
17import static com.google.common.truth.Truth.assertThat;
Florian Weikert92b22362015-12-03 10:17:18 +000018import static org.junit.Assert.fail;
Kristina Chodorow335f0672015-11-16 23:19:13 +000019
20import com.google.common.base.Predicates;
21import com.google.common.collect.ImmutableList;
22import com.google.common.collect.ImmutableMap;
23import com.google.common.collect.Maps;
Googlerc804c662016-12-01 16:53:28 +000024import com.google.common.collect.Sets;
Florian Weikertcca703a2015-12-07 09:56:38 +000025import com.google.devtools.build.lib.analysis.util.BuildViewTestCase;
philwo3bcb9f62017-09-06 12:52:21 +020026import com.google.devtools.build.lib.clock.BlazeClock;
Kristina Chodorow335f0672015-11-16 23:19:13 +000027import com.google.devtools.build.lib.cmdline.Label;
28import com.google.devtools.build.lib.cmdline.PackageIdentifier;
29import com.google.devtools.build.lib.packages.ConstantRuleVisibility;
nharmataff688bf2017-06-07 17:03:52 -040030import com.google.devtools.build.lib.packages.NoSuchPackageException;
Nathan Harmata2022ad82016-02-22 23:04:14 +000031import com.google.devtools.build.lib.packages.NoSuchTargetException;
brandjon674ab862017-10-06 23:17:33 +020032import com.google.devtools.build.lib.packages.SkylarkSemanticsOptions;
Janak Ramakrishnan326c6982016-09-27 14:58:26 +000033import com.google.devtools.build.lib.pkgcache.PackageCacheOptions;
Kristina Chodorow335f0672015-11-16 23:19:13 +000034import com.google.devtools.build.lib.pkgcache.PathPackageLocator;
35import com.google.devtools.build.lib.skyframe.util.SkyframeExecutorTestUtils;
36import com.google.devtools.build.lib.testutil.ManualClock;
Ulf Adamsc73051c62016-03-23 09:18:13 +000037import com.google.devtools.build.lib.util.io.TimestampGranularityMonitor;
Kristina Chodorow335f0672015-11-16 23:19:13 +000038import com.google.devtools.build.lib.vfs.Dirent;
39import com.google.devtools.build.lib.vfs.FileStatus;
40import com.google.devtools.build.lib.vfs.FileSystem;
41import com.google.devtools.build.lib.vfs.FileSystemUtils;
42import com.google.devtools.build.lib.vfs.ModifiedFileSet;
43import com.google.devtools.build.lib.vfs.Path;
44import com.google.devtools.build.lib.vfs.PathFragment;
tomluee6a6862018-01-17 14:36:26 -080045import com.google.devtools.build.lib.vfs.Root;
Kristina Chodorow335f0672015-11-16 23:19:13 +000046import com.google.devtools.build.lib.vfs.RootedPath;
47import com.google.devtools.build.lib.vfs.inmemoryfs.InMemoryFileSystem;
48import com.google.devtools.build.skyframe.ErrorInfo;
49import com.google.devtools.build.skyframe.EvaluationResult;
50import com.google.devtools.build.skyframe.RecordingDifferencer;
51import com.google.devtools.build.skyframe.SkyKey;
52import com.google.devtools.build.skyframe.SkyValue;
Janak Ramakrishnan326c6982016-09-27 14:58:26 +000053import com.google.devtools.common.options.Options;
Kristina Chodorow335f0672015-11-16 23:19:13 +000054import java.io.IOException;
nharmataff688bf2017-06-07 17:03:52 -040055import java.io.InputStream;
Janak Ramakrishnanffbc28a2017-02-13 22:51:45 +000056import java.util.ArrayList;
tomluee6a6862018-01-17 14:36:26 -080057import java.util.Arrays;
Kristina Chodorow335f0672015-11-16 23:19:13 +000058import java.util.Collection;
Janak Ramakrishnanffbc28a2017-02-13 22:51:45 +000059import java.util.List;
Kristina Chodorow335f0672015-11-16 23:19:13 +000060import java.util.Map;
Googlerc804c662016-12-01 16:53:28 +000061import java.util.Set;
Kristina Chodorow335f0672015-11-16 23:19:13 +000062import java.util.UUID;
Kristina Chodorow335f0672015-11-16 23:19:13 +000063import javax.annotation.Nullable;
John Cater94695912016-08-03 12:09:39 +000064import org.junit.Test;
65import org.junit.runner.RunWith;
66import org.junit.runners.JUnit4;
Kristina Chodorow335f0672015-11-16 23:19:13 +000067
68/**
69 * Unit tests of specific functionality of PackageFunction. Note that it's already tested
70 * indirectly in several other places.
71 */
Florian Weikert92b22362015-12-03 10:17:18 +000072@RunWith(JUnit4.class)
Florian Weikertcca703a2015-12-07 09:56:38 +000073public class PackageFunctionTest extends BuildViewTestCase {
Kristina Chodorow335f0672015-11-16 23:19:13 +000074
75 private CustomInMemoryFs fs = new CustomInMemoryFs(new ManualClock());
76
Ulf Adamsc73051c62016-03-23 09:18:13 +000077 private void preparePackageLoading(Path... roots) {
Janak Ramakrishnan326c6982016-09-27 14:58:26 +000078 PackageCacheOptions packageCacheOptions = Options.getDefaults(PackageCacheOptions.class);
79 packageCacheOptions.defaultVisibility = ConstantRuleVisibility.PUBLIC;
80 packageCacheOptions.showLoadingProgress = true;
81 packageCacheOptions.globbingThreads = 7;
Klaus Aehlig6f33a1c2016-09-13 16:46:10 +000082 getSkyframeExecutor()
83 .preparePackageLoading(
John Catere0d1d0e2017-11-28 20:47:41 -080084 new PathPackageLocator(
85 outputBase,
tomluee6a6862018-01-17 14:36:26 -080086 Arrays.stream(roots).map(Root::fromPath).collect(ImmutableList.toImmutableList()),
John Catere0d1d0e2017-11-28 20:47:41 -080087 BazelSkyframeExecutorConstants.BUILD_FILES_BY_PRIORITY),
Janak Ramakrishnan326c6982016-09-27 14:58:26 +000088 packageCacheOptions,
brandjon7dc34162017-04-27 18:34:33 +020089 Options.getDefaults(SkylarkSemanticsOptions.class),
Klaus Aehlig6f33a1c2016-09-13 16:46:10 +000090 "",
91 UUID.randomUUID(),
92 ImmutableMap.<String, String>of(),
Damien Martin-Guillerez777f3af2017-02-08 17:22:02 +000093 ImmutableMap.<String, String>of(),
Klaus Aehlig6f33a1c2016-09-13 16:46:10 +000094 new TimestampGranularityMonitor(BlazeClock.instance()));
Ulf Adamsc73051c62016-03-23 09:18:13 +000095 }
96
Kristina Chodorow335f0672015-11-16 23:19:13 +000097 @Override
Kristina Chodorow335f0672015-11-16 23:19:13 +000098 protected FileSystem createFileSystem() {
99 return fs;
100 }
101
102 private PackageValue validPackage(SkyKey skyKey) throws InterruptedException {
103 EvaluationResult<PackageValue> result = SkyframeExecutorTestUtils.evaluate(
104 getSkyframeExecutor(), skyKey, /*keepGoing=*/false, reporter);
105 if (result.hasError()) {
106 fail(result.getError(skyKey).getException().getMessage());
107 }
108 PackageValue value = result.get(skyKey);
lberkiaea56b32017-05-30 12:35:33 +0200109 assertThat(value.getPackage().containsErrors()).isFalse();
Kristina Chodorow335f0672015-11-16 23:19:13 +0000110 return value;
111 }
112
Florian Weikert92b22362015-12-03 10:17:18 +0000113 @Test
John Cater94695912016-08-03 12:09:39 +0000114 public void testValidPackage() throws Exception {
115 scratch.file("pkg/BUILD");
116 validPackage(PackageValue.key(PackageIdentifier.parse("@//pkg")));
117 }
118
119 @Test
Kristina Chodorow335f0672015-11-16 23:19:13 +0000120 public void testPropagatesFilesystemInconsistencies() throws Exception {
121 reporter.removeHandler(failFastHandler);
122 RecordingDifferencer differencer = getSkyframeExecutor().getDifferencerForTesting();
tomluee6a6862018-01-17 14:36:26 -0800123 Root pkgRoot = getSkyframeExecutor().getPathEntries().get(0);
Kristina Chodorow335f0672015-11-16 23:19:13 +0000124 Path fooBuildFile = scratch.file("foo/BUILD");
125 Path fooDir = fooBuildFile.getParentDirectory();
126
127 // Our custom filesystem says "foo/BUILD" exists but its parent "foo" is a file.
128 FileStatus inconsistentParentFileStatus = new FileStatus() {
129 @Override
130 public boolean isFile() {
131 return true;
132 }
133
134 @Override
135 public boolean isDirectory() {
136 return false;
137 }
138
139 @Override
140 public boolean isSymbolicLink() {
141 return false;
142 }
143
144 @Override
145 public boolean isSpecialFile() {
146 return false;
147 }
148
149 @Override
150 public long getSize() throws IOException {
151 return 0;
152 }
153
154 @Override
155 public long getLastModifiedTime() throws IOException {
156 return 0;
157 }
158
159 @Override
160 public long getLastChangeTime() throws IOException {
161 return 0;
162 }
163
164 @Override
165 public long getNodeId() throws IOException {
166 return 0;
167 }
168 };
aehligc801c392017-12-19 07:12:25 -0800169 fs.stubStat(fooDir, inconsistentParentFileStatus);
Kristina Chodorow335f0672015-11-16 23:19:13 +0000170 RootedPath pkgRootedPath = RootedPath.toRootedPath(pkgRoot, fooDir);
Ulf Adamsc73051c62016-03-23 09:18:13 +0000171 SkyValue fooDirValue = FileStateValue.create(pkgRootedPath, tsgm);
Kristina Chodorow335f0672015-11-16 23:19:13 +0000172 differencer.inject(ImmutableMap.of(FileStateValue.key(pkgRootedPath), fooDirValue));
Brian Silvermand7d6d622016-03-17 09:53:39 +0000173 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//foo"));
Kristina Chodorow335f0672015-11-16 23:19:13 +0000174 String expectedMessage = "/workspace/foo/BUILD exists but its parent path /workspace/foo isn't "
175 + "an existing directory";
176 EvaluationResult<PackageValue> result = SkyframeExecutorTestUtils.evaluate(
177 getSkyframeExecutor(), skyKey, /*keepGoing=*/false, reporter);
lberkiaea56b32017-05-30 12:35:33 +0200178 assertThat(result.hasError()).isTrue();
Kristina Chodorow335f0672015-11-16 23:19:13 +0000179 ErrorInfo errorInfo = result.getError(skyKey);
180 String errorMessage = errorInfo.getException().getMessage();
181 assertThat(errorMessage).contains("Inconsistent filesystem operations");
182 assertThat(errorMessage).contains(expectedMessage);
183 }
184
Florian Weikert92b22362015-12-03 10:17:18 +0000185 @Test
Kristina Chodorow335f0672015-11-16 23:19:13 +0000186 public void testPropagatesFilesystemInconsistencies_Globbing() throws Exception {
187 reporter.removeHandler(failFastHandler);
188 RecordingDifferencer differencer = getSkyframeExecutor().getDifferencerForTesting();
tomluee6a6862018-01-17 14:36:26 -0800189 Root pkgRoot = getSkyframeExecutor().getPathEntries().get(0);
Kristina Chodorow335f0672015-11-16 23:19:13 +0000190 scratch.file("foo/BUILD",
191 "subinclude('//a:a')",
192 "sh_library(name = 'foo', srcs = glob(['bar/**/baz.sh']))");
193 scratch.file("a/BUILD");
194 scratch.file("a/a");
195 Path bazFile = scratch.file("foo/bar/baz/baz.sh");
196 Path bazDir = bazFile.getParentDirectory();
197 Path barDir = bazDir.getParentDirectory();
198
Kristina Chodorow335f0672015-11-16 23:19:13 +0000199 // Our custom filesystem says "foo/bar/baz" does not exist but it also says that "foo/bar"
200 // has a child directory "baz".
aehligc801c392017-12-19 07:12:25 -0800201 fs.stubStat(bazDir, null);
Kristina Chodorow335f0672015-11-16 23:19:13 +0000202 RootedPath barDirRootedPath = RootedPath.toRootedPath(pkgRoot, barDir);
Ulf Adamsc73051c62016-03-23 09:18:13 +0000203 FileStateValue barDirFileStateValue = FileStateValue.create(barDirRootedPath, tsgm);
Kristina Chodorow335f0672015-11-16 23:19:13 +0000204 FileValue barDirFileValue = FileValue.value(barDirRootedPath, barDirFileStateValue,
205 barDirRootedPath, barDirFileStateValue);
206 DirectoryListingValue barDirListing = DirectoryListingValue.value(barDirRootedPath,
207 barDirFileValue, DirectoryListingStateValue.create(ImmutableList.of(
208 new Dirent("baz", Dirent.Type.DIRECTORY))));
209 differencer.inject(ImmutableMap.of(DirectoryListingValue.key(barDirRootedPath), barDirListing));
Brian Silvermand7d6d622016-03-17 09:53:39 +0000210 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//foo"));
Nathan Harmatac0f3d4e2016-10-17 15:49:34 +0000211 String expectedMessage = "/workspace/foo/bar/baz is no longer an existing directory";
Kristina Chodorow335f0672015-11-16 23:19:13 +0000212 EvaluationResult<PackageValue> result = SkyframeExecutorTestUtils.evaluate(
213 getSkyframeExecutor(), skyKey, /*keepGoing=*/false, reporter);
lberkiaea56b32017-05-30 12:35:33 +0200214 assertThat(result.hasError()).isTrue();
Kristina Chodorow335f0672015-11-16 23:19:13 +0000215 ErrorInfo errorInfo = result.getError(skyKey);
216 String errorMessage = errorInfo.getException().getMessage();
217 assertThat(errorMessage).contains("Inconsistent filesystem operations");
218 assertThat(errorMessage).contains(expectedMessage);
219 }
220
221 /** Regression test for unexpected exception type from PackageValue. */
Florian Weikert92b22362015-12-03 10:17:18 +0000222 @Test
Kristina Chodorow335f0672015-11-16 23:19:13 +0000223 public void testDiscrepancyBetweenLegacyAndSkyframePackageLoadingErrors() throws Exception {
224 reporter.removeHandler(failFastHandler);
225 Path fooBuildFile = scratch.file("foo/BUILD",
226 "sh_library(name = 'foo', srcs = glob(['bar/*.sh']))");
227 Path fooDir = fooBuildFile.getParentDirectory();
228 Path barDir = fooDir.getRelative("bar");
229 scratch.file("foo/bar/baz.sh");
aehligc801c392017-12-19 07:12:25 -0800230 fs.scheduleMakeUnreadableAfterReaddir(barDir);
Kristina Chodorow335f0672015-11-16 23:19:13 +0000231
Brian Silvermand7d6d622016-03-17 09:53:39 +0000232 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//foo"));
Kristina Chodorow335f0672015-11-16 23:19:13 +0000233 String expectedMessage = "Encountered error 'Directory is not readable'";
234 EvaluationResult<PackageValue> result = SkyframeExecutorTestUtils.evaluate(
235 getSkyframeExecutor(), skyKey, /*keepGoing=*/false, reporter);
lberkiaea56b32017-05-30 12:35:33 +0200236 assertThat(result.hasError()).isTrue();
Kristina Chodorow335f0672015-11-16 23:19:13 +0000237 ErrorInfo errorInfo = result.getError(skyKey);
238 String errorMessage = errorInfo.getException().getMessage();
239 assertThat(errorMessage).contains("Inconsistent filesystem operations");
240 assertThat(errorMessage).contains(expectedMessage);
241 }
242
Janak Ramakrishnan063b4882016-07-18 20:33:28 +0000243 @SuppressWarnings("unchecked") // Cast of srcs attribute to Iterable<Label>.
244 @Test
245 public void testGlobOrderStable() throws Exception {
246 scratch.file("foo/BUILD", "sh_library(name = 'foo', srcs = glob(['**/*.txt']))");
247 scratch.file("foo/b.txt");
248 scratch.file("foo/c/c.txt");
249 preparePackageLoading(rootDirectory);
250 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//foo"));
251 PackageValue value = validPackage(skyKey);
252 assertThat(
253 (Iterable<Label>)
254 value
255 .getPackage()
256 .getTarget("foo")
257 .getAssociatedRule()
258 .getAttributeContainer()
259 .getAttr("srcs"))
260 .containsExactly(
261 Label.parseAbsoluteUnchecked("//foo:b.txt"),
262 Label.parseAbsoluteUnchecked("//foo:c/c.txt"))
263 .inOrder();
264 scratch.file("foo/d.txt");
265 getSkyframeExecutor()
266 .invalidateFilesUnderPathForTesting(
267 reporter,
nharmatab4060b62017-04-04 17:11:39 +0000268 ModifiedFileSet.builder().modify(PathFragment.create("foo/d.txt")).build(),
tomluee6a6862018-01-17 14:36:26 -0800269 Root.fromPath(rootDirectory));
Janak Ramakrishnan063b4882016-07-18 20:33:28 +0000270 value = validPackage(skyKey);
271 assertThat(
272 (Iterable<Label>)
273 value
274 .getPackage()
275 .getTarget("foo")
276 .getAssociatedRule()
277 .getAttributeContainer()
278 .getAttr("srcs"))
279 .containsExactly(
280 Label.parseAbsoluteUnchecked("//foo:b.txt"),
281 Label.parseAbsoluteUnchecked("//foo:c/c.txt"),
282 Label.parseAbsoluteUnchecked("//foo:d.txt"))
283 .inOrder();
284 }
285
Janak Ramakrishnan063b4882016-07-18 20:33:28 +0000286 @Test
287 public void testGlobOrderStableWithLegacyAndSkyframeComponents() throws Exception {
288 scratch.file("foo/BUILD", "sh_library(name = 'foo', srcs = glob(['*.txt']))");
289 scratch.file("foo/b.txt");
290 scratch.file("foo/a.config");
291 preparePackageLoading(rootDirectory);
292 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//foo"));
Janak Ramakrishnanffbc28a2017-02-13 22:51:45 +0000293 assertSrcs(validPackage(skyKey), "foo", "//foo:b.txt");
Janak Ramakrishnan063b4882016-07-18 20:33:28 +0000294 scratch.overwriteFile(
295 "foo/BUILD", "sh_library(name = 'foo', srcs = glob(['*.txt', '*.config']))");
296 getSkyframeExecutor()
297 .invalidateFilesUnderPathForTesting(
298 reporter,
nharmatab4060b62017-04-04 17:11:39 +0000299 ModifiedFileSet.builder().modify(PathFragment.create("foo/BUILD")).build(),
tomluee6a6862018-01-17 14:36:26 -0800300 Root.fromPath(rootDirectory));
Janak Ramakrishnanffbc28a2017-02-13 22:51:45 +0000301 assertSrcs(validPackage(skyKey), "foo", "//foo:a.config", "//foo:b.txt");
Janak Ramakrishnan063b4882016-07-18 20:33:28 +0000302 scratch.overwriteFile(
303 "foo/BUILD", "sh_library(name = 'foo', srcs = glob(['*.txt', '*.config'])) # comment");
304 getSkyframeExecutor()
305 .invalidateFilesUnderPathForTesting(
306 reporter,
nharmatab4060b62017-04-04 17:11:39 +0000307 ModifiedFileSet.builder().modify(PathFragment.create("foo/BUILD")).build(),
tomluee6a6862018-01-17 14:36:26 -0800308 Root.fromPath(rootDirectory));
Janak Ramakrishnanffbc28a2017-02-13 22:51:45 +0000309 assertSrcs(validPackage(skyKey), "foo", "//foo:a.config", "//foo:b.txt");
Nathan Harmata44e1e3a2016-08-23 21:22:17 +0000310 getSkyframeExecutor().resetEvaluator();
Janak Ramakrishnan326c6982016-09-27 14:58:26 +0000311 PackageCacheOptions packageCacheOptions = Options.getDefaults(PackageCacheOptions.class);
312 packageCacheOptions.defaultVisibility = ConstantRuleVisibility.PUBLIC;
313 packageCacheOptions.showLoadingProgress = true;
314 packageCacheOptions.globbingThreads = 7;
Klaus Aehlig6f33a1c2016-09-13 16:46:10 +0000315 getSkyframeExecutor()
316 .preparePackageLoading(
John Catere0d1d0e2017-11-28 20:47:41 -0800317 new PathPackageLocator(
318 outputBase,
tomluee6a6862018-01-17 14:36:26 -0800319 ImmutableList.of(Root.fromPath(rootDirectory)),
John Catere0d1d0e2017-11-28 20:47:41 -0800320 BazelSkyframeExecutorConstants.BUILD_FILES_BY_PRIORITY),
Janak Ramakrishnan326c6982016-09-27 14:58:26 +0000321 packageCacheOptions,
brandjon7dc34162017-04-27 18:34:33 +0200322 Options.getDefaults(SkylarkSemanticsOptions.class),
Klaus Aehlig6f33a1c2016-09-13 16:46:10 +0000323 "",
324 UUID.randomUUID(),
Klaus Aehlig03b9cfd2016-09-14 13:14:39 +0000325 ImmutableMap.<String, String>of(),
Damien Martin-Guillerez777f3af2017-02-08 17:22:02 +0000326 ImmutableMap.<String, String>of(),
Klaus Aehlig6f33a1c2016-09-13 16:46:10 +0000327 tsgm);
Janak Ramakrishnanffbc28a2017-02-13 22:51:45 +0000328 assertSrcs(validPackage(skyKey), "foo", "//foo:a.config", "//foo:b.txt");
Janak Ramakrishnan063b4882016-07-18 20:33:28 +0000329 }
330
Janak Ramakrishnanffbc28a2017-02-13 22:51:45 +0000331 /**
332 * Tests that a symlink to a file outside of the package root is handled consistently. If the
333 * default behavior of Bazel was changed from {@code
334 * ExternalFileAction#DEPEND_ON_EXTERNAL_PKG_FOR_EXTERNAL_REPO_PATHS} to {@code
335 * ExternalFileAction#ASSUME_NON_EXISTENT_AND_IMMUTABLE_FOR_EXTERNAL_PATHS} then foo/link.sh
336 * should no longer appear in the srcs of //foo:foo. However, either way the srcs should be the
337 * same independent of the evaluation being incremental or clean.
338 */
339 @Test
340 public void testGlobWithExternalSymlink() throws Exception {
341 scratch.file(
342 "foo/BUILD",
343 "sh_library(name = 'foo', srcs = glob(['*.sh']))",
344 "sh_library(name = 'bar', srcs = glob(['link.sh']))",
345 "sh_library(name = 'baz', srcs = glob(['subdir_link/*.txt']))");
346 scratch.file("foo/ordinary.sh");
347 Path externalTarget = scratch.file("../ops/target.txt");
348 FileSystemUtils.ensureSymbolicLink(scratch.resolve("foo/link.sh"), externalTarget);
349 FileSystemUtils.ensureSymbolicLink(
350 scratch.resolve("foo/subdir_link"), externalTarget.getParentDirectory());
351 preparePackageLoading(rootDirectory);
352 SkyKey fooKey = PackageValue.key(PackageIdentifier.parse("@//foo"));
353 PackageValue fooValue = validPackage(fooKey);
354 assertSrcs(fooValue, "foo", "//foo:link.sh", "//foo:ordinary.sh");
355 assertSrcs(fooValue, "bar", "//foo:link.sh");
356 assertSrcs(fooValue, "baz", "//foo:subdir_link/target.txt");
357 scratch.overwriteFile(
358 "foo/BUILD",
359 "sh_library(name = 'foo', srcs = glob(['*.sh'])) #comment",
360 "sh_library(name = 'bar', srcs = glob(['link.sh']))",
361 "sh_library(name = 'baz', srcs = glob(['subdir_link/*.txt']))");
362 getSkyframeExecutor()
363 .invalidateFilesUnderPathForTesting(
364 reporter,
nharmatab4060b62017-04-04 17:11:39 +0000365 ModifiedFileSet.builder().modify(PathFragment.create("foo/BUILD")).build(),
tomluee6a6862018-01-17 14:36:26 -0800366 Root.fromPath(rootDirectory));
Janak Ramakrishnanffbc28a2017-02-13 22:51:45 +0000367 PackageValue fooValue2 = validPackage(fooKey);
368 assertThat(fooValue2).isNotEqualTo(fooValue);
369 assertSrcs(fooValue2, "foo", "//foo:link.sh", "//foo:ordinary.sh");
370 assertSrcs(fooValue2, "bar", "//foo:link.sh");
371 assertSrcs(fooValue2, "baz", "//foo:subdir_link/target.txt");
372 }
373
374 private static void assertSrcs(PackageValue value, String targetName, String... expected)
375 throws NoSuchTargetException {
376 List<Label> expectedLabels = new ArrayList<>();
377 for (String item : expected) {
378 expectedLabels.add(Label.parseAbsoluteUnchecked(item));
379 }
380 assertThat(getSrcs(value, targetName)).containsExactlyElementsIn(expectedLabels).inOrder();
381 }
382
383 @SuppressWarnings("unchecked")
384 private static Iterable<Label> getSrcs(PackageValue packageValue, String targetName)
385 throws NoSuchTargetException {
386 return (Iterable<Label>)
387 packageValue
388 .getPackage()
389 .getTarget(targetName)
390 .getAssociatedRule()
391 .getAttributeContainer()
392 .getAttr("srcs");
393 }
Florian Weikert92b22362015-12-03 10:17:18 +0000394 @Test
Janak Ramakrishnan4e2e4082017-01-06 06:28:45 +0000395 public void testOneNewElementInMultipleGlob() throws Exception {
396 scratch.file(
397 "foo/BUILD",
398 "sh_library(name = 'foo', srcs = glob(['*.sh']))",
399 "sh_library(name = 'bar', srcs = glob(['*.sh', '*.txt']))");
400 preparePackageLoading(rootDirectory);
401 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//foo"));
402 PackageValue value = validPackage(skyKey);
403 scratch.file("foo/irrelevent");
404 getSkyframeExecutor()
405 .invalidateFilesUnderPathForTesting(
406 reporter,
nharmatab4060b62017-04-04 17:11:39 +0000407 ModifiedFileSet.builder().modify(PathFragment.create("foo/irrelevant")).build(),
tomluee6a6862018-01-17 14:36:26 -0800408 Root.fromPath(rootDirectory));
Janak Ramakrishnan4e2e4082017-01-06 06:28:45 +0000409 assertThat(validPackage(skyKey)).isSameAs(value);
410 }
411
412 @Test
413 public void testNoNewElementInMultipleGlob() throws Exception {
414 scratch.file(
415 "foo/BUILD",
416 "sh_library(name = 'foo', srcs = glob(['*.sh', '*.txt']))",
417 "sh_library(name = 'bar', srcs = glob(['*.sh', '*.txt']))");
418 preparePackageLoading(rootDirectory);
419 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//foo"));
420 PackageValue value = validPackage(skyKey);
421 scratch.file("foo/irrelevent");
422 getSkyframeExecutor()
423 .invalidateFilesUnderPathForTesting(
424 reporter,
nharmatab4060b62017-04-04 17:11:39 +0000425 ModifiedFileSet.builder().modify(PathFragment.create("foo/irrelevant")).build(),
tomluee6a6862018-01-17 14:36:26 -0800426 Root.fromPath(rootDirectory));
Janak Ramakrishnan4e2e4082017-01-06 06:28:45 +0000427 assertThat(validPackage(skyKey)).isSameAs(value);
428 }
429
430 @Test
Kristina Chodorow335f0672015-11-16 23:19:13 +0000431 public void testTransitiveSkylarkDepsStoredInPackage() throws Exception {
432 scratch.file("foo/BUILD",
laurentlb5ddd8042017-11-30 12:03:31 -0800433 "load('//bar:ext.bzl', 'a')");
Kristina Chodorow335f0672015-11-16 23:19:13 +0000434 scratch.file("bar/BUILD");
435 scratch.file("bar/ext.bzl",
laurentlb5ddd8042017-11-30 12:03:31 -0800436 "load('//baz:ext.bzl', 'b')",
Kristina Chodorow335f0672015-11-16 23:19:13 +0000437 "a = b");
438 scratch.file("baz/BUILD");
439 scratch.file("baz/ext.bzl",
440 "b = 1");
441 scratch.file("qux/BUILD");
442 scratch.file("qux/ext.bzl",
443 "c = 1");
444
Ulf Adamsc73051c62016-03-23 09:18:13 +0000445 preparePackageLoading(rootDirectory);
Kristina Chodorow335f0672015-11-16 23:19:13 +0000446
Brian Silvermand7d6d622016-03-17 09:53:39 +0000447 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//foo"));
Kristina Chodorow335f0672015-11-16 23:19:13 +0000448 PackageValue value = validPackage(skyKey);
449 assertThat(value.getPackage().getSkylarkFileDependencies()).containsExactly(
450 Label.parseAbsolute("//bar:ext.bzl"), Label.parseAbsolute("//baz:ext.bzl"));
451
452 scratch.overwriteFile("bar/ext.bzl",
laurentlb5ddd8042017-11-30 12:03:31 -0800453 "load('//qux:ext.bzl', 'c')",
Kristina Chodorow335f0672015-11-16 23:19:13 +0000454 "a = c");
tomluee6a6862018-01-17 14:36:26 -0800455 getSkyframeExecutor()
456 .invalidateFilesUnderPathForTesting(
457 reporter,
458 ModifiedFileSet.builder().modify(PathFragment.create("bar/ext.bzl")).build(),
459 Root.fromPath(rootDirectory));
Kristina Chodorow335f0672015-11-16 23:19:13 +0000460
461 value = validPackage(skyKey);
462 assertThat(value.getPackage().getSkylarkFileDependencies()).containsExactly(
463 Label.parseAbsolute("//bar:ext.bzl"), Label.parseAbsolute("//qux:ext.bzl"));
464 }
465
Florian Weikert92b22362015-12-03 10:17:18 +0000466 @Test
Kristina Chodorow335f0672015-11-16 23:19:13 +0000467 public void testNonExistingSkylarkExtension() throws Exception {
468 reporter.removeHandler(failFastHandler);
469 scratch.file("test/skylark/BUILD",
laurentlb5ddd8042017-11-30 12:03:31 -0800470 "load('//test/skylark:bad_extension.bzl', 'some_symbol')",
Kristina Chodorow335f0672015-11-16 23:19:13 +0000471 "genrule(name = gr,",
472 " outs = ['out.txt'],",
473 " cmd = 'echo hello >@')");
474 invalidatePackages();
475
Brian Silvermand7d6d622016-03-17 09:53:39 +0000476 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//test/skylark"));
Kristina Chodorow335f0672015-11-16 23:19:13 +0000477 EvaluationResult<PackageValue> result = SkyframeExecutorTestUtils.evaluate(
478 getSkyframeExecutor(), skyKey, /*keepGoing=*/false, reporter);
lberkiaea56b32017-05-30 12:35:33 +0200479 assertThat(result.hasError()).isTrue();
Kristina Chodorow335f0672015-11-16 23:19:13 +0000480 ErrorInfo errorInfo = result.getError(skyKey);
John Field1ea7fc32015-12-22 19:37:19 +0000481 String expectedMsg = "error loading package 'test/skylark': "
482 + "Extension file not found. Unable to load file '//test/skylark:bad_extension.bzl': "
483 + "file doesn't exist or isn't a file";
Kristina Chodorow335f0672015-11-16 23:19:13 +0000484 assertThat(errorInfo.getException())
John Field1ea7fc32015-12-22 19:37:19 +0000485 .hasMessage(expectedMsg);
Kristina Chodorow335f0672015-11-16 23:19:13 +0000486 }
487
Florian Weikert92b22362015-12-03 10:17:18 +0000488 @Test
Kristina Chodorow335f0672015-11-16 23:19:13 +0000489 public void testNonExistingSkylarkExtensionFromExtension() throws Exception {
490 reporter.removeHandler(failFastHandler);
491 scratch.file("test/skylark/extension.bzl",
laurentlb5ddd8042017-11-30 12:03:31 -0800492 "load('//test/skylark:bad_extension.bzl', 'some_symbol')",
Kristina Chodorow335f0672015-11-16 23:19:13 +0000493 "a = 'a'");
494 scratch.file("test/skylark/BUILD",
laurentlb5ddd8042017-11-30 12:03:31 -0800495 "load('//test/skylark:extension.bzl', 'a')",
Kristina Chodorow335f0672015-11-16 23:19:13 +0000496 "genrule(name = gr,",
497 " outs = ['out.txt'],",
498 " cmd = 'echo hello >@')");
499 invalidatePackages();
500
Brian Silvermand7d6d622016-03-17 09:53:39 +0000501 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//test/skylark"));
Kristina Chodorow335f0672015-11-16 23:19:13 +0000502 EvaluationResult<PackageValue> result = SkyframeExecutorTestUtils.evaluate(
503 getSkyframeExecutor(), skyKey, /*keepGoing=*/false, reporter);
lberkiaea56b32017-05-30 12:35:33 +0200504 assertThat(result.hasError()).isTrue();
Kristina Chodorow335f0672015-11-16 23:19:13 +0000505 ErrorInfo errorInfo = result.getError(skyKey);
506 assertThat(errorInfo.getException())
507 .hasMessage("error loading package 'test/skylark': Extension file not found. "
508 + "Unable to load file '//test/skylark:bad_extension.bzl': "
509 + "file doesn't exist or isn't a file");
510 }
511
Florian Weikert92b22362015-12-03 10:17:18 +0000512 @Test
Kristina Chodorow335f0672015-11-16 23:19:13 +0000513 public void testSymlinkCycleWithSkylarkExtension() throws Exception {
514 reporter.removeHandler(failFastHandler);
515 Path extensionFilePath = scratch.resolve("/workspace/test/skylark/extension.bzl");
nharmatab4060b62017-04-04 17:11:39 +0000516 FileSystemUtils.ensureSymbolicLink(extensionFilePath, PathFragment.create("extension.bzl"));
Kristina Chodorow335f0672015-11-16 23:19:13 +0000517 scratch.file("test/skylark/BUILD",
laurentlb5ddd8042017-11-30 12:03:31 -0800518 "load('//test/skylark:extension.bzl', 'a')",
Kristina Chodorow335f0672015-11-16 23:19:13 +0000519 "genrule(name = gr,",
520 " outs = ['out.txt'],",
521 " cmd = 'echo hello >@')");
522 invalidatePackages();
523
Brian Silvermand7d6d622016-03-17 09:53:39 +0000524 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//test/skylark"));
Kristina Chodorow335f0672015-11-16 23:19:13 +0000525 EvaluationResult<PackageValue> result = SkyframeExecutorTestUtils.evaluate(
526 getSkyframeExecutor(), skyKey, /*keepGoing=*/false, reporter);
lberkiaea56b32017-05-30 12:35:33 +0200527 assertThat(result.hasError()).isTrue();
Kristina Chodorow335f0672015-11-16 23:19:13 +0000528 ErrorInfo errorInfo = result.getError(skyKey);
lberkiaea56b32017-05-30 12:35:33 +0200529 assertThat(errorInfo.getRootCauseOfException()).isEqualTo(skyKey);
Kristina Chodorow335f0672015-11-16 23:19:13 +0000530 assertThat(errorInfo.getException())
531 .hasMessage(
532 "error loading package 'test/skylark': Encountered error while reading extension "
533 + "file 'test/skylark/extension.bzl': Symlink cycle");
534 }
535
Florian Weikert92b22362015-12-03 10:17:18 +0000536 @Test
Kristina Chodorow335f0672015-11-16 23:19:13 +0000537 public void testIOErrorLookingForSubpackageForLabelIsHandled() throws Exception {
538 reporter.removeHandler(failFastHandler);
539 scratch.file("foo/BUILD",
540 "sh_library(name = 'foo', srcs = ['bar/baz.sh'])");
541 Path barBuildFile = scratch.file("foo/bar/BUILD");
aehligc801c392017-12-19 07:12:25 -0800542 fs.stubStatError(barBuildFile, new IOException("nope"));
Brian Silvermand7d6d622016-03-17 09:53:39 +0000543 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//foo"));
Kristina Chodorow335f0672015-11-16 23:19:13 +0000544 EvaluationResult<PackageValue> result = SkyframeExecutorTestUtils.evaluate(
545 getSkyframeExecutor(), skyKey, /*keepGoing=*/false, reporter);
lberkiaea56b32017-05-30 12:35:33 +0200546 assertThat(result.hasError()).isTrue();
Kristina Chodorow335f0672015-11-16 23:19:13 +0000547 assertContainsEvent("nope");
548 }
549
Florian Weikert92b22362015-12-03 10:17:18 +0000550 @Test
Kristina Chodorow335f0672015-11-16 23:19:13 +0000551 public void testLoadRelativePath() throws Exception {
laurentlb5ddd8042017-11-30 12:03:31 -0800552 scratch.file("pkg/BUILD", "load(':ext.bzl', 'a')");
Kristina Chodorow335f0672015-11-16 23:19:13 +0000553 scratch.file("pkg/ext.bzl", "a = 1");
Brian Silvermand7d6d622016-03-17 09:53:39 +0000554 validPackage(PackageValue.key(PackageIdentifier.parse("@//pkg")));
Kristina Chodorow335f0672015-11-16 23:19:13 +0000555 }
556
Florian Weikert92b22362015-12-03 10:17:18 +0000557 @Test
Kristina Chodorow335f0672015-11-16 23:19:13 +0000558 public void testLoadAbsolutePath() throws Exception {
559 scratch.file("pkg1/BUILD");
560 scratch.file("pkg2/BUILD",
laurentlb5ddd8042017-11-30 12:03:31 -0800561 "load('//pkg1:ext.bzl', 'a')");
Kristina Chodorow335f0672015-11-16 23:19:13 +0000562 scratch.file("pkg1/ext.bzl", "a = 1");
Brian Silvermand7d6d622016-03-17 09:53:39 +0000563 validPackage(PackageValue.key(PackageIdentifier.parse("@//pkg2")));
Kristina Chodorow335f0672015-11-16 23:19:13 +0000564 }
565
Florian Weikert92b22362015-12-03 10:17:18 +0000566 @Test
Kristina Chodorow335f0672015-11-16 23:19:13 +0000567 public void testBadWorkspaceFile() throws Exception {
568 Path workspacePath = scratch.overwriteFile("WORKSPACE", "junk");
Brian Silvermand7d6d622016-03-17 09:53:39 +0000569 SkyKey skyKey = PackageValue.key(PackageIdentifier.createInMainRepo("external"));
Kristina Chodorow335f0672015-11-16 23:19:13 +0000570 getSkyframeExecutor()
571 .invalidate(
572 Predicates.equalTo(
Janak Ramakrishnan4e2e4082017-01-06 06:28:45 +0000573 com.google.devtools.build.lib.skyframe.FileStateValue.key(
Kristina Chodorow335f0672015-11-16 23:19:13 +0000574 RootedPath.toRootedPath(
tomluee6a6862018-01-17 14:36:26 -0800575 Root.fromPath(workspacePath.getParentDirectory()),
nharmatab4060b62017-04-04 17:11:39 +0000576 PathFragment.create(workspacePath.getBaseName())))));
Kristina Chodorow335f0672015-11-16 23:19:13 +0000577
578 reporter.removeHandler(failFastHandler);
579 EvaluationResult<PackageValue> result =
580 SkyframeExecutorTestUtils.evaluate(
581 getSkyframeExecutor(), skyKey, /*keepGoing=*/ false, reporter);
lberkiaea56b32017-05-30 12:35:33 +0200582 assertThat(result.hasError()).isFalse();
583 assertThat(result.get(skyKey).getPackage().containsErrors()).isTrue();
Kristina Chodorow335f0672015-11-16 23:19:13 +0000584 }
585
Nathan Harmata2022ad82016-02-22 23:04:14 +0000586 // Regression test for the two ugly consequences of a bug where GlobFunction incorrectly matched
587 // dangling symlinks.
588 @Test
589 public void testIncrementalSkyframeHybridGlobbingOnDanglingSymlink() throws Exception {
590 Path packageDirPath = scratch.file("foo/BUILD",
591 "exports_files(glob(['*.txt']))").getParentDirectory();
592 scratch.file("foo/existing.txt");
593 FileSystemUtils.ensureSymbolicLink(packageDirPath.getChild("dangling.txt"), "nope");
594
Ulf Adamsc73051c62016-03-23 09:18:13 +0000595 preparePackageLoading(rootDirectory);
Nathan Harmata2022ad82016-02-22 23:04:14 +0000596
Brian Silvermand7d6d622016-03-17 09:53:39 +0000597 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//foo"));
Nathan Harmata2022ad82016-02-22 23:04:14 +0000598 PackageValue value = validPackage(skyKey);
lberkiaea56b32017-05-30 12:35:33 +0200599 assertThat(value.getPackage().containsErrors()).isFalse();
Nathan Harmata2022ad82016-02-22 23:04:14 +0000600 assertThat(value.getPackage().getTarget("existing.txt").getName()).isEqualTo("existing.txt");
601 try {
602 value.getPackage().getTarget("dangling.txt");
603 fail();
604 } catch (NoSuchTargetException expected) {
605 }
606
607 scratch.overwriteFile("foo/BUILD",
Laurent Le Brunb639ca82017-01-17 11:18:23 +0000608 "exports_files(glob(['*.txt']))",
Nathan Harmata2022ad82016-02-22 23:04:14 +0000609 "#some-irrelevant-comment");
610
tomluee6a6862018-01-17 14:36:26 -0800611 getSkyframeExecutor()
612 .invalidateFilesUnderPathForTesting(
613 reporter,
614 ModifiedFileSet.builder().modify(PathFragment.create("foo/BUILD")).build(),
615 Root.fromPath(rootDirectory));
Nathan Harmata2022ad82016-02-22 23:04:14 +0000616
617 value = validPackage(skyKey);
lberkiaea56b32017-05-30 12:35:33 +0200618 assertThat(value.getPackage().containsErrors()).isFalse();
Nathan Harmata2022ad82016-02-22 23:04:14 +0000619 assertThat(value.getPackage().getTarget("existing.txt").getName()).isEqualTo("existing.txt");
620 try {
621 value.getPackage().getTarget("dangling.txt");
622 fail();
623 } catch (NoSuchTargetException expected) {
624 // One consequence of the bug was that dangling symlinks were matched by globs evaluated by
625 // Skyframe globbing, meaning there would incorrectly be corresponding targets in packages
626 // that had skyframe cache hits during skyframe hybrid globbing.
627 }
628
629 scratch.file("foo/nope");
tomluee6a6862018-01-17 14:36:26 -0800630 getSkyframeExecutor()
631 .invalidateFilesUnderPathForTesting(
632 reporter,
633 ModifiedFileSet.builder().modify(PathFragment.create("foo/nope")).build(),
634 Root.fromPath(rootDirectory));
Nathan Harmata2022ad82016-02-22 23:04:14 +0000635
636 PackageValue newValue = validPackage(skyKey);
lberkiaea56b32017-05-30 12:35:33 +0200637 assertThat(newValue.getPackage().containsErrors()).isFalse();
Nathan Harmata2022ad82016-02-22 23:04:14 +0000638 assertThat(newValue.getPackage().getTarget("existing.txt").getName()).isEqualTo("existing.txt");
639 // Another consequence of the bug is that change pruning would incorrectly cut off changes that
640 // caused a dangling symlink potentially matched by a glob to come into existence.
641 assertThat(newValue.getPackage().getTarget("dangling.txt").getName()).isEqualTo("dangling.txt");
642 assertThat(newValue.getPackage()).isNotSameAs(value.getPackage());
643 }
644
Nathan Harmata86c319e2016-02-25 01:12:22 +0000645 // Regression test for Skyframe globbing incorrectly matching the package's directory path on
646 // 'glob(['**'], exclude_directories = 0)'. We test for this directly by triggering
647 // hybrid globbing (gives coverage for both legacy globbing and skyframe globbing).
648 @Test
649 public void testRecursiveGlobNeverMatchesPackageDirectory() throws Exception {
650 scratch.file("foo/BUILD",
651 "[sh_library(name = x + '-matched') for x in glob(['**'], exclude_directories = 0)]");
652 scratch.file("foo/bar");
653
Ulf Adamsc73051c62016-03-23 09:18:13 +0000654 preparePackageLoading(rootDirectory);
Nathan Harmata86c319e2016-02-25 01:12:22 +0000655
Brian Silvermand7d6d622016-03-17 09:53:39 +0000656 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//foo"));
Nathan Harmata86c319e2016-02-25 01:12:22 +0000657 PackageValue value = validPackage(skyKey);
lberkiaea56b32017-05-30 12:35:33 +0200658 assertThat(value.getPackage().containsErrors()).isFalse();
Nathan Harmata86c319e2016-02-25 01:12:22 +0000659 assertThat(value.getPackage().getTarget("bar-matched").getName()).isEqualTo("bar-matched");
660 try {
661 value.getPackage().getTarget("-matched");
662 fail();
663 } catch (NoSuchTargetException expected) {
664 }
665
666 scratch.overwriteFile("foo/BUILD",
667 "[sh_library(name = x + '-matched') for x in glob(['**'], exclude_directories = 0)]",
668 "#some-irrelevant-comment");
tomluee6a6862018-01-17 14:36:26 -0800669 getSkyframeExecutor()
670 .invalidateFilesUnderPathForTesting(
671 reporter,
672 ModifiedFileSet.builder().modify(PathFragment.create("foo/BUILD")).build(),
673 Root.fromPath(rootDirectory));
Nathan Harmata86c319e2016-02-25 01:12:22 +0000674
675 value = validPackage(skyKey);
lberkiaea56b32017-05-30 12:35:33 +0200676 assertThat(value.getPackage().containsErrors()).isFalse();
Nathan Harmata86c319e2016-02-25 01:12:22 +0000677 assertThat(value.getPackage().getTarget("bar-matched").getName()).isEqualTo("bar-matched");
678 try {
679 value.getPackage().getTarget("-matched");
680 fail();
681 } catch (NoSuchTargetException expected) {
682 }
683 }
684
nharmataff688bf2017-06-07 17:03:52 -0400685 @Test
686 public void testPackageLoadingErrorOnIOExceptionReadingBuildFile() throws Exception {
687 Path fooBuildFilePath = scratch.file("foo/BUILD");
688 IOException exn = new IOException("nope");
aehligc801c392017-12-19 07:12:25 -0800689 fs.throwExceptionOnGetInputStream(fooBuildFilePath, exn);
nharmataff688bf2017-06-07 17:03:52 -0400690
691 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//foo"));
692 EvaluationResult<PackageValue> result = SkyframeExecutorTestUtils.evaluate(
693 getSkyframeExecutor(), skyKey, /*keepGoing=*/false, reporter);
694 assertThat(result.hasError()).isTrue();
695 ErrorInfo errorInfo = result.getError(skyKey);
696 String errorMessage = errorInfo.getException().getMessage();
697 assertThat(errorMessage).contains("nope");
698 assertThat(errorInfo.getException()).isInstanceOf(NoSuchPackageException.class);
nharmata351efff2018-03-30 15:04:38 -0700699 assertThat(errorInfo.getException()).hasCauseThat().isInstanceOf(IOException.class);
nharmataff688bf2017-06-07 17:03:52 -0400700 }
701
nharmatabea67e92017-06-16 00:26:27 +0200702 @Test
703 public void testPackageLoadingErrorOnIOExceptionReadingBzlFile() throws Exception {
704 scratch.file("foo/BUILD", "load('//foo:bzl.bzl', 'x')");
705 Path fooBzlFilePath = scratch.file("foo/bzl.bzl");
706 IOException exn = new IOException("nope");
aehligc801c392017-12-19 07:12:25 -0800707 fs.throwExceptionOnGetInputStream(fooBzlFilePath, exn);
nharmatabea67e92017-06-16 00:26:27 +0200708
709 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//foo"));
710 EvaluationResult<PackageValue> result = SkyframeExecutorTestUtils.evaluate(
711 getSkyframeExecutor(), skyKey, /*keepGoing=*/false, reporter);
712 assertThat(result.hasError()).isTrue();
713 ErrorInfo errorInfo = result.getError(skyKey);
714 String errorMessage = errorInfo.getException().getMessage();
715 assertThat(errorMessage).contains("nope");
716 assertThat(errorInfo.getException()).isInstanceOf(NoSuchPackageException.class);
nharmata351efff2018-03-30 15:04:38 -0700717 assertThat(errorInfo.getException()).hasCauseThat().isInstanceOf(IOException.class);
nharmatabea67e92017-06-16 00:26:27 +0200718 }
719
Kristina Chodorow335f0672015-11-16 23:19:13 +0000720 private static class CustomInMemoryFs extends InMemoryFileSystem {
Googlerc804c662016-12-01 16:53:28 +0000721 private abstract static class FileStatusOrException {
722 abstract FileStatus get() throws IOException;
723
724 private static class ExceptionImpl extends FileStatusOrException {
725 private final IOException exn;
726
727 private ExceptionImpl(IOException exn) {
728 this.exn = exn;
729 }
730
731 @Override
732 FileStatus get() throws IOException {
733 throw exn;
734 }
735 }
736
737 private static class FileStatusImpl extends FileStatusOrException {
738
739 @Nullable
740 private final FileStatus fileStatus;
741
742 private FileStatusImpl(@Nullable FileStatus fileStatus) {
743 this.fileStatus = fileStatus;
744 }
745
746 @Override
747 @Nullable
748 FileStatus get() {
749 return fileStatus;
750 }
751 }
752 }
753
aehligc801c392017-12-19 07:12:25 -0800754 private final Map<Path, FileStatusOrException> stubbedStats = Maps.newHashMap();
755 private final Set<Path> makeUnreadableAfterReaddir = Sets.newHashSet();
756 private final Map<Path, IOException> pathsToErrorOnGetInputStream = Maps.newHashMap();
Kristina Chodorow335f0672015-11-16 23:19:13 +0000757
758 public CustomInMemoryFs(ManualClock manualClock) {
759 super(manualClock);
760 }
761
aehligc801c392017-12-19 07:12:25 -0800762 public void stubStat(Path path, @Nullable FileStatus stubbedResult) {
Googlerc804c662016-12-01 16:53:28 +0000763 stubbedStats.put(path, new FileStatusOrException.FileStatusImpl(stubbedResult));
Kristina Chodorow335f0672015-11-16 23:19:13 +0000764 }
765
aehligc801c392017-12-19 07:12:25 -0800766 public void stubStatError(Path path, IOException stubbedResult) {
Googlerc804c662016-12-01 16:53:28 +0000767 stubbedStats.put(path, new FileStatusOrException.ExceptionImpl(stubbedResult));
Kristina Chodorow335f0672015-11-16 23:19:13 +0000768 }
769
770 @Override
aehligc801c392017-12-19 07:12:25 -0800771 public FileStatus stat(Path path, boolean followSymlinks) throws IOException {
Googlerc804c662016-12-01 16:53:28 +0000772 if (stubbedStats.containsKey(path)) {
773 return stubbedStats.get(path).get();
Kristina Chodorow335f0672015-11-16 23:19:13 +0000774 }
Googlerc804c662016-12-01 16:53:28 +0000775 return super.stat(path, followSymlinks);
Kristina Chodorow335f0672015-11-16 23:19:13 +0000776 }
777
aehligc801c392017-12-19 07:12:25 -0800778 public void scheduleMakeUnreadableAfterReaddir(Path path) {
Googlerc804c662016-12-01 16:53:28 +0000779 makeUnreadableAfterReaddir.add(path);
Kristina Chodorow335f0672015-11-16 23:19:13 +0000780 }
781
782 @Override
aehligc801c392017-12-19 07:12:25 -0800783 public Collection<Dirent> readdir(Path path, boolean followSymlinks) throws IOException {
Kristina Chodorow335f0672015-11-16 23:19:13 +0000784 Collection<Dirent> result = super.readdir(path, followSymlinks);
Googlerc804c662016-12-01 16:53:28 +0000785 if (makeUnreadableAfterReaddir.contains(path)) {
aehligc801c392017-12-19 07:12:25 -0800786 path.setReadable(false);
Kristina Chodorow335f0672015-11-16 23:19:13 +0000787 }
788 return result;
789 }
nharmataff688bf2017-06-07 17:03:52 -0400790
aehligc801c392017-12-19 07:12:25 -0800791 public void throwExceptionOnGetInputStream(Path path, IOException exn) {
nharmataff688bf2017-06-07 17:03:52 -0400792 pathsToErrorOnGetInputStream.put(path, exn);
793 }
794
795 @Override
aehligc801c392017-12-19 07:12:25 -0800796 protected InputStream getInputStream(Path path) throws IOException {
nharmataff688bf2017-06-07 17:03:52 -0400797 IOException exnToThrow = pathsToErrorOnGetInputStream.get(path);
798 if (exnToThrow != null) {
799 throw exnToThrow;
800 }
801 return super.getInputStream(path);
802 }
Kristina Chodorow335f0672015-11-16 23:19:13 +0000803 }
Kristina Chodorow335f0672015-11-16 23:19:13 +0000804}