blob: 1a3dcdd50a9020644b3b766f4c015bd4bb8102fe [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;
shahan602cc852018-06-06 20:09:57 -070025import com.google.devtools.build.lib.actions.FileStateValue;
Florian Weikertcca703a2015-12-07 09:56:38 +000026import com.google.devtools.build.lib.analysis.util.BuildViewTestCase;
philwo3bcb9f62017-09-06 12:52:21 +020027import com.google.devtools.build.lib.clock.BlazeClock;
Kristina Chodorow335f0672015-11-16 23:19:13 +000028import com.google.devtools.build.lib.cmdline.Label;
29import com.google.devtools.build.lib.cmdline.PackageIdentifier;
30import com.google.devtools.build.lib.packages.ConstantRuleVisibility;
nharmataff688bf2017-06-07 17:03:52 -040031import com.google.devtools.build.lib.packages.NoSuchPackageException;
Nathan Harmata2022ad82016-02-22 23:04:14 +000032import com.google.devtools.build.lib.packages.NoSuchTargetException;
brandjon674ab862017-10-06 23:17:33 +020033import com.google.devtools.build.lib.packages.SkylarkSemanticsOptions;
Janak Ramakrishnan326c6982016-09-27 14:58:26 +000034import com.google.devtools.build.lib.pkgcache.PackageCacheOptions;
Kristina Chodorow335f0672015-11-16 23:19:13 +000035import com.google.devtools.build.lib.pkgcache.PathPackageLocator;
36import com.google.devtools.build.lib.skyframe.util.SkyframeExecutorTestUtils;
37import com.google.devtools.build.lib.testutil.ManualClock;
Ulf Adamsc73051c62016-03-23 09:18:13 +000038import com.google.devtools.build.lib.util.io.TimestampGranularityMonitor;
Kristina Chodorow335f0672015-11-16 23:19:13 +000039import com.google.devtools.build.lib.vfs.Dirent;
40import com.google.devtools.build.lib.vfs.FileStatus;
41import com.google.devtools.build.lib.vfs.FileSystem;
42import com.google.devtools.build.lib.vfs.FileSystemUtils;
43import com.google.devtools.build.lib.vfs.ModifiedFileSet;
44import com.google.devtools.build.lib.vfs.Path;
45import com.google.devtools.build.lib.vfs.PathFragment;
tomluee6a6862018-01-17 14:36:26 -080046import com.google.devtools.build.lib.vfs.Root;
Kristina Chodorow335f0672015-11-16 23:19:13 +000047import com.google.devtools.build.lib.vfs.RootedPath;
48import com.google.devtools.build.lib.vfs.inmemoryfs.InMemoryFileSystem;
49import com.google.devtools.build.skyframe.ErrorInfo;
50import com.google.devtools.build.skyframe.EvaluationResult;
51import com.google.devtools.build.skyframe.RecordingDifferencer;
52import com.google.devtools.build.skyframe.SkyKey;
53import com.google.devtools.build.skyframe.SkyValue;
Janak Ramakrishnan326c6982016-09-27 14:58:26 +000054import com.google.devtools.common.options.Options;
Kristina Chodorow335f0672015-11-16 23:19:13 +000055import java.io.IOException;
nharmataff688bf2017-06-07 17:03:52 -040056import java.io.InputStream;
Janak Ramakrishnanffbc28a2017-02-13 22:51:45 +000057import java.util.ArrayList;
tomluee6a6862018-01-17 14:36:26 -080058import java.util.Arrays;
Kristina Chodorow335f0672015-11-16 23:19:13 +000059import java.util.Collection;
Janak Ramakrishnanffbc28a2017-02-13 22:51:45 +000060import java.util.List;
Kristina Chodorow335f0672015-11-16 23:19:13 +000061import java.util.Map;
Googlerc804c662016-12-01 16:53:28 +000062import java.util.Set;
Kristina Chodorow335f0672015-11-16 23:19:13 +000063import java.util.UUID;
Kristina Chodorow335f0672015-11-16 23:19:13 +000064import javax.annotation.Nullable;
John Cater94695912016-08-03 12:09:39 +000065import org.junit.Test;
66import org.junit.runner.RunWith;
67import org.junit.runners.JUnit4;
Kristina Chodorow335f0672015-11-16 23:19:13 +000068
69/**
70 * Unit tests of specific functionality of PackageFunction. Note that it's already tested
71 * indirectly in several other places.
72 */
Florian Weikert92b22362015-12-03 10:17:18 +000073@RunWith(JUnit4.class)
Florian Weikertcca703a2015-12-07 09:56:38 +000074public class PackageFunctionTest extends BuildViewTestCase {
Kristina Chodorow335f0672015-11-16 23:19:13 +000075
76 private CustomInMemoryFs fs = new CustomInMemoryFs(new ManualClock());
77
Ulf Adamsc73051c62016-03-23 09:18:13 +000078 private void preparePackageLoading(Path... roots) {
Janak Ramakrishnan326c6982016-09-27 14:58:26 +000079 PackageCacheOptions packageCacheOptions = Options.getDefaults(PackageCacheOptions.class);
80 packageCacheOptions.defaultVisibility = ConstantRuleVisibility.PUBLIC;
81 packageCacheOptions.showLoadingProgress = true;
82 packageCacheOptions.globbingThreads = 7;
Klaus Aehlig6f33a1c2016-09-13 16:46:10 +000083 getSkyframeExecutor()
84 .preparePackageLoading(
John Catere0d1d0e2017-11-28 20:47:41 -080085 new PathPackageLocator(
86 outputBase,
tomluee6a6862018-01-17 14:36:26 -080087 Arrays.stream(roots).map(Root::fromPath).collect(ImmutableList.toImmutableList()),
John Catere0d1d0e2017-11-28 20:47:41 -080088 BazelSkyframeExecutorConstants.BUILD_FILES_BY_PRIORITY),
Janak Ramakrishnan326c6982016-09-27 14:58:26 +000089 packageCacheOptions,
brandjon7dc34162017-04-27 18:34:33 +020090 Options.getDefaults(SkylarkSemanticsOptions.class),
laurentlb99958b82018-08-20 06:24:23 -070091 "",
Klaus Aehlig6f33a1c2016-09-13 16:46:10 +000092 UUID.randomUUID(),
93 ImmutableMap.<String, String>of(),
94 new TimestampGranularityMonitor(BlazeClock.instance()));
juliexxia651797f2018-08-01 11:45:13 -070095 skyframeExecutor.setActionEnv(ImmutableMap.<String, String>of());
Ulf Adamsc73051c62016-03-23 09:18:13 +000096 }
97
Kristina Chodorow335f0672015-11-16 23:19:13 +000098 @Override
Kristina Chodorow335f0672015-11-16 23:19:13 +000099 protected FileSystem createFileSystem() {
100 return fs;
101 }
102
103 private PackageValue validPackage(SkyKey skyKey) throws InterruptedException {
104 EvaluationResult<PackageValue> result = SkyframeExecutorTestUtils.evaluate(
105 getSkyframeExecutor(), skyKey, /*keepGoing=*/false, reporter);
106 if (result.hasError()) {
107 fail(result.getError(skyKey).getException().getMessage());
108 }
109 PackageValue value = result.get(skyKey);
lberkiaea56b32017-05-30 12:35:33 +0200110 assertThat(value.getPackage().containsErrors()).isFalse();
Kristina Chodorow335f0672015-11-16 23:19:13 +0000111 return value;
112 }
113
Florian Weikert92b22362015-12-03 10:17:18 +0000114 @Test
John Cater94695912016-08-03 12:09:39 +0000115 public void testValidPackage() throws Exception {
116 scratch.file("pkg/BUILD");
117 validPackage(PackageValue.key(PackageIdentifier.parse("@//pkg")));
118 }
119
120 @Test
Kristina Chodorow335f0672015-11-16 23:19:13 +0000121 public void testPropagatesFilesystemInconsistencies() throws Exception {
122 reporter.removeHandler(failFastHandler);
123 RecordingDifferencer differencer = getSkyframeExecutor().getDifferencerForTesting();
tomluee6a6862018-01-17 14:36:26 -0800124 Root pkgRoot = getSkyframeExecutor().getPathEntries().get(0);
Kristina Chodorow335f0672015-11-16 23:19:13 +0000125 Path fooBuildFile = scratch.file("foo/BUILD");
126 Path fooDir = fooBuildFile.getParentDirectory();
127
neerajen89188eb2018-07-19 13:03:43 -0700128 // Our custom filesystem says that fooDir is neither a file nor directory nor symlink
129 FileStatus inconsistentFileStatus = new FileStatus() {
Kristina Chodorow335f0672015-11-16 23:19:13 +0000130 @Override
131 public boolean isFile() {
neerajen89188eb2018-07-19 13:03:43 -0700132 return false;
Kristina Chodorow335f0672015-11-16 23:19:13 +0000133 }
134
135 @Override
136 public boolean isDirectory() {
137 return false;
138 }
139
140 @Override
141 public boolean isSymbolicLink() {
142 return false;
143 }
144
145 @Override
146 public boolean isSpecialFile() {
147 return false;
148 }
149
150 @Override
151 public long getSize() throws IOException {
152 return 0;
153 }
154
155 @Override
156 public long getLastModifiedTime() throws IOException {
157 return 0;
158 }
159
160 @Override
161 public long getLastChangeTime() throws IOException {
162 return 0;
163 }
164
165 @Override
166 public long getNodeId() throws IOException {
167 return 0;
168 }
169 };
neerajen89188eb2018-07-19 13:03:43 -0700170
171 fs.stubStat(fooBuildFile, inconsistentFileStatus);
Kristina Chodorow335f0672015-11-16 23:19:13 +0000172 RootedPath pkgRootedPath = RootedPath.toRootedPath(pkgRoot, fooDir);
Ulf Adamsc73051c62016-03-23 09:18:13 +0000173 SkyValue fooDirValue = FileStateValue.create(pkgRootedPath, tsgm);
Kristina Chodorow335f0672015-11-16 23:19:13 +0000174 differencer.inject(ImmutableMap.of(FileStateValue.key(pkgRootedPath), fooDirValue));
Brian Silvermand7d6d622016-03-17 09:53:39 +0000175 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//foo"));
neerajen89188eb2018-07-19 13:03:43 -0700176 String expectedMessage = "according to stat, existing path /workspace/foo/BUILD is neither"
177 + " a file nor directory nor symlink.";
Kristina Chodorow335f0672015-11-16 23:19:13 +0000178 EvaluationResult<PackageValue> result = SkyframeExecutorTestUtils.evaluate(
179 getSkyframeExecutor(), skyKey, /*keepGoing=*/false, reporter);
lberkiaea56b32017-05-30 12:35:33 +0200180 assertThat(result.hasError()).isTrue();
Kristina Chodorow335f0672015-11-16 23:19:13 +0000181 ErrorInfo errorInfo = result.getError(skyKey);
182 String errorMessage = errorInfo.getException().getMessage();
183 assertThat(errorMessage).contains("Inconsistent filesystem operations");
184 assertThat(errorMessage).contains(expectedMessage);
185 }
186
Florian Weikert92b22362015-12-03 10:17:18 +0000187 @Test
Kristina Chodorow335f0672015-11-16 23:19:13 +0000188 public void testPropagatesFilesystemInconsistencies_Globbing() throws Exception {
189 reporter.removeHandler(failFastHandler);
190 RecordingDifferencer differencer = getSkyframeExecutor().getDifferencerForTesting();
tomluee6a6862018-01-17 14:36:26 -0800191 Root pkgRoot = getSkyframeExecutor().getPathEntries().get(0);
Kristina Chodorow335f0672015-11-16 23:19:13 +0000192 scratch.file("foo/BUILD",
193 "subinclude('//a:a')",
194 "sh_library(name = 'foo', srcs = glob(['bar/**/baz.sh']))");
195 scratch.file("a/BUILD");
196 scratch.file("a/a");
197 Path bazFile = scratch.file("foo/bar/baz/baz.sh");
198 Path bazDir = bazFile.getParentDirectory();
199 Path barDir = bazDir.getParentDirectory();
200
Kristina Chodorow335f0672015-11-16 23:19:13 +0000201 // Our custom filesystem says "foo/bar/baz" does not exist but it also says that "foo/bar"
202 // has a child directory "baz".
aehligc801c392017-12-19 07:12:25 -0800203 fs.stubStat(bazDir, null);
Kristina Chodorow335f0672015-11-16 23:19:13 +0000204 RootedPath barDirRootedPath = RootedPath.toRootedPath(pkgRoot, barDir);
janakre54491e2018-07-11 16:29:13 -0700205 differencer.inject(
206 ImmutableMap.of(
207 DirectoryListingStateValue.key(barDirRootedPath),
208 DirectoryListingStateValue.create(
209 ImmutableList.of(new Dirent("baz", Dirent.Type.DIRECTORY)))));
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),
laurentlb99958b82018-08-20 06:24:23 -0700323 "",
Klaus Aehlig6f33a1c2016-09-13 16:46:10 +0000324 UUID.randomUUID(),
Klaus Aehlig03b9cfd2016-09-14 13:14:39 +0000325 ImmutableMap.<String, String>of(),
Klaus Aehlig6f33a1c2016-09-13 16:46:10 +0000326 tsgm);
juliexxia651797f2018-08-01 11:45:13 -0700327 getSkyframeExecutor().setActionEnv(ImmutableMap.<String, String>of());
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);
dannark90e2b4b2018-06-27 13:35:04 -0700449 assertThat(value.getPackage().getSkylarkFileDependencies())
450 .containsExactly(
451 Label.parseAbsolute("//bar:ext.bzl", ImmutableMap.of()),
452 Label.parseAbsolute("//baz:ext.bzl", ImmutableMap.of()));
Kristina Chodorow335f0672015-11-16 23:19:13 +0000453
454 scratch.overwriteFile("bar/ext.bzl",
laurentlb5ddd8042017-11-30 12:03:31 -0800455 "load('//qux:ext.bzl', 'c')",
Kristina Chodorow335f0672015-11-16 23:19:13 +0000456 "a = c");
tomluee6a6862018-01-17 14:36:26 -0800457 getSkyframeExecutor()
458 .invalidateFilesUnderPathForTesting(
459 reporter,
460 ModifiedFileSet.builder().modify(PathFragment.create("bar/ext.bzl")).build(),
461 Root.fromPath(rootDirectory));
Kristina Chodorow335f0672015-11-16 23:19:13 +0000462
463 value = validPackage(skyKey);
dannark90e2b4b2018-06-27 13:35:04 -0700464 assertThat(value.getPackage().getSkylarkFileDependencies())
465 .containsExactly(
466 Label.parseAbsolute("//bar:ext.bzl", ImmutableMap.of()),
467 Label.parseAbsolute("//qux:ext.bzl", ImmutableMap.of()));
Kristina Chodorow335f0672015-11-16 23:19:13 +0000468 }
469
Florian Weikert92b22362015-12-03 10:17:18 +0000470 @Test
Kristina Chodorow335f0672015-11-16 23:19:13 +0000471 public void testNonExistingSkylarkExtension() throws Exception {
472 reporter.removeHandler(failFastHandler);
473 scratch.file("test/skylark/BUILD",
laurentlb5ddd8042017-11-30 12:03:31 -0800474 "load('//test/skylark:bad_extension.bzl', 'some_symbol')",
Kristina Chodorow335f0672015-11-16 23:19:13 +0000475 "genrule(name = gr,",
476 " outs = ['out.txt'],",
477 " cmd = 'echo hello >@')");
478 invalidatePackages();
479
Brian Silvermand7d6d622016-03-17 09:53:39 +0000480 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//test/skylark"));
Kristina Chodorow335f0672015-11-16 23:19:13 +0000481 EvaluationResult<PackageValue> result = SkyframeExecutorTestUtils.evaluate(
482 getSkyframeExecutor(), skyKey, /*keepGoing=*/false, reporter);
lberkiaea56b32017-05-30 12:35:33 +0200483 assertThat(result.hasError()).isTrue();
Kristina Chodorow335f0672015-11-16 23:19:13 +0000484 ErrorInfo errorInfo = result.getError(skyKey);
John Field1ea7fc32015-12-22 19:37:19 +0000485 String expectedMsg = "error loading package 'test/skylark': "
486 + "Extension file not found. Unable to load file '//test/skylark:bad_extension.bzl': "
487 + "file doesn't exist or isn't a file";
Kristina Chodorow335f0672015-11-16 23:19:13 +0000488 assertThat(errorInfo.getException())
John Field1ea7fc32015-12-22 19:37:19 +0000489 .hasMessage(expectedMsg);
Kristina Chodorow335f0672015-11-16 23:19:13 +0000490 }
491
Florian Weikert92b22362015-12-03 10:17:18 +0000492 @Test
Kristina Chodorow335f0672015-11-16 23:19:13 +0000493 public void testNonExistingSkylarkExtensionFromExtension() throws Exception {
494 reporter.removeHandler(failFastHandler);
495 scratch.file("test/skylark/extension.bzl",
laurentlb5ddd8042017-11-30 12:03:31 -0800496 "load('//test/skylark:bad_extension.bzl', 'some_symbol')",
Kristina Chodorow335f0672015-11-16 23:19:13 +0000497 "a = 'a'");
498 scratch.file("test/skylark/BUILD",
laurentlb5ddd8042017-11-30 12:03:31 -0800499 "load('//test/skylark:extension.bzl', 'a')",
Kristina Chodorow335f0672015-11-16 23:19:13 +0000500 "genrule(name = gr,",
501 " outs = ['out.txt'],",
502 " cmd = 'echo hello >@')");
503 invalidatePackages();
504
Brian Silvermand7d6d622016-03-17 09:53:39 +0000505 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//test/skylark"));
Kristina Chodorow335f0672015-11-16 23:19:13 +0000506 EvaluationResult<PackageValue> result = SkyframeExecutorTestUtils.evaluate(
507 getSkyframeExecutor(), skyKey, /*keepGoing=*/false, reporter);
lberkiaea56b32017-05-30 12:35:33 +0200508 assertThat(result.hasError()).isTrue();
Kristina Chodorow335f0672015-11-16 23:19:13 +0000509 ErrorInfo errorInfo = result.getError(skyKey);
510 assertThat(errorInfo.getException())
511 .hasMessage("error loading package 'test/skylark': Extension file not found. "
512 + "Unable to load file '//test/skylark:bad_extension.bzl': "
513 + "file doesn't exist or isn't a file");
514 }
515
Florian Weikert92b22362015-12-03 10:17:18 +0000516 @Test
Kristina Chodorow335f0672015-11-16 23:19:13 +0000517 public void testSymlinkCycleWithSkylarkExtension() throws Exception {
518 reporter.removeHandler(failFastHandler);
519 Path extensionFilePath = scratch.resolve("/workspace/test/skylark/extension.bzl");
nharmatab4060b62017-04-04 17:11:39 +0000520 FileSystemUtils.ensureSymbolicLink(extensionFilePath, PathFragment.create("extension.bzl"));
Kristina Chodorow335f0672015-11-16 23:19:13 +0000521 scratch.file("test/skylark/BUILD",
laurentlb5ddd8042017-11-30 12:03:31 -0800522 "load('//test/skylark:extension.bzl', 'a')",
Kristina Chodorow335f0672015-11-16 23:19:13 +0000523 "genrule(name = gr,",
524 " outs = ['out.txt'],",
525 " cmd = 'echo hello >@')");
526 invalidatePackages();
527
Brian Silvermand7d6d622016-03-17 09:53:39 +0000528 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//test/skylark"));
Kristina Chodorow335f0672015-11-16 23:19:13 +0000529 EvaluationResult<PackageValue> result = SkyframeExecutorTestUtils.evaluate(
530 getSkyframeExecutor(), skyKey, /*keepGoing=*/false, reporter);
lberkiaea56b32017-05-30 12:35:33 +0200531 assertThat(result.hasError()).isTrue();
Kristina Chodorow335f0672015-11-16 23:19:13 +0000532 ErrorInfo errorInfo = result.getError(skyKey);
lberkiaea56b32017-05-30 12:35:33 +0200533 assertThat(errorInfo.getRootCauseOfException()).isEqualTo(skyKey);
Kristina Chodorow335f0672015-11-16 23:19:13 +0000534 assertThat(errorInfo.getException())
535 .hasMessage(
536 "error loading package 'test/skylark': Encountered error while reading extension "
537 + "file 'test/skylark/extension.bzl': Symlink cycle");
538 }
539
Florian Weikert92b22362015-12-03 10:17:18 +0000540 @Test
Kristina Chodorow335f0672015-11-16 23:19:13 +0000541 public void testIOErrorLookingForSubpackageForLabelIsHandled() throws Exception {
542 reporter.removeHandler(failFastHandler);
543 scratch.file("foo/BUILD",
544 "sh_library(name = 'foo', srcs = ['bar/baz.sh'])");
545 Path barBuildFile = scratch.file("foo/bar/BUILD");
aehligc801c392017-12-19 07:12:25 -0800546 fs.stubStatError(barBuildFile, new IOException("nope"));
Brian Silvermand7d6d622016-03-17 09:53:39 +0000547 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//foo"));
Kristina Chodorow335f0672015-11-16 23:19:13 +0000548 EvaluationResult<PackageValue> result = SkyframeExecutorTestUtils.evaluate(
549 getSkyframeExecutor(), skyKey, /*keepGoing=*/false, reporter);
lberkiaea56b32017-05-30 12:35:33 +0200550 assertThat(result.hasError()).isTrue();
Kristina Chodorow335f0672015-11-16 23:19:13 +0000551 assertContainsEvent("nope");
552 }
553
Florian Weikert92b22362015-12-03 10:17:18 +0000554 @Test
Kristina Chodorow335f0672015-11-16 23:19:13 +0000555 public void testLoadRelativePath() throws Exception {
laurentlb5ddd8042017-11-30 12:03:31 -0800556 scratch.file("pkg/BUILD", "load(':ext.bzl', 'a')");
Kristina Chodorow335f0672015-11-16 23:19:13 +0000557 scratch.file("pkg/ext.bzl", "a = 1");
Brian Silvermand7d6d622016-03-17 09:53:39 +0000558 validPackage(PackageValue.key(PackageIdentifier.parse("@//pkg")));
Kristina Chodorow335f0672015-11-16 23:19:13 +0000559 }
560
Florian Weikert92b22362015-12-03 10:17:18 +0000561 @Test
Kristina Chodorow335f0672015-11-16 23:19:13 +0000562 public void testLoadAbsolutePath() throws Exception {
563 scratch.file("pkg1/BUILD");
564 scratch.file("pkg2/BUILD",
laurentlb5ddd8042017-11-30 12:03:31 -0800565 "load('//pkg1:ext.bzl', 'a')");
Kristina Chodorow335f0672015-11-16 23:19:13 +0000566 scratch.file("pkg1/ext.bzl", "a = 1");
Brian Silvermand7d6d622016-03-17 09:53:39 +0000567 validPackage(PackageValue.key(PackageIdentifier.parse("@//pkg2")));
Kristina Chodorow335f0672015-11-16 23:19:13 +0000568 }
569
Florian Weikert92b22362015-12-03 10:17:18 +0000570 @Test
Kristina Chodorow335f0672015-11-16 23:19:13 +0000571 public void testBadWorkspaceFile() throws Exception {
572 Path workspacePath = scratch.overwriteFile("WORKSPACE", "junk");
Brian Silvermand7d6d622016-03-17 09:53:39 +0000573 SkyKey skyKey = PackageValue.key(PackageIdentifier.createInMainRepo("external"));
Kristina Chodorow335f0672015-11-16 23:19:13 +0000574 getSkyframeExecutor()
575 .invalidate(
576 Predicates.equalTo(
shahan602cc852018-06-06 20:09:57 -0700577 FileStateValue.key(
Kristina Chodorow335f0672015-11-16 23:19:13 +0000578 RootedPath.toRootedPath(
tomluee6a6862018-01-17 14:36:26 -0800579 Root.fromPath(workspacePath.getParentDirectory()),
nharmatab4060b62017-04-04 17:11:39 +0000580 PathFragment.create(workspacePath.getBaseName())))));
Kristina Chodorow335f0672015-11-16 23:19:13 +0000581
582 reporter.removeHandler(failFastHandler);
583 EvaluationResult<PackageValue> result =
584 SkyframeExecutorTestUtils.evaluate(
585 getSkyframeExecutor(), skyKey, /*keepGoing=*/ false, reporter);
lberkiaea56b32017-05-30 12:35:33 +0200586 assertThat(result.hasError()).isFalse();
587 assertThat(result.get(skyKey).getPackage().containsErrors()).isTrue();
Kristina Chodorow335f0672015-11-16 23:19:13 +0000588 }
589
Nathan Harmata2022ad82016-02-22 23:04:14 +0000590 // Regression test for the two ugly consequences of a bug where GlobFunction incorrectly matched
591 // dangling symlinks.
592 @Test
593 public void testIncrementalSkyframeHybridGlobbingOnDanglingSymlink() throws Exception {
594 Path packageDirPath = scratch.file("foo/BUILD",
595 "exports_files(glob(['*.txt']))").getParentDirectory();
596 scratch.file("foo/existing.txt");
597 FileSystemUtils.ensureSymbolicLink(packageDirPath.getChild("dangling.txt"), "nope");
598
Ulf Adamsc73051c62016-03-23 09:18:13 +0000599 preparePackageLoading(rootDirectory);
Nathan Harmata2022ad82016-02-22 23:04:14 +0000600
Brian Silvermand7d6d622016-03-17 09:53:39 +0000601 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//foo"));
Nathan Harmata2022ad82016-02-22 23:04:14 +0000602 PackageValue value = validPackage(skyKey);
lberkiaea56b32017-05-30 12:35:33 +0200603 assertThat(value.getPackage().containsErrors()).isFalse();
Nathan Harmata2022ad82016-02-22 23:04:14 +0000604 assertThat(value.getPackage().getTarget("existing.txt").getName()).isEqualTo("existing.txt");
605 try {
606 value.getPackage().getTarget("dangling.txt");
607 fail();
608 } catch (NoSuchTargetException expected) {
609 }
610
611 scratch.overwriteFile("foo/BUILD",
Laurent Le Brunb639ca82017-01-17 11:18:23 +0000612 "exports_files(glob(['*.txt']))",
Nathan Harmata2022ad82016-02-22 23:04:14 +0000613 "#some-irrelevant-comment");
614
tomluee6a6862018-01-17 14:36:26 -0800615 getSkyframeExecutor()
616 .invalidateFilesUnderPathForTesting(
617 reporter,
618 ModifiedFileSet.builder().modify(PathFragment.create("foo/BUILD")).build(),
619 Root.fromPath(rootDirectory));
Nathan Harmata2022ad82016-02-22 23:04:14 +0000620
621 value = validPackage(skyKey);
lberkiaea56b32017-05-30 12:35:33 +0200622 assertThat(value.getPackage().containsErrors()).isFalse();
Nathan Harmata2022ad82016-02-22 23:04:14 +0000623 assertThat(value.getPackage().getTarget("existing.txt").getName()).isEqualTo("existing.txt");
624 try {
625 value.getPackage().getTarget("dangling.txt");
626 fail();
627 } catch (NoSuchTargetException expected) {
628 // One consequence of the bug was that dangling symlinks were matched by globs evaluated by
629 // Skyframe globbing, meaning there would incorrectly be corresponding targets in packages
630 // that had skyframe cache hits during skyframe hybrid globbing.
631 }
632
633 scratch.file("foo/nope");
tomluee6a6862018-01-17 14:36:26 -0800634 getSkyframeExecutor()
635 .invalidateFilesUnderPathForTesting(
636 reporter,
637 ModifiedFileSet.builder().modify(PathFragment.create("foo/nope")).build(),
638 Root.fromPath(rootDirectory));
Nathan Harmata2022ad82016-02-22 23:04:14 +0000639
640 PackageValue newValue = validPackage(skyKey);
lberkiaea56b32017-05-30 12:35:33 +0200641 assertThat(newValue.getPackage().containsErrors()).isFalse();
Nathan Harmata2022ad82016-02-22 23:04:14 +0000642 assertThat(newValue.getPackage().getTarget("existing.txt").getName()).isEqualTo("existing.txt");
643 // Another consequence of the bug is that change pruning would incorrectly cut off changes that
644 // caused a dangling symlink potentially matched by a glob to come into existence.
645 assertThat(newValue.getPackage().getTarget("dangling.txt").getName()).isEqualTo("dangling.txt");
646 assertThat(newValue.getPackage()).isNotSameAs(value.getPackage());
647 }
648
Nathan Harmata86c319e2016-02-25 01:12:22 +0000649 // Regression test for Skyframe globbing incorrectly matching the package's directory path on
650 // 'glob(['**'], exclude_directories = 0)'. We test for this directly by triggering
651 // hybrid globbing (gives coverage for both legacy globbing and skyframe globbing).
652 @Test
653 public void testRecursiveGlobNeverMatchesPackageDirectory() throws Exception {
654 scratch.file("foo/BUILD",
655 "[sh_library(name = x + '-matched') for x in glob(['**'], exclude_directories = 0)]");
656 scratch.file("foo/bar");
657
Ulf Adamsc73051c62016-03-23 09:18:13 +0000658 preparePackageLoading(rootDirectory);
Nathan Harmata86c319e2016-02-25 01:12:22 +0000659
Brian Silvermand7d6d622016-03-17 09:53:39 +0000660 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//foo"));
Nathan Harmata86c319e2016-02-25 01:12:22 +0000661 PackageValue value = validPackage(skyKey);
lberkiaea56b32017-05-30 12:35:33 +0200662 assertThat(value.getPackage().containsErrors()).isFalse();
Nathan Harmata86c319e2016-02-25 01:12:22 +0000663 assertThat(value.getPackage().getTarget("bar-matched").getName()).isEqualTo("bar-matched");
664 try {
665 value.getPackage().getTarget("-matched");
666 fail();
667 } catch (NoSuchTargetException expected) {
668 }
669
670 scratch.overwriteFile("foo/BUILD",
671 "[sh_library(name = x + '-matched') for x in glob(['**'], exclude_directories = 0)]",
672 "#some-irrelevant-comment");
tomluee6a6862018-01-17 14:36:26 -0800673 getSkyframeExecutor()
674 .invalidateFilesUnderPathForTesting(
675 reporter,
676 ModifiedFileSet.builder().modify(PathFragment.create("foo/BUILD")).build(),
677 Root.fromPath(rootDirectory));
Nathan Harmata86c319e2016-02-25 01:12:22 +0000678
679 value = validPackage(skyKey);
lberkiaea56b32017-05-30 12:35:33 +0200680 assertThat(value.getPackage().containsErrors()).isFalse();
Nathan Harmata86c319e2016-02-25 01:12:22 +0000681 assertThat(value.getPackage().getTarget("bar-matched").getName()).isEqualTo("bar-matched");
682 try {
683 value.getPackage().getTarget("-matched");
684 fail();
685 } catch (NoSuchTargetException expected) {
686 }
687 }
688
nharmataff688bf2017-06-07 17:03:52 -0400689 @Test
690 public void testPackageLoadingErrorOnIOExceptionReadingBuildFile() throws Exception {
691 Path fooBuildFilePath = scratch.file("foo/BUILD");
692 IOException exn = new IOException("nope");
aehligc801c392017-12-19 07:12:25 -0800693 fs.throwExceptionOnGetInputStream(fooBuildFilePath, exn);
nharmataff688bf2017-06-07 17:03:52 -0400694
695 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//foo"));
696 EvaluationResult<PackageValue> result = SkyframeExecutorTestUtils.evaluate(
697 getSkyframeExecutor(), skyKey, /*keepGoing=*/false, reporter);
698 assertThat(result.hasError()).isTrue();
699 ErrorInfo errorInfo = result.getError(skyKey);
700 String errorMessage = errorInfo.getException().getMessage();
701 assertThat(errorMessage).contains("nope");
702 assertThat(errorInfo.getException()).isInstanceOf(NoSuchPackageException.class);
nharmata351efff2018-03-30 15:04:38 -0700703 assertThat(errorInfo.getException()).hasCauseThat().isInstanceOf(IOException.class);
nharmataff688bf2017-06-07 17:03:52 -0400704 }
705
nharmatabea67e92017-06-16 00:26:27 +0200706 @Test
707 public void testPackageLoadingErrorOnIOExceptionReadingBzlFile() throws Exception {
708 scratch.file("foo/BUILD", "load('//foo:bzl.bzl', 'x')");
709 Path fooBzlFilePath = scratch.file("foo/bzl.bzl");
710 IOException exn = new IOException("nope");
aehligc801c392017-12-19 07:12:25 -0800711 fs.throwExceptionOnGetInputStream(fooBzlFilePath, exn);
nharmatabea67e92017-06-16 00:26:27 +0200712
713 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//foo"));
714 EvaluationResult<PackageValue> result = SkyframeExecutorTestUtils.evaluate(
715 getSkyframeExecutor(), skyKey, /*keepGoing=*/false, reporter);
716 assertThat(result.hasError()).isTrue();
717 ErrorInfo errorInfo = result.getError(skyKey);
718 String errorMessage = errorInfo.getException().getMessage();
719 assertThat(errorMessage).contains("nope");
720 assertThat(errorInfo.getException()).isInstanceOf(NoSuchPackageException.class);
nharmata351efff2018-03-30 15:04:38 -0700721 assertThat(errorInfo.getException()).hasCauseThat().isInstanceOf(IOException.class);
nharmatabea67e92017-06-16 00:26:27 +0200722 }
723
Kristina Chodorow335f0672015-11-16 23:19:13 +0000724 private static class CustomInMemoryFs extends InMemoryFileSystem {
Googlerc804c662016-12-01 16:53:28 +0000725 private abstract static class FileStatusOrException {
726 abstract FileStatus get() throws IOException;
727
728 private static class ExceptionImpl extends FileStatusOrException {
729 private final IOException exn;
730
731 private ExceptionImpl(IOException exn) {
732 this.exn = exn;
733 }
734
735 @Override
736 FileStatus get() throws IOException {
737 throw exn;
738 }
739 }
740
741 private static class FileStatusImpl extends FileStatusOrException {
742
743 @Nullable
744 private final FileStatus fileStatus;
745
746 private FileStatusImpl(@Nullable FileStatus fileStatus) {
747 this.fileStatus = fileStatus;
748 }
749
750 @Override
751 @Nullable
752 FileStatus get() {
753 return fileStatus;
754 }
755 }
756 }
757
aehligc801c392017-12-19 07:12:25 -0800758 private final Map<Path, FileStatusOrException> stubbedStats = Maps.newHashMap();
759 private final Set<Path> makeUnreadableAfterReaddir = Sets.newHashSet();
760 private final Map<Path, IOException> pathsToErrorOnGetInputStream = Maps.newHashMap();
Kristina Chodorow335f0672015-11-16 23:19:13 +0000761
762 public CustomInMemoryFs(ManualClock manualClock) {
ccalvarinc9efd062018-07-27 12:46:46 -0700763 super(manualClock);
Kristina Chodorow335f0672015-11-16 23:19:13 +0000764 }
765
aehligc801c392017-12-19 07:12:25 -0800766 public void stubStat(Path path, @Nullable FileStatus stubbedResult) {
Googlerc804c662016-12-01 16:53:28 +0000767 stubbedStats.put(path, new FileStatusOrException.FileStatusImpl(stubbedResult));
Kristina Chodorow335f0672015-11-16 23:19:13 +0000768 }
769
aehligc801c392017-12-19 07:12:25 -0800770 public void stubStatError(Path path, IOException stubbedResult) {
Googlerc804c662016-12-01 16:53:28 +0000771 stubbedStats.put(path, new FileStatusOrException.ExceptionImpl(stubbedResult));
Kristina Chodorow335f0672015-11-16 23:19:13 +0000772 }
773
774 @Override
aehligc801c392017-12-19 07:12:25 -0800775 public FileStatus stat(Path path, boolean followSymlinks) throws IOException {
Googlerc804c662016-12-01 16:53:28 +0000776 if (stubbedStats.containsKey(path)) {
777 return stubbedStats.get(path).get();
Kristina Chodorow335f0672015-11-16 23:19:13 +0000778 }
Googlerc804c662016-12-01 16:53:28 +0000779 return super.stat(path, followSymlinks);
Kristina Chodorow335f0672015-11-16 23:19:13 +0000780 }
781
aehligc801c392017-12-19 07:12:25 -0800782 public void scheduleMakeUnreadableAfterReaddir(Path path) {
Googlerc804c662016-12-01 16:53:28 +0000783 makeUnreadableAfterReaddir.add(path);
Kristina Chodorow335f0672015-11-16 23:19:13 +0000784 }
785
786 @Override
aehligc801c392017-12-19 07:12:25 -0800787 public Collection<Dirent> readdir(Path path, boolean followSymlinks) throws IOException {
Kristina Chodorow335f0672015-11-16 23:19:13 +0000788 Collection<Dirent> result = super.readdir(path, followSymlinks);
Googlerc804c662016-12-01 16:53:28 +0000789 if (makeUnreadableAfterReaddir.contains(path)) {
aehligc801c392017-12-19 07:12:25 -0800790 path.setReadable(false);
Kristina Chodorow335f0672015-11-16 23:19:13 +0000791 }
792 return result;
793 }
nharmataff688bf2017-06-07 17:03:52 -0400794
aehligc801c392017-12-19 07:12:25 -0800795 public void throwExceptionOnGetInputStream(Path path, IOException exn) {
nharmataff688bf2017-06-07 17:03:52 -0400796 pathsToErrorOnGetInputStream.put(path, exn);
797 }
798
799 @Override
aehligc801c392017-12-19 07:12:25 -0800800 protected InputStream getInputStream(Path path) throws IOException {
nharmataff688bf2017-06-07 17:03:52 -0400801 IOException exnToThrow = pathsToErrorOnGetInputStream.get(path);
802 if (exnToThrow != null) {
803 throw exnToThrow;
804 }
805 return super.getInputStream(path);
806 }
Kristina Chodorow335f0672015-11-16 23:19:13 +0000807 }
Kristina Chodorow335f0672015-11-16 23:19:13 +0000808}