blob: 885b72877c8ee8b97659d5179bee198d8cf58b33 [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;
nharmata58613102018-10-11 15:10:04 -070018import static com.google.devtools.build.skyframe.EvaluationResultSubjectFactory.assertThatEvaluationResult;
michajlo660d17f2020-03-27 09:01:57 -070019import static org.junit.Assert.assertThrows;
Florian Weikert92b22362015-12-03 10:17:18 +000020import static org.junit.Assert.fail;
michajlod05a9232020-02-25 16:39:00 -080021import static org.mockito.ArgumentMatchers.any;
22import static org.mockito.Mockito.doAnswer;
Kristina Chodorow335f0672015-11-16 23:19:13 +000023
Kristina Chodorow335f0672015-11-16 23:19:13 +000024import com.google.common.base.Predicates;
25import com.google.common.collect.ImmutableList;
26import com.google.common.collect.ImmutableMap;
27import com.google.common.collect.Maps;
Googlerc804c662016-12-01 16:53:28 +000028import com.google.common.collect.Sets;
shahan602cc852018-06-06 20:09:57 -070029import com.google.devtools.build.lib.actions.FileStateValue;
brandjon38dafdd2020-08-06 09:49:13 -070030import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider;
Florian Weikertcca703a2015-12-07 09:56:38 +000031import com.google.devtools.build.lib.analysis.util.BuildViewTestCase;
philwo3bcb9f62017-09-06 12:52:21 +020032import com.google.devtools.build.lib.clock.BlazeClock;
Kristina Chodorow335f0672015-11-16 23:19:13 +000033import com.google.devtools.build.lib.cmdline.Label;
34import com.google.devtools.build.lib.cmdline.PackageIdentifier;
michajloa96b2d22020-02-26 14:54:50 -080035import com.google.devtools.build.lib.events.Event;
36import com.google.devtools.build.lib.events.ExtendedEventHandler;
adonovan87b46082020-07-08 15:58:04 -070037import com.google.devtools.build.lib.packages.BazelModuleContext;
nharmata58613102018-10-11 15:10:04 -070038import com.google.devtools.build.lib.packages.BuildFileNotFoundException;
Kristina Chodorow335f0672015-11-16 23:19:13 +000039import com.google.devtools.build.lib.packages.ConstantRuleVisibility;
nharmataff688bf2017-06-07 17:03:52 -040040import com.google.devtools.build.lib.packages.NoSuchPackageException;
Nathan Harmata2022ad82016-02-22 23:04:14 +000041import com.google.devtools.build.lib.packages.NoSuchTargetException;
nharmatac9fbe952019-06-13 09:39:23 -070042import com.google.devtools.build.lib.packages.Package;
michajlod05a9232020-02-25 16:39:00 -080043import com.google.devtools.build.lib.packages.PackageValidator;
44import com.google.devtools.build.lib.packages.PackageValidator.InvalidPackageException;
adonovan240bdea2020-09-03 15:24:12 -070045import com.google.devtools.build.lib.packages.semantics.BuildLanguageOptions;
ajurkowskid74b0ec2020-04-13 10:58:21 -070046import com.google.devtools.build.lib.pkgcache.PackageOptions;
Kristina Chodorow335f0672015-11-16 23:19:13 +000047import com.google.devtools.build.lib.pkgcache.PathPackageLocator;
Klaus Aehlig8eb47482018-09-17 09:14:58 -070048import com.google.devtools.build.lib.rules.repository.RepositoryDelegatorFunction;
Googler74178a52020-06-29 17:42:47 -070049import com.google.devtools.build.lib.server.FailureDetails.PackageLoading;
Kristina Chodorow335f0672015-11-16 23:19:13 +000050import com.google.devtools.build.lib.skyframe.util.SkyframeExecutorTestUtils;
51import com.google.devtools.build.lib.testutil.ManualClock;
brandjon38dafdd2020-08-06 09:49:13 -070052import com.google.devtools.build.lib.testutil.TestRuleClassProvider;
Googler74178a52020-06-29 17:42:47 -070053import com.google.devtools.build.lib.util.DetailedExitCode;
54import com.google.devtools.build.lib.util.ExitCode;
Benjamin Peterson723eca62019-07-22 17:24:10 -070055import com.google.devtools.build.lib.util.Pair;
Ulf Adamsc73051c62016-03-23 09:18:13 +000056import com.google.devtools.build.lib.util.io.TimestampGranularityMonitor;
janakr97c0bd12020-09-08 13:19:03 -070057import com.google.devtools.build.lib.vfs.DigestHashFunction;
Kristina Chodorow335f0672015-11-16 23:19:13 +000058import com.google.devtools.build.lib.vfs.Dirent;
59import com.google.devtools.build.lib.vfs.FileStatus;
60import com.google.devtools.build.lib.vfs.FileSystem;
61import com.google.devtools.build.lib.vfs.FileSystemUtils;
62import com.google.devtools.build.lib.vfs.ModifiedFileSet;
63import com.google.devtools.build.lib.vfs.Path;
64import com.google.devtools.build.lib.vfs.PathFragment;
tomluee6a6862018-01-17 14:36:26 -080065import com.google.devtools.build.lib.vfs.Root;
Kristina Chodorow335f0672015-11-16 23:19:13 +000066import com.google.devtools.build.lib.vfs.RootedPath;
nharmatace0335a2019-11-13 15:48:05 -080067import com.google.devtools.build.lib.vfs.Symlinks;
Kristina Chodorow335f0672015-11-16 23:19:13 +000068import com.google.devtools.build.lib.vfs.inmemoryfs.InMemoryFileSystem;
69import com.google.devtools.build.skyframe.ErrorInfo;
70import com.google.devtools.build.skyframe.EvaluationResult;
71import com.google.devtools.build.skyframe.RecordingDifferencer;
72import com.google.devtools.build.skyframe.SkyKey;
73import com.google.devtools.build.skyframe.SkyValue;
Janak Ramakrishnan326c6982016-09-27 14:58:26 +000074import com.google.devtools.common.options.Options;
Kristina Chodorow335f0672015-11-16 23:19:13 +000075import java.io.IOException;
nharmataff688bf2017-06-07 17:03:52 -040076import java.io.InputStream;
Janak Ramakrishnanffbc28a2017-02-13 22:51:45 +000077import java.util.ArrayList;
tomluee6a6862018-01-17 14:36:26 -080078import java.util.Arrays;
Kristina Chodorow335f0672015-11-16 23:19:13 +000079import java.util.Collection;
Janak Ramakrishnanffbc28a2017-02-13 22:51:45 +000080import java.util.List;
Kristina Chodorow335f0672015-11-16 23:19:13 +000081import java.util.Map;
jhorvitzdd1d8412020-08-01 05:59:14 -070082import java.util.Optional;
Googlerc804c662016-12-01 16:53:28 +000083import java.util.Set;
Kristina Chodorow335f0672015-11-16 23:19:13 +000084import java.util.UUID;
michajlo90810222020-03-02 09:36:23 -080085import java.util.concurrent.atomic.AtomicInteger;
Kristina Chodorow335f0672015-11-16 23:19:13 +000086import javax.annotation.Nullable;
adonovan450c7ad2020-09-14 13:00:21 -070087import net.starlark.java.eval.Module;
adonovan3ed7ed52020-09-30 12:03:28 -070088import net.starlark.java.eval.StarlarkInt;
michajlod05a9232020-02-25 16:39:00 -080089import org.junit.Rule;
John Cater94695912016-08-03 12:09:39 +000090import org.junit.Test;
91import org.junit.runner.RunWith;
92import org.junit.runners.JUnit4;
michajlod05a9232020-02-25 16:39:00 -080093import org.mockito.Mock;
94import org.mockito.junit.MockitoJUnit;
95import org.mockito.junit.MockitoRule;
Kristina Chodorow335f0672015-11-16 23:19:13 +000096
97/**
laurentlbc0bd2102018-10-17 07:05:25 -070098 * Unit tests of specific functionality of PackageFunction. Note that it's already tested indirectly
99 * in several other places.
Kristina Chodorow335f0672015-11-16 23:19:13 +0000100 */
Florian Weikert92b22362015-12-03 10:17:18 +0000101@RunWith(JUnit4.class)
Florian Weikertcca703a2015-12-07 09:56:38 +0000102public class PackageFunctionTest extends BuildViewTestCase {
Kristina Chodorow335f0672015-11-16 23:19:13 +0000103
michajlod05a9232020-02-25 16:39:00 -0800104 @Rule public final MockitoRule mockito = MockitoJUnit.rule();
105
106 @Mock private PackageValidator mockPackageValidator;
107
Kristina Chodorow335f0672015-11-16 23:19:13 +0000108 private CustomInMemoryFs fs = new CustomInMemoryFs(new ManualClock());
109
Ulf Adamsc73051c62016-03-23 09:18:13 +0000110 private void preparePackageLoading(Path... roots) {
nharmatac9fbe952019-06-13 09:39:23 -0700111 preparePackageLoadingWithCustomStarklarkSemanticsOptions(
adonovan240bdea2020-09-03 15:24:12 -0700112 Options.getDefaults(BuildLanguageOptions.class), roots);
nharmatac9fbe952019-06-13 09:39:23 -0700113 }
114
115 private void preparePackageLoadingWithCustomStarklarkSemanticsOptions(
brandjon6dbfa3e2020-10-06 19:31:08 -0700116 BuildLanguageOptions buildLanguageOptions, Path... roots) {
ajurkowskid74b0ec2020-04-13 10:58:21 -0700117 PackageOptions packageOptions = Options.getDefaults(PackageOptions.class);
118 packageOptions.defaultVisibility = ConstantRuleVisibility.PUBLIC;
119 packageOptions.showLoadingProgress = true;
120 packageOptions.globbingThreads = 7;
Klaus Aehlig6f33a1c2016-09-13 16:46:10 +0000121 getSkyframeExecutor()
122 .preparePackageLoading(
John Catere0d1d0e2017-11-28 20:47:41 -0800123 new PathPackageLocator(
124 outputBase,
tomluee6a6862018-01-17 14:36:26 -0800125 Arrays.stream(roots).map(Root::fromPath).collect(ImmutableList.toImmutableList()),
John Catere0d1d0e2017-11-28 20:47:41 -0800126 BazelSkyframeExecutorConstants.BUILD_FILES_BY_PRIORITY),
ajurkowskid74b0ec2020-04-13 10:58:21 -0700127 packageOptions,
brandjon6dbfa3e2020-10-06 19:31:08 -0700128 buildLanguageOptions,
Klaus Aehlig6f33a1c2016-09-13 16:46:10 +0000129 UUID.randomUUID(),
130 ImmutableMap.<String, String>of(),
131 new TimestampGranularityMonitor(BlazeClock.instance()));
juliexxia651797f2018-08-01 11:45:13 -0700132 skyframeExecutor.setActionEnv(ImmutableMap.<String, String>of());
Ulf Adamsc73051c62016-03-23 09:18:13 +0000133 }
134
Kristina Chodorow335f0672015-11-16 23:19:13 +0000135 @Override
Kristina Chodorow335f0672015-11-16 23:19:13 +0000136 protected FileSystem createFileSystem() {
137 return fs;
138 }
139
michajlod05a9232020-02-25 16:39:00 -0800140 @Override
141 protected PackageValidator getPackageValidator() {
142 return mockPackageValidator;
143 }
144
nharmatac9fbe952019-06-13 09:39:23 -0700145 private Package validPackageWithoutErrors(SkyKey skyKey) throws InterruptedException {
146 return validPackageInternal(skyKey, /*checkPackageError=*/ true);
147 }
148
149 private Package validPackage(SkyKey skyKey) throws InterruptedException {
150 return validPackageInternal(skyKey, /*checkPackageError=*/ false);
151 }
152
153 private Package validPackageInternal(SkyKey skyKey, boolean checkPackageError)
154 throws InterruptedException {
Klaus Aehlig8eb47482018-09-17 09:14:58 -0700155 SkyframeExecutor skyframeExecutor = getSkyframeExecutor();
156 skyframeExecutor.injectExtraPrecomputedValues(
157 ImmutableList.of(
158 PrecomputedValue.injected(
jhorvitzdd1d8412020-08-01 05:59:14 -0700159 RepositoryDelegatorFunction.RESOLVED_FILE_INSTEAD_OF_WORKSPACE, Optional.empty())));
Klaus Aehlig8eb47482018-09-17 09:14:58 -0700160 EvaluationResult<PackageValue> result =
161 SkyframeExecutorTestUtils.evaluate(
162 skyframeExecutor, skyKey, /*keepGoing=*/ false, reporter);
Kristina Chodorow335f0672015-11-16 23:19:13 +0000163 if (result.hasError()) {
164 fail(result.getError(skyKey).getException().getMessage());
165 }
166 PackageValue value = result.get(skyKey);
nharmatac9fbe952019-06-13 09:39:23 -0700167 if (checkPackageError) {
168 assertThat(value.getPackage().containsErrors()).isFalse();
169 }
170 return value.getPackage();
Kristina Chodorow335f0672015-11-16 23:19:13 +0000171 }
172
Florian Weikert92b22362015-12-03 10:17:18 +0000173 @Test
John Cater94695912016-08-03 12:09:39 +0000174 public void testValidPackage() throws Exception {
175 scratch.file("pkg/BUILD");
nharmatac9fbe952019-06-13 09:39:23 -0700176 validPackageWithoutErrors(PackageValue.key(PackageIdentifier.parse("@//pkg")));
John Cater94695912016-08-03 12:09:39 +0000177 }
178
179 @Test
michajlod05a9232020-02-25 16:39:00 -0800180 public void testInvalidPackage() throws Exception {
181 scratch.file("pkg/BUILD", "sh_library(name='foo', srcs=['foo.sh'])");
182 scratch.file("pkg/foo.sh");
183
184 doAnswer(
185 inv -> {
186 Package pkg = inv.getArgument(0, Package.class);
187 if (pkg.getName().equals("pkg")) {
michajloa96b2d22020-02-26 14:54:50 -0800188 inv.getArgument(1, ExtendedEventHandler.class).handle(Event.warn("warning event"));
michajlod05a9232020-02-25 16:39:00 -0800189 throw new InvalidPackageException(pkg.getPackageIdentifier(), "no good");
190 }
191 return null;
192 })
193 .when(mockPackageValidator)
michajloa96b2d22020-02-26 14:54:50 -0800194 .validate(any(Package.class), any(ExtendedEventHandler.class));
michajlod05a9232020-02-25 16:39:00 -0800195
196 invalidatePackages();
197
198 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//pkg"));
199 EvaluationResult<PackageValue> result =
200 SkyframeExecutorTestUtils.evaluate(
201 getSkyframeExecutor(), skyKey, /*keepGoing=*/ false, reporter);
202 assertThatEvaluationResult(result).hasError();
203 assertThatEvaluationResult(result)
204 .hasErrorEntryForKeyThat(skyKey)
205 .hasExceptionThat()
206 .isInstanceOf(InvalidPackageException.class);
207 assertThatEvaluationResult(result)
208 .hasErrorEntryForKeyThat(skyKey)
209 .hasExceptionThat()
210 .hasMessageThat()
211 .contains("no such package 'pkg': no good");
michajloa96b2d22020-02-26 14:54:50 -0800212 assertContainsEvent("warning event");
michajlod05a9232020-02-25 16:39:00 -0800213 }
214
215 @Test
michajlo90810222020-03-02 09:36:23 -0800216 public void testSkyframeExecutorClearedPackagesResultsInReload() throws Exception {
217 scratch.file("pkg/BUILD", "sh_library(name='foo', srcs=['foo.sh'])");
218 scratch.file("pkg/foo.sh");
219
220 invalidatePackages();
221
222 // Use number of times the package was validated as a proxy for number of times it was loaded.
223 AtomicInteger validationCount = new AtomicInteger();
224 doAnswer(
225 inv -> {
226 if (inv.getArgument(0, Package.class).getName().equals("pkg")) {
227 validationCount.incrementAndGet();
228 }
229 return null;
230 })
231 .when(mockPackageValidator)
232 .validate(any(Package.class), any(ExtendedEventHandler.class));
233
234 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//pkg"));
235 EvaluationResult<PackageValue> result1 =
236 SkyframeExecutorTestUtils.evaluate(
237 getSkyframeExecutor(), skyKey, /*keepGoing=*/ false, reporter);
238 assertThatEvaluationResult(result1).hasNoError();
239
240 skyframeExecutor.clearLoadedPackages();
241
242 EvaluationResult<PackageValue> result2 =
243 SkyframeExecutorTestUtils.evaluate(
244 getSkyframeExecutor(), skyKey, /*keepGoing=*/ false, reporter);
245 assertThatEvaluationResult(result2).hasNoError();
246
247 assertThat(validationCount.get()).isEqualTo(2);
248 }
249
250 @Test
Kristina Chodorow335f0672015-11-16 23:19:13 +0000251 public void testPropagatesFilesystemInconsistencies() throws Exception {
252 reporter.removeHandler(failFastHandler);
253 RecordingDifferencer differencer = getSkyframeExecutor().getDifferencerForTesting();
tomluee6a6862018-01-17 14:36:26 -0800254 Root pkgRoot = getSkyframeExecutor().getPathEntries().get(0);
Kristina Chodorow335f0672015-11-16 23:19:13 +0000255 Path fooBuildFile = scratch.file("foo/BUILD");
256 Path fooDir = fooBuildFile.getParentDirectory();
257
neerajen89188eb2018-07-19 13:03:43 -0700258 // Our custom filesystem says that fooDir is neither a file nor directory nor symlink
laurentlbc0bd2102018-10-17 07:05:25 -0700259 FileStatus inconsistentFileStatus =
260 new FileStatus() {
261 @Override
262 public boolean isFile() {
263 return false;
264 }
Kristina Chodorow335f0672015-11-16 23:19:13 +0000265
laurentlbc0bd2102018-10-17 07:05:25 -0700266 @Override
267 public boolean isDirectory() {
268 return false;
269 }
Kristina Chodorow335f0672015-11-16 23:19:13 +0000270
laurentlbc0bd2102018-10-17 07:05:25 -0700271 @Override
272 public boolean isSymbolicLink() {
273 return false;
274 }
Kristina Chodorow335f0672015-11-16 23:19:13 +0000275
laurentlbc0bd2102018-10-17 07:05:25 -0700276 @Override
277 public boolean isSpecialFile() {
278 return false;
279 }
Kristina Chodorow335f0672015-11-16 23:19:13 +0000280
laurentlbc0bd2102018-10-17 07:05:25 -0700281 @Override
282 public long getSize() throws IOException {
283 return 0;
284 }
Kristina Chodorow335f0672015-11-16 23:19:13 +0000285
laurentlbc0bd2102018-10-17 07:05:25 -0700286 @Override
287 public long getLastModifiedTime() throws IOException {
288 return 0;
289 }
Kristina Chodorow335f0672015-11-16 23:19:13 +0000290
laurentlbc0bd2102018-10-17 07:05:25 -0700291 @Override
292 public long getLastChangeTime() throws IOException {
293 return 0;
294 }
Kristina Chodorow335f0672015-11-16 23:19:13 +0000295
laurentlbc0bd2102018-10-17 07:05:25 -0700296 @Override
297 public long getNodeId() throws IOException {
298 return 0;
299 }
300 };
neerajen89188eb2018-07-19 13:03:43 -0700301
302 fs.stubStat(fooBuildFile, inconsistentFileStatus);
Kristina Chodorow335f0672015-11-16 23:19:13 +0000303 RootedPath pkgRootedPath = RootedPath.toRootedPath(pkgRoot, fooDir);
Ulf Adamsc73051c62016-03-23 09:18:13 +0000304 SkyValue fooDirValue = FileStateValue.create(pkgRootedPath, tsgm);
Kristina Chodorow335f0672015-11-16 23:19:13 +0000305 differencer.inject(ImmutableMap.of(FileStateValue.key(pkgRootedPath), fooDirValue));
Brian Silvermand7d6d622016-03-17 09:53:39 +0000306 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//foo"));
laurentlbc0bd2102018-10-17 07:05:25 -0700307 String expectedMessage =
308 "according to stat, existing path /workspace/foo/BUILD is neither"
309 + " a file nor directory nor symlink.";
310 EvaluationResult<PackageValue> result =
311 SkyframeExecutorTestUtils.evaluate(
312 getSkyframeExecutor(), skyKey, /*keepGoing=*/ false, reporter);
lberkiaea56b32017-05-30 12:35:33 +0200313 assertThat(result.hasError()).isTrue();
Kristina Chodorow335f0672015-11-16 23:19:13 +0000314 ErrorInfo errorInfo = result.getError(skyKey);
315 String errorMessage = errorInfo.getException().getMessage();
316 assertThat(errorMessage).contains("Inconsistent filesystem operations");
317 assertThat(errorMessage).contains(expectedMessage);
Googler74178a52020-06-29 17:42:47 -0700318 assertDetailedExitCode(
319 errorInfo.getException(), PackageLoading.Code.PERSISTENT_INCONSISTENT_FILESYSTEM_ERROR);
Kristina Chodorow335f0672015-11-16 23:19:13 +0000320 }
321
Florian Weikert92b22362015-12-03 10:17:18 +0000322 @Test
jmmvbfbd95f2020-08-31 13:12:38 -0700323 public void testPropagatesFilesystemInconsistencies_globbing() throws Exception {
djasper7faa0ef2019-03-28 10:00:00 -0700324 getSkyframeExecutor().turnOffSyscallCacheForTesting();
Kristina Chodorow335f0672015-11-16 23:19:13 +0000325 reporter.removeHandler(failFastHandler);
326 RecordingDifferencer differencer = getSkyframeExecutor().getDifferencerForTesting();
tomluee6a6862018-01-17 14:36:26 -0800327 Root pkgRoot = getSkyframeExecutor().getPathEntries().get(0);
laurentlbc0bd2102018-10-17 07:05:25 -0700328 scratch.file(
329 "foo/BUILD",
Googlerbb0d36a2019-09-26 13:19:28 -0700330 "sh_library(name = 'foo', srcs = glob(['bar/**/baz.sh']))",
331 "x = 1//0" // causes 'foo' to be marked in error
332 );
Kristina Chodorow335f0672015-11-16 23:19:13 +0000333 Path bazFile = scratch.file("foo/bar/baz/baz.sh");
334 Path bazDir = bazFile.getParentDirectory();
335 Path barDir = bazDir.getParentDirectory();
336
Kristina Chodorow335f0672015-11-16 23:19:13 +0000337 // Our custom filesystem says "foo/bar/baz" does not exist but it also says that "foo/bar"
338 // has a child directory "baz".
aehligc801c392017-12-19 07:12:25 -0800339 fs.stubStat(bazDir, null);
Kristina Chodorow335f0672015-11-16 23:19:13 +0000340 RootedPath barDirRootedPath = RootedPath.toRootedPath(pkgRoot, barDir);
janakre54491e2018-07-11 16:29:13 -0700341 differencer.inject(
342 ImmutableMap.of(
343 DirectoryListingStateValue.key(barDirRootedPath),
344 DirectoryListingStateValue.create(
345 ImmutableList.of(new Dirent("baz", Dirent.Type.DIRECTORY)))));
Brian Silvermand7d6d622016-03-17 09:53:39 +0000346 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//foo"));
Nathan Harmatac0f3d4e2016-10-17 15:49:34 +0000347 String expectedMessage = "/workspace/foo/bar/baz is no longer an existing directory";
laurentlbc0bd2102018-10-17 07:05:25 -0700348 EvaluationResult<PackageValue> result =
349 SkyframeExecutorTestUtils.evaluate(
350 getSkyframeExecutor(), skyKey, /*keepGoing=*/ false, reporter);
lberkiaea56b32017-05-30 12:35:33 +0200351 assertThat(result.hasError()).isTrue();
Kristina Chodorow335f0672015-11-16 23:19:13 +0000352 ErrorInfo errorInfo = result.getError(skyKey);
353 String errorMessage = errorInfo.getException().getMessage();
354 assertThat(errorMessage).contains("Inconsistent filesystem operations");
355 assertThat(errorMessage).contains(expectedMessage);
Googler74178a52020-06-29 17:42:47 -0700356 assertDetailedExitCode(
357 errorInfo.getException(), PackageLoading.Code.PERSISTENT_INCONSISTENT_FILESYSTEM_ERROR);
Kristina Chodorow335f0672015-11-16 23:19:13 +0000358 }
359
360 /** Regression test for unexpected exception type from PackageValue. */
Florian Weikert92b22362015-12-03 10:17:18 +0000361 @Test
Kristina Chodorow335f0672015-11-16 23:19:13 +0000362 public void testDiscrepancyBetweenLegacyAndSkyframePackageLoadingErrors() throws Exception {
djasperb109a5f2019-02-14 01:05:34 -0800363 // Normally, legacy globbing and skyframe globbing share a cache for `readdir` filesystem calls.
364 // In order to exercise a situation where they observe different results for filesystem calls,
365 // we disable the cache. This might happen in a real scenario, e.g. if the cache hits a limit
366 // and evicts entries.
367 getSkyframeExecutor().turnOffSyscallCacheForTesting();
Kristina Chodorow335f0672015-11-16 23:19:13 +0000368 reporter.removeHandler(failFastHandler);
laurentlbc0bd2102018-10-17 07:05:25 -0700369 Path fooBuildFile =
370 scratch.file("foo/BUILD", "sh_library(name = 'foo', srcs = glob(['bar/*.sh']))");
Kristina Chodorow335f0672015-11-16 23:19:13 +0000371 Path fooDir = fooBuildFile.getParentDirectory();
372 Path barDir = fooDir.getRelative("bar");
373 scratch.file("foo/bar/baz.sh");
aehligc801c392017-12-19 07:12:25 -0800374 fs.scheduleMakeUnreadableAfterReaddir(barDir);
Kristina Chodorow335f0672015-11-16 23:19:13 +0000375
Brian Silvermand7d6d622016-03-17 09:53:39 +0000376 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//foo"));
Kristina Chodorow335f0672015-11-16 23:19:13 +0000377 String expectedMessage = "Encountered error 'Directory is not readable'";
laurentlbc0bd2102018-10-17 07:05:25 -0700378 EvaluationResult<PackageValue> result =
379 SkyframeExecutorTestUtils.evaluate(
380 getSkyframeExecutor(), skyKey, /*keepGoing=*/ false, reporter);
lberkiaea56b32017-05-30 12:35:33 +0200381 assertThat(result.hasError()).isTrue();
Kristina Chodorow335f0672015-11-16 23:19:13 +0000382 ErrorInfo errorInfo = result.getError(skyKey);
383 String errorMessage = errorInfo.getException().getMessage();
384 assertThat(errorMessage).contains("Inconsistent filesystem operations");
385 assertThat(errorMessage).contains(expectedMessage);
Googler74178a52020-06-29 17:42:47 -0700386 assertDetailedExitCode(
387 errorInfo.getException(), PackageLoading.Code.TRANSIENT_INCONSISTENT_FILESYSTEM_ERROR);
Kristina Chodorow335f0672015-11-16 23:19:13 +0000388 }
389
Janak Ramakrishnan063b4882016-07-18 20:33:28 +0000390 @SuppressWarnings("unchecked") // Cast of srcs attribute to Iterable<Label>.
391 @Test
392 public void testGlobOrderStable() throws Exception {
393 scratch.file("foo/BUILD", "sh_library(name = 'foo', srcs = glob(['**/*.txt']))");
394 scratch.file("foo/b.txt");
395 scratch.file("foo/c/c.txt");
396 preparePackageLoading(rootDirectory);
397 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//foo"));
nharmatac9fbe952019-06-13 09:39:23 -0700398 Package pkg = validPackageWithoutErrors(skyKey);
Googlera40c64a2020-08-11 16:39:39 -0700399 assertThat((Iterable<Label>) pkg.getTarget("foo").getAssociatedRule().getAttr("srcs"))
Janak Ramakrishnan063b4882016-07-18 20:33:28 +0000400 .containsExactly(
401 Label.parseAbsoluteUnchecked("//foo:b.txt"),
402 Label.parseAbsoluteUnchecked("//foo:c/c.txt"))
403 .inOrder();
404 scratch.file("foo/d.txt");
405 getSkyframeExecutor()
406 .invalidateFilesUnderPathForTesting(
407 reporter,
nharmatab4060b62017-04-04 17:11:39 +0000408 ModifiedFileSet.builder().modify(PathFragment.create("foo/d.txt")).build(),
tomluee6a6862018-01-17 14:36:26 -0800409 Root.fromPath(rootDirectory));
nharmatac9fbe952019-06-13 09:39:23 -0700410 pkg = validPackageWithoutErrors(skyKey);
Googlera40c64a2020-08-11 16:39:39 -0700411 assertThat((Iterable<Label>) pkg.getTarget("foo").getAssociatedRule().getAttr("srcs"))
Janak Ramakrishnan063b4882016-07-18 20:33:28 +0000412 .containsExactly(
413 Label.parseAbsoluteUnchecked("//foo:b.txt"),
414 Label.parseAbsoluteUnchecked("//foo:c/c.txt"),
415 Label.parseAbsoluteUnchecked("//foo:d.txt"))
416 .inOrder();
417 }
418
Janak Ramakrishnan063b4882016-07-18 20:33:28 +0000419 @Test
420 public void testGlobOrderStableWithLegacyAndSkyframeComponents() throws Exception {
421 scratch.file("foo/BUILD", "sh_library(name = 'foo', srcs = glob(['*.txt']))");
422 scratch.file("foo/b.txt");
423 scratch.file("foo/a.config");
424 preparePackageLoading(rootDirectory);
425 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//foo"));
nharmatac9fbe952019-06-13 09:39:23 -0700426 assertSrcs(validPackageWithoutErrors(skyKey), "foo", "//foo:b.txt");
Janak Ramakrishnan063b4882016-07-18 20:33:28 +0000427 scratch.overwriteFile(
428 "foo/BUILD", "sh_library(name = 'foo', srcs = glob(['*.txt', '*.config']))");
429 getSkyframeExecutor()
430 .invalidateFilesUnderPathForTesting(
431 reporter,
nharmatab4060b62017-04-04 17:11:39 +0000432 ModifiedFileSet.builder().modify(PathFragment.create("foo/BUILD")).build(),
tomluee6a6862018-01-17 14:36:26 -0800433 Root.fromPath(rootDirectory));
nharmatac9fbe952019-06-13 09:39:23 -0700434 assertSrcs(validPackageWithoutErrors(skyKey), "foo", "//foo:a.config", "//foo:b.txt");
Janak Ramakrishnan063b4882016-07-18 20:33:28 +0000435 scratch.overwriteFile(
436 "foo/BUILD", "sh_library(name = 'foo', srcs = glob(['*.txt', '*.config'])) # comment");
437 getSkyframeExecutor()
438 .invalidateFilesUnderPathForTesting(
439 reporter,
nharmatab4060b62017-04-04 17:11:39 +0000440 ModifiedFileSet.builder().modify(PathFragment.create("foo/BUILD")).build(),
tomluee6a6862018-01-17 14:36:26 -0800441 Root.fromPath(rootDirectory));
nharmatac9fbe952019-06-13 09:39:23 -0700442 assertSrcs(validPackageWithoutErrors(skyKey), "foo", "//foo:a.config", "//foo:b.txt");
Nathan Harmata44e1e3a2016-08-23 21:22:17 +0000443 getSkyframeExecutor().resetEvaluator();
ajurkowskid74b0ec2020-04-13 10:58:21 -0700444 PackageOptions packageOptions = Options.getDefaults(PackageOptions.class);
445 packageOptions.defaultVisibility = ConstantRuleVisibility.PUBLIC;
446 packageOptions.showLoadingProgress = true;
447 packageOptions.globbingThreads = 7;
Klaus Aehlig6f33a1c2016-09-13 16:46:10 +0000448 getSkyframeExecutor()
449 .preparePackageLoading(
John Catere0d1d0e2017-11-28 20:47:41 -0800450 new PathPackageLocator(
451 outputBase,
tomluee6a6862018-01-17 14:36:26 -0800452 ImmutableList.of(Root.fromPath(rootDirectory)),
John Catere0d1d0e2017-11-28 20:47:41 -0800453 BazelSkyframeExecutorConstants.BUILD_FILES_BY_PRIORITY),
ajurkowskid74b0ec2020-04-13 10:58:21 -0700454 packageOptions,
adonovan240bdea2020-09-03 15:24:12 -0700455 Options.getDefaults(BuildLanguageOptions.class),
Klaus Aehlig6f33a1c2016-09-13 16:46:10 +0000456 UUID.randomUUID(),
Klaus Aehlig03b9cfd2016-09-14 13:14:39 +0000457 ImmutableMap.<String, String>of(),
Klaus Aehlig6f33a1c2016-09-13 16:46:10 +0000458 tsgm);
juliexxia651797f2018-08-01 11:45:13 -0700459 getSkyframeExecutor().setActionEnv(ImmutableMap.<String, String>of());
nharmatac9fbe952019-06-13 09:39:23 -0700460 assertSrcs(validPackageWithoutErrors(skyKey), "foo", "//foo:a.config", "//foo:b.txt");
Janak Ramakrishnan063b4882016-07-18 20:33:28 +0000461 }
462
Benjamin Peterson3b39e1e2020-01-31 10:21:38 -0800463 @Test
464 public void globEscapesAt() throws Exception {
465 scratch.file("foo/BUILD", "filegroup(name = 'foo', srcs = glob(['*.txt']))");
466 scratch.file("foo/@f.txt");
467 preparePackageLoading(rootDirectory);
468 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//foo"));
469 assertSrcs(validPackageWithoutErrors(skyKey), "foo", "//foo:@f.txt");
470
471 scratch.overwriteFile("foo/BUILD", "filegroup(name = 'foo', srcs = glob(['*.txt'])) # comment");
472 getSkyframeExecutor()
473 .invalidateFilesUnderPathForTesting(
474 reporter,
475 ModifiedFileSet.builder().modify(PathFragment.create("foo/BUILD")).build(),
476 Root.fromPath(rootDirectory));
477 assertSrcs(validPackageWithoutErrors(skyKey), "foo", "//foo:@f.txt");
478 }
479
Janak Ramakrishnanffbc28a2017-02-13 22:51:45 +0000480 /**
481 * Tests that a symlink to a file outside of the package root is handled consistently. If the
482 * default behavior of Bazel was changed from {@code
483 * ExternalFileAction#DEPEND_ON_EXTERNAL_PKG_FOR_EXTERNAL_REPO_PATHS} to {@code
484 * ExternalFileAction#ASSUME_NON_EXISTENT_AND_IMMUTABLE_FOR_EXTERNAL_PATHS} then foo/link.sh
485 * should no longer appear in the srcs of //foo:foo. However, either way the srcs should be the
486 * same independent of the evaluation being incremental or clean.
487 */
488 @Test
489 public void testGlobWithExternalSymlink() throws Exception {
490 scratch.file(
491 "foo/BUILD",
492 "sh_library(name = 'foo', srcs = glob(['*.sh']))",
493 "sh_library(name = 'bar', srcs = glob(['link.sh']))",
494 "sh_library(name = 'baz', srcs = glob(['subdir_link/*.txt']))");
495 scratch.file("foo/ordinary.sh");
496 Path externalTarget = scratch.file("../ops/target.txt");
497 FileSystemUtils.ensureSymbolicLink(scratch.resolve("foo/link.sh"), externalTarget);
498 FileSystemUtils.ensureSymbolicLink(
499 scratch.resolve("foo/subdir_link"), externalTarget.getParentDirectory());
500 preparePackageLoading(rootDirectory);
501 SkyKey fooKey = PackageValue.key(PackageIdentifier.parse("@//foo"));
nharmatac9fbe952019-06-13 09:39:23 -0700502 Package fooPkg = validPackageWithoutErrors(fooKey);
503 assertSrcs(fooPkg, "foo", "//foo:link.sh", "//foo:ordinary.sh");
504 assertSrcs(fooPkg, "bar", "//foo:link.sh");
505 assertSrcs(fooPkg, "baz", "//foo:subdir_link/target.txt");
Janak Ramakrishnanffbc28a2017-02-13 22:51:45 +0000506 scratch.overwriteFile(
507 "foo/BUILD",
508 "sh_library(name = 'foo', srcs = glob(['*.sh'])) #comment",
509 "sh_library(name = 'bar', srcs = glob(['link.sh']))",
510 "sh_library(name = 'baz', srcs = glob(['subdir_link/*.txt']))");
511 getSkyframeExecutor()
512 .invalidateFilesUnderPathForTesting(
513 reporter,
nharmatab4060b62017-04-04 17:11:39 +0000514 ModifiedFileSet.builder().modify(PathFragment.create("foo/BUILD")).build(),
tomluee6a6862018-01-17 14:36:26 -0800515 Root.fromPath(rootDirectory));
nharmatac9fbe952019-06-13 09:39:23 -0700516 Package fooPkg2 = validPackageWithoutErrors(fooKey);
517 assertThat(fooPkg2).isNotEqualTo(fooPkg);
518 assertSrcs(fooPkg2, "foo", "//foo:link.sh", "//foo:ordinary.sh");
519 assertSrcs(fooPkg2, "bar", "//foo:link.sh");
520 assertSrcs(fooPkg2, "baz", "//foo:subdir_link/target.txt");
Janak Ramakrishnanffbc28a2017-02-13 22:51:45 +0000521 }
522
nharmatac9fbe952019-06-13 09:39:23 -0700523 private static void assertSrcs(Package pkg, String targetName, String... expected)
Janak Ramakrishnanffbc28a2017-02-13 22:51:45 +0000524 throws NoSuchTargetException {
525 List<Label> expectedLabels = new ArrayList<>();
526 for (String item : expected) {
527 expectedLabels.add(Label.parseAbsoluteUnchecked(item));
528 }
nharmatac9fbe952019-06-13 09:39:23 -0700529 assertThat(getSrcs(pkg, targetName)).containsExactlyElementsIn(expectedLabels).inOrder();
Janak Ramakrishnanffbc28a2017-02-13 22:51:45 +0000530 }
531
532 @SuppressWarnings("unchecked")
nharmatac9fbe952019-06-13 09:39:23 -0700533 private static Iterable<Label> getSrcs(Package pkg, String targetName)
Janak Ramakrishnanffbc28a2017-02-13 22:51:45 +0000534 throws NoSuchTargetException {
Googlera40c64a2020-08-11 16:39:39 -0700535 return (Iterable<Label>) pkg.getTarget(targetName).getAssociatedRule().getAttr("srcs");
Janak Ramakrishnanffbc28a2017-02-13 22:51:45 +0000536 }
laurentlbc0bd2102018-10-17 07:05:25 -0700537
Florian Weikert92b22362015-12-03 10:17:18 +0000538 @Test
Janak Ramakrishnan4e2e4082017-01-06 06:28:45 +0000539 public void testOneNewElementInMultipleGlob() throws Exception {
540 scratch.file(
541 "foo/BUILD",
542 "sh_library(name = 'foo', srcs = glob(['*.sh']))",
543 "sh_library(name = 'bar', srcs = glob(['*.sh', '*.txt']))");
544 preparePackageLoading(rootDirectory);
545 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//foo"));
nharmatac9fbe952019-06-13 09:39:23 -0700546 Package pkg = validPackageWithoutErrors(skyKey);
547 scratch.file("foo/irrelevant");
Janak Ramakrishnan4e2e4082017-01-06 06:28:45 +0000548 getSkyframeExecutor()
549 .invalidateFilesUnderPathForTesting(
550 reporter,
nharmatab4060b62017-04-04 17:11:39 +0000551 ModifiedFileSet.builder().modify(PathFragment.create("foo/irrelevant")).build(),
tomluee6a6862018-01-17 14:36:26 -0800552 Root.fromPath(rootDirectory));
nharmatac9fbe952019-06-13 09:39:23 -0700553 assertThat(validPackageWithoutErrors(skyKey)).isSameInstanceAs(pkg);
Janak Ramakrishnan4e2e4082017-01-06 06:28:45 +0000554 }
555
556 @Test
557 public void testNoNewElementInMultipleGlob() throws Exception {
558 scratch.file(
559 "foo/BUILD",
560 "sh_library(name = 'foo', srcs = glob(['*.sh', '*.txt']))",
561 "sh_library(name = 'bar', srcs = glob(['*.sh', '*.txt']))");
562 preparePackageLoading(rootDirectory);
563 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//foo"));
nharmatac9fbe952019-06-13 09:39:23 -0700564 Package pkg = validPackageWithoutErrors(skyKey);
565 scratch.file("foo/irrelevant");
Janak Ramakrishnan4e2e4082017-01-06 06:28:45 +0000566 getSkyframeExecutor()
567 .invalidateFilesUnderPathForTesting(
568 reporter,
nharmatab4060b62017-04-04 17:11:39 +0000569 ModifiedFileSet.builder().modify(PathFragment.create("foo/irrelevant")).build(),
tomluee6a6862018-01-17 14:36:26 -0800570 Root.fromPath(rootDirectory));
nharmatac9fbe952019-06-13 09:39:23 -0700571 assertThat(validPackageWithoutErrors(skyKey)).isSameInstanceAs(pkg);
Janak Ramakrishnan4e2e4082017-01-06 06:28:45 +0000572 }
573
574 @Test
gregceb100b1d2020-05-20 10:22:17 -0700575 public void testTransitiveStarlarkDepsStoredInPackage() throws Exception {
laurentlbc0bd2102018-10-17 07:05:25 -0700576 scratch.file("foo/BUILD", "load('//bar:ext.bzl', 'a')");
Kristina Chodorow335f0672015-11-16 23:19:13 +0000577 scratch.file("bar/BUILD");
laurentlbc0bd2102018-10-17 07:05:25 -0700578 scratch.file("bar/ext.bzl", "load('//baz:ext.bzl', 'b')", "a = b");
Kristina Chodorow335f0672015-11-16 23:19:13 +0000579 scratch.file("baz/BUILD");
laurentlbc0bd2102018-10-17 07:05:25 -0700580 scratch.file("baz/ext.bzl", "b = 1");
Kristina Chodorow335f0672015-11-16 23:19:13 +0000581 scratch.file("qux/BUILD");
laurentlbc0bd2102018-10-17 07:05:25 -0700582 scratch.file("qux/ext.bzl", "c = 1");
Kristina Chodorow335f0672015-11-16 23:19:13 +0000583
Ulf Adamsc73051c62016-03-23 09:18:13 +0000584 preparePackageLoading(rootDirectory);
Kristina Chodorow335f0672015-11-16 23:19:13 +0000585
Brian Silvermand7d6d622016-03-17 09:53:39 +0000586 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//foo"));
nharmatac9fbe952019-06-13 09:39:23 -0700587 Package pkg = validPackageWithoutErrors(skyKey);
gregce7ecc2d62020-04-17 15:32:47 -0700588 assertThat(pkg.getStarlarkFileDependencies())
dannark90e2b4b2018-06-27 13:35:04 -0700589 .containsExactly(
590 Label.parseAbsolute("//bar:ext.bzl", ImmutableMap.of()),
591 Label.parseAbsolute("//baz:ext.bzl", ImmutableMap.of()));
Kristina Chodorow335f0672015-11-16 23:19:13 +0000592
laurentlbc0bd2102018-10-17 07:05:25 -0700593 scratch.overwriteFile("bar/ext.bzl", "load('//qux:ext.bzl', 'c')", "a = c");
tomluee6a6862018-01-17 14:36:26 -0800594 getSkyframeExecutor()
595 .invalidateFilesUnderPathForTesting(
596 reporter,
597 ModifiedFileSet.builder().modify(PathFragment.create("bar/ext.bzl")).build(),
598 Root.fromPath(rootDirectory));
Kristina Chodorow335f0672015-11-16 23:19:13 +0000599
nharmatac9fbe952019-06-13 09:39:23 -0700600 pkg = validPackageWithoutErrors(skyKey);
gregce7ecc2d62020-04-17 15:32:47 -0700601 assertThat(pkg.getStarlarkFileDependencies())
dannark90e2b4b2018-06-27 13:35:04 -0700602 .containsExactly(
603 Label.parseAbsolute("//bar:ext.bzl", ImmutableMap.of()),
604 Label.parseAbsolute("//qux:ext.bzl", ImmutableMap.of()));
Kristina Chodorow335f0672015-11-16 23:19:13 +0000605 }
606
Florian Weikert92b22362015-12-03 10:17:18 +0000607 @Test
gregceb100b1d2020-05-20 10:22:17 -0700608 public void testNonExistingStarlarkExtension() throws Exception {
Kristina Chodorow335f0672015-11-16 23:19:13 +0000609 reporter.removeHandler(failFastHandler);
laurentlbc0bd2102018-10-17 07:05:25 -0700610 scratch.file(
gregce0503fee2020-06-11 09:22:27 -0700611 "test/starlark/BUILD",
612 "load('//test/starlark:bad_extension.bzl', 'some_symbol')",
Kristina Chodorow335f0672015-11-16 23:19:13 +0000613 "genrule(name = gr,",
614 " outs = ['out.txt'],",
615 " cmd = 'echo hello >@')");
616 invalidatePackages();
617
gregce0503fee2020-06-11 09:22:27 -0700618 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//test/starlark"));
laurentlbc0bd2102018-10-17 07:05:25 -0700619 EvaluationResult<PackageValue> result =
620 SkyframeExecutorTestUtils.evaluate(
621 getSkyframeExecutor(), skyKey, /*keepGoing=*/ false, reporter);
lberkiaea56b32017-05-30 12:35:33 +0200622 assertThat(result.hasError()).isTrue();
Kristina Chodorow335f0672015-11-16 23:19:13 +0000623 ErrorInfo errorInfo = result.getError(skyKey);
laurentlbdd612a82018-10-16 19:42:48 -0700624 String expectedMsg =
gregce0503fee2020-06-11 09:22:27 -0700625 "error loading package 'test/starlark': "
626 + "cannot load '//test/starlark:bad_extension.bzl': no such file";
diamondmd6df9802019-03-19 06:53:43 -0700627 assertThat(errorInfo.getException()).hasMessageThat().isEqualTo(expectedMsg);
Googler74178a52020-06-29 17:42:47 -0700628 assertDetailedExitCode(
629 errorInfo.getException(), PackageLoading.Code.IMPORT_STARLARK_FILE_ERROR);
Kristina Chodorow335f0672015-11-16 23:19:13 +0000630 }
631
Florian Weikert92b22362015-12-03 10:17:18 +0000632 @Test
gregceb100b1d2020-05-20 10:22:17 -0700633 public void testNonExistingStarlarkExtensionFromExtension() throws Exception {
Kristina Chodorow335f0672015-11-16 23:19:13 +0000634 reporter.removeHandler(failFastHandler);
laurentlbc0bd2102018-10-17 07:05:25 -0700635 scratch.file(
gregce0503fee2020-06-11 09:22:27 -0700636 "test/starlark/extension.bzl",
637 "load('//test/starlark:bad_extension.bzl', 'some_symbol')",
Kristina Chodorow335f0672015-11-16 23:19:13 +0000638 "a = 'a'");
laurentlbc0bd2102018-10-17 07:05:25 -0700639 scratch.file(
gregce0503fee2020-06-11 09:22:27 -0700640 "test/starlark/BUILD",
641 "load('//test/starlark:extension.bzl', 'a')",
Kristina Chodorow335f0672015-11-16 23:19:13 +0000642 "genrule(name = gr,",
643 " outs = ['out.txt'],",
644 " cmd = 'echo hello >@')");
645 invalidatePackages();
646
gregce0503fee2020-06-11 09:22:27 -0700647 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//test/starlark"));
laurentlbc0bd2102018-10-17 07:05:25 -0700648 EvaluationResult<PackageValue> result =
649 SkyframeExecutorTestUtils.evaluate(
650 getSkyframeExecutor(), skyKey, /*keepGoing=*/ false, reporter);
lberkiaea56b32017-05-30 12:35:33 +0200651 assertThat(result.hasError()).isTrue();
Kristina Chodorow335f0672015-11-16 23:19:13 +0000652 ErrorInfo errorInfo = result.getError(skyKey);
653 assertThat(errorInfo.getException())
diamondmd6df9802019-03-19 06:53:43 -0700654 .hasMessageThat()
655 .isEqualTo(
gregce0503fee2020-06-11 09:22:27 -0700656 "error loading package 'test/starlark': "
657 + "in /workspace/test/starlark/extension.bzl: "
658 + "cannot load '//test/starlark:bad_extension.bzl': no such file");
Googler74178a52020-06-29 17:42:47 -0700659 assertDetailedExitCode(
660 errorInfo.getException(), PackageLoading.Code.IMPORT_STARLARK_FILE_ERROR);
Kristina Chodorow335f0672015-11-16 23:19:13 +0000661 }
662
Florian Weikert92b22362015-12-03 10:17:18 +0000663 @Test
gregceb100b1d2020-05-20 10:22:17 -0700664 public void testSymlinkCycleWithStarlarkExtension() throws Exception {
Kristina Chodorow335f0672015-11-16 23:19:13 +0000665 reporter.removeHandler(failFastHandler);
gregce0503fee2020-06-11 09:22:27 -0700666 Path extensionFilePath = scratch.resolve("/workspace/test/starlark/extension.bzl");
nharmatab4060b62017-04-04 17:11:39 +0000667 FileSystemUtils.ensureSymbolicLink(extensionFilePath, PathFragment.create("extension.bzl"));
laurentlbc0bd2102018-10-17 07:05:25 -0700668 scratch.file(
gregce0503fee2020-06-11 09:22:27 -0700669 "test/starlark/BUILD",
670 "load('//test/starlark:extension.bzl', 'a')",
Kristina Chodorow335f0672015-11-16 23:19:13 +0000671 "genrule(name = gr,",
672 " outs = ['out.txt'],",
673 " cmd = 'echo hello >@')");
674 invalidatePackages();
675
gregce0503fee2020-06-11 09:22:27 -0700676 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//test/starlark"));
laurentlbc0bd2102018-10-17 07:05:25 -0700677 EvaluationResult<PackageValue> result =
678 SkyframeExecutorTestUtils.evaluate(
679 getSkyframeExecutor(), skyKey, /*keepGoing=*/ false, reporter);
lberkiaea56b32017-05-30 12:35:33 +0200680 assertThat(result.hasError()).isTrue();
Kristina Chodorow335f0672015-11-16 23:19:13 +0000681 ErrorInfo errorInfo = result.getError(skyKey);
lberkiaea56b32017-05-30 12:35:33 +0200682 assertThat(errorInfo.getRootCauseOfException()).isEqualTo(skyKey);
Kristina Chodorow335f0672015-11-16 23:19:13 +0000683 assertThat(errorInfo.getException())
diamondmd6df9802019-03-19 06:53:43 -0700684 .hasMessageThat()
685 .isEqualTo(
gregce0503fee2020-06-11 09:22:27 -0700686 "error loading package 'test/starlark': Encountered error while reading extension "
687 + "file 'test/starlark/extension.bzl': Symlink cycle");
Googler74178a52020-06-29 17:42:47 -0700688 assertDetailedExitCode(
689 errorInfo.getException(), PackageLoading.Code.IMPORT_STARLARK_FILE_ERROR);
Kristina Chodorow335f0672015-11-16 23:19:13 +0000690 }
691
Florian Weikert92b22362015-12-03 10:17:18 +0000692 @Test
Kristina Chodorow335f0672015-11-16 23:19:13 +0000693 public void testIOErrorLookingForSubpackageForLabelIsHandled() throws Exception {
694 reporter.removeHandler(failFastHandler);
laurentlbc0bd2102018-10-17 07:05:25 -0700695 scratch.file("foo/BUILD", "sh_library(name = 'foo', srcs = ['bar/baz.sh'])");
Kristina Chodorow335f0672015-11-16 23:19:13 +0000696 Path barBuildFile = scratch.file("foo/bar/BUILD");
aehligc801c392017-12-19 07:12:25 -0800697 fs.stubStatError(barBuildFile, new IOException("nope"));
Brian Silvermand7d6d622016-03-17 09:53:39 +0000698 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//foo"));
laurentlbc0bd2102018-10-17 07:05:25 -0700699 EvaluationResult<PackageValue> result =
700 SkyframeExecutorTestUtils.evaluate(
701 getSkyframeExecutor(), skyKey, /*keepGoing=*/ false, reporter);
lberkiaea56b32017-05-30 12:35:33 +0200702 assertThat(result.hasError()).isTrue();
Kristina Chodorow335f0672015-11-16 23:19:13 +0000703 assertContainsEvent("nope");
704 }
705
Florian Weikert92b22362015-12-03 10:17:18 +0000706 @Test
Googler83439e62019-09-24 12:11:30 -0700707 public void testLoadOK() throws Exception {
708 scratch.file("p/a.bzl", "a = 1; b = 1; d = 1");
709 scratch.file("p/subdir/a.bzl", "c = 1; e = 1");
710 scratch.file(
711 "p/BUILD",
712 //
713 "load(':a.bzl', 'a')",
714 "load('a.bzl', 'b')",
715 "load('subdir/a.bzl', 'c')",
716 "load('//p:a.bzl', 'd')",
717 "load('//p:subdir/a.bzl', 'e')");
718 validPackageWithoutErrors(PackageValue.key(PackageIdentifier.parse("@//p")));
719 }
720
adonovane0bd9d32020-09-18 12:51:15 -0700721 // See WorkspaceFileFunctionTest for tests that exercise load('@repo...').
Googler83439e62019-09-24 12:11:30 -0700722
723 @Test
724 public void testLoadBadLabel() throws Exception {
725 scratch.file("p/BUILD", "load('this\tis not a label', 'a')");
726 reporter.removeHandler(failFastHandler);
727 SkyKey key = PackageValue.key(PackageIdentifier.parse("@//p"));
728 SkyframeExecutorTestUtils.evaluate(skyframeExecutor, key, /*keepGoing=*/ false, reporter);
729 assertContainsEvent(
730 "in load statement: invalid target name 'this<?>is not a label': target names may not"
731 + " contain non-printable characters");
Kristina Chodorow335f0672015-11-16 23:19:13 +0000732 }
733
Florian Weikert92b22362015-12-03 10:17:18 +0000734 @Test
Googler83439e62019-09-24 12:11:30 -0700735 public void testLoadFromExternalPackage() throws Exception {
736 scratch.file("p/BUILD", "load('//external:file.bzl', 'a')");
737 reporter.removeHandler(failFastHandler);
738 SkyKey key = PackageValue.key(PackageIdentifier.parse("@//p"));
739 SkyframeExecutorTestUtils.evaluate(skyframeExecutor, key, /*keepGoing=*/ false, reporter);
740 assertContainsEvent("Starlark files may not be loaded from the //external package");
741 }
742
743 @Test
744 public void testLoadWithoutBzlSuffix() throws Exception {
745 scratch.file("p/BUILD", "load('//p:file.starlark', 'a')");
746 reporter.removeHandler(failFastHandler);
747 SkyKey key = PackageValue.key(PackageIdentifier.parse("@//p"));
748 SkyframeExecutorTestUtils.evaluate(skyframeExecutor, key, /*keepGoing=*/ false, reporter);
749 assertContainsEvent("The label must reference a file with extension '.bzl'");
Kristina Chodorow335f0672015-11-16 23:19:13 +0000750 }
751
Florian Weikert92b22362015-12-03 10:17:18 +0000752 @Test
Kristina Chodorow335f0672015-11-16 23:19:13 +0000753 public void testBadWorkspaceFile() throws Exception {
754 Path workspacePath = scratch.overwriteFile("WORKSPACE", "junk");
Brian Silvermand7d6d622016-03-17 09:53:39 +0000755 SkyKey skyKey = PackageValue.key(PackageIdentifier.createInMainRepo("external"));
Kristina Chodorow335f0672015-11-16 23:19:13 +0000756 getSkyframeExecutor()
757 .invalidate(
758 Predicates.equalTo(
shahan602cc852018-06-06 20:09:57 -0700759 FileStateValue.key(
Kristina Chodorow335f0672015-11-16 23:19:13 +0000760 RootedPath.toRootedPath(
tomluee6a6862018-01-17 14:36:26 -0800761 Root.fromPath(workspacePath.getParentDirectory()),
nharmatab4060b62017-04-04 17:11:39 +0000762 PathFragment.create(workspacePath.getBaseName())))));
Kristina Chodorow335f0672015-11-16 23:19:13 +0000763
764 reporter.removeHandler(failFastHandler);
765 EvaluationResult<PackageValue> result =
766 SkyframeExecutorTestUtils.evaluate(
767 getSkyframeExecutor(), skyKey, /*keepGoing=*/ false, reporter);
lberkiaea56b32017-05-30 12:35:33 +0200768 assertThat(result.hasError()).isFalse();
769 assertThat(result.get(skyKey).getPackage().containsErrors()).isTrue();
Kristina Chodorow335f0672015-11-16 23:19:13 +0000770 }
771
Nathan Harmata2022ad82016-02-22 23:04:14 +0000772 // Regression test for the two ugly consequences of a bug where GlobFunction incorrectly matched
773 // dangling symlinks.
774 @Test
775 public void testIncrementalSkyframeHybridGlobbingOnDanglingSymlink() throws Exception {
laurentlbc0bd2102018-10-17 07:05:25 -0700776 Path packageDirPath =
777 scratch.file("foo/BUILD", "exports_files(glob(['*.txt']))").getParentDirectory();
Nathan Harmata2022ad82016-02-22 23:04:14 +0000778 scratch.file("foo/existing.txt");
779 FileSystemUtils.ensureSymbolicLink(packageDirPath.getChild("dangling.txt"), "nope");
780
Ulf Adamsc73051c62016-03-23 09:18:13 +0000781 preparePackageLoading(rootDirectory);
Nathan Harmata2022ad82016-02-22 23:04:14 +0000782
Brian Silvermand7d6d622016-03-17 09:53:39 +0000783 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//foo"));
nharmatac9fbe952019-06-13 09:39:23 -0700784 Package pkg = validPackageWithoutErrors(skyKey);
785 assertThat(pkg.containsErrors()).isFalse();
786 assertThat(pkg.getTarget("existing.txt").getName()).isEqualTo("existing.txt");
787 assertThrows(NoSuchTargetException.class, () -> pkg.getTarget("dangling.txt"));
Nathan Harmata2022ad82016-02-22 23:04:14 +0000788
laurentlbc0bd2102018-10-17 07:05:25 -0700789 scratch.overwriteFile(
790 "foo/BUILD", "exports_files(glob(['*.txt']))", "#some-irrelevant-comment");
Nathan Harmata2022ad82016-02-22 23:04:14 +0000791
tomluee6a6862018-01-17 14:36:26 -0800792 getSkyframeExecutor()
793 .invalidateFilesUnderPathForTesting(
794 reporter,
795 ModifiedFileSet.builder().modify(PathFragment.create("foo/BUILD")).build(),
796 Root.fromPath(rootDirectory));
Nathan Harmata2022ad82016-02-22 23:04:14 +0000797
nharmatac9fbe952019-06-13 09:39:23 -0700798 Package pkg2 = validPackageWithoutErrors(skyKey);
799 assertThat(pkg2.containsErrors()).isFalse();
800 assertThat(pkg2.getTarget("existing.txt").getName()).isEqualTo("existing.txt");
801 assertThrows(NoSuchTargetException.class, () -> pkg2.getTarget("dangling.txt"));
jcater83130f42019-04-30 14:29:28 -0700802 // One consequence of the bug was that dangling symlinks were matched by globs evaluated by
803 // Skyframe globbing, meaning there would incorrectly be corresponding targets in packages
804 // that had skyframe cache hits during skyframe hybrid globbing.
Nathan Harmata2022ad82016-02-22 23:04:14 +0000805
806 scratch.file("foo/nope");
tomluee6a6862018-01-17 14:36:26 -0800807 getSkyframeExecutor()
808 .invalidateFilesUnderPathForTesting(
809 reporter,
810 ModifiedFileSet.builder().modify(PathFragment.create("foo/nope")).build(),
811 Root.fromPath(rootDirectory));
Nathan Harmata2022ad82016-02-22 23:04:14 +0000812
nharmatac9fbe952019-06-13 09:39:23 -0700813 Package newPkg = validPackageWithoutErrors(skyKey);
814 assertThat(newPkg.containsErrors()).isFalse();
815 assertThat(newPkg.getTarget("existing.txt").getName()).isEqualTo("existing.txt");
Nathan Harmata2022ad82016-02-22 23:04:14 +0000816 // Another consequence of the bug is that change pruning would incorrectly cut off changes that
817 // caused a dangling symlink potentially matched by a glob to come into existence.
nharmatac9fbe952019-06-13 09:39:23 -0700818 assertThat(newPkg.getTarget("dangling.txt").getName()).isEqualTo("dangling.txt");
819 assertThat(newPkg).isNotSameInstanceAs(pkg);
Nathan Harmata2022ad82016-02-22 23:04:14 +0000820 }
821
Nathan Harmata86c319e2016-02-25 01:12:22 +0000822 // Regression test for Skyframe globbing incorrectly matching the package's directory path on
823 // 'glob(['**'], exclude_directories = 0)'. We test for this directly by triggering
824 // hybrid globbing (gives coverage for both legacy globbing and skyframe globbing).
825 @Test
826 public void testRecursiveGlobNeverMatchesPackageDirectory() throws Exception {
laurentlbc0bd2102018-10-17 07:05:25 -0700827 scratch.file(
828 "foo/BUILD",
Nathan Harmata86c319e2016-02-25 01:12:22 +0000829 "[sh_library(name = x + '-matched') for x in glob(['**'], exclude_directories = 0)]");
830 scratch.file("foo/bar");
831
Ulf Adamsc73051c62016-03-23 09:18:13 +0000832 preparePackageLoading(rootDirectory);
Nathan Harmata86c319e2016-02-25 01:12:22 +0000833
Brian Silvermand7d6d622016-03-17 09:53:39 +0000834 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//foo"));
nharmatac9fbe952019-06-13 09:39:23 -0700835 Package pkg = validPackageWithoutErrors(skyKey);
836 assertThat(pkg.containsErrors()).isFalse();
837 assertThat(pkg.getTarget("bar-matched").getName()).isEqualTo("bar-matched");
838 assertThrows(NoSuchTargetException.class, () -> pkg.getTarget("-matched"));
Nathan Harmata86c319e2016-02-25 01:12:22 +0000839
laurentlbc0bd2102018-10-17 07:05:25 -0700840 scratch.overwriteFile(
841 "foo/BUILD",
Nathan Harmata86c319e2016-02-25 01:12:22 +0000842 "[sh_library(name = x + '-matched') for x in glob(['**'], exclude_directories = 0)]",
843 "#some-irrelevant-comment");
tomluee6a6862018-01-17 14:36:26 -0800844 getSkyframeExecutor()
845 .invalidateFilesUnderPathForTesting(
846 reporter,
847 ModifiedFileSet.builder().modify(PathFragment.create("foo/BUILD")).build(),
848 Root.fromPath(rootDirectory));
Nathan Harmata86c319e2016-02-25 01:12:22 +0000849
nharmatac9fbe952019-06-13 09:39:23 -0700850 Package pkg2 = validPackageWithoutErrors(skyKey);
851 assertThat(pkg2.containsErrors()).isFalse();
852 assertThat(pkg2.getTarget("bar-matched").getName()).isEqualTo("bar-matched");
853 assertThrows(NoSuchTargetException.class, () -> pkg2.getTarget("-matched"));
Nathan Harmata86c319e2016-02-25 01:12:22 +0000854 }
855
nharmataff688bf2017-06-07 17:03:52 -0400856 @Test
857 public void testPackageLoadingErrorOnIOExceptionReadingBuildFile() throws Exception {
858 Path fooBuildFilePath = scratch.file("foo/BUILD");
859 IOException exn = new IOException("nope");
aehligc801c392017-12-19 07:12:25 -0800860 fs.throwExceptionOnGetInputStream(fooBuildFilePath, exn);
nharmataff688bf2017-06-07 17:03:52 -0400861
862 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//foo"));
laurentlbc0bd2102018-10-17 07:05:25 -0700863 EvaluationResult<PackageValue> result =
864 SkyframeExecutorTestUtils.evaluate(
865 getSkyframeExecutor(), skyKey, /*keepGoing=*/ false, reporter);
nharmataff688bf2017-06-07 17:03:52 -0400866 assertThat(result.hasError()).isTrue();
867 ErrorInfo errorInfo = result.getError(skyKey);
868 String errorMessage = errorInfo.getException().getMessage();
869 assertThat(errorMessage).contains("nope");
870 assertThat(errorInfo.getException()).isInstanceOf(NoSuchPackageException.class);
nharmata351efff2018-03-30 15:04:38 -0700871 assertThat(errorInfo.getException()).hasCauseThat().isInstanceOf(IOException.class);
Googler74178a52020-06-29 17:42:47 -0700872 assertDetailedExitCode(errorInfo.getException(), PackageLoading.Code.BUILD_FILE_MISSING);
nharmataff688bf2017-06-07 17:03:52 -0400873 }
874
nharmatabea67e92017-06-16 00:26:27 +0200875 @Test
876 public void testPackageLoadingErrorOnIOExceptionReadingBzlFile() throws Exception {
877 scratch.file("foo/BUILD", "load('//foo:bzl.bzl', 'x')");
878 Path fooBzlFilePath = scratch.file("foo/bzl.bzl");
879 IOException exn = new IOException("nope");
aehligc801c392017-12-19 07:12:25 -0800880 fs.throwExceptionOnGetInputStream(fooBzlFilePath, exn);
nharmatabea67e92017-06-16 00:26:27 +0200881
882 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//foo"));
laurentlbc0bd2102018-10-17 07:05:25 -0700883 EvaluationResult<PackageValue> result =
884 SkyframeExecutorTestUtils.evaluate(
885 getSkyframeExecutor(), skyKey, /*keepGoing=*/ false, reporter);
nharmatabea67e92017-06-16 00:26:27 +0200886 assertThat(result.hasError()).isTrue();
887 ErrorInfo errorInfo = result.getError(skyKey);
888 String errorMessage = errorInfo.getException().getMessage();
889 assertThat(errorMessage).contains("nope");
890 assertThat(errorInfo.getException()).isInstanceOf(NoSuchPackageException.class);
nharmata351efff2018-03-30 15:04:38 -0700891 assertThat(errorInfo.getException()).hasCauseThat().isInstanceOf(IOException.class);
Googler74178a52020-06-29 17:42:47 -0700892 assertDetailedExitCode(
893 errorInfo.getException(), PackageLoading.Code.IMPORT_STARLARK_FILE_ERROR);
nharmatabea67e92017-06-16 00:26:27 +0200894 }
895
nharmata58613102018-10-11 15:10:04 -0700896 @Test
897 public void testLabelsCrossesSubpackageBoundaries() throws Exception {
898 reporter.removeHandler(failFastHandler);
899
900 scratch.file("pkg/BUILD", "exports_files(['sub/blah'])");
901 scratch.file("pkg/sub/BUILD");
902 invalidatePackages();
903
904 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//pkg"));
laurentlbc0bd2102018-10-17 07:05:25 -0700905 EvaluationResult<PackageValue> result =
906 SkyframeExecutorTestUtils.evaluate(
907 getSkyframeExecutor(), skyKey, /*keepGoing=*/ false, reporter);
nharmata58613102018-10-11 15:10:04 -0700908 assertThatEvaluationResult(result).hasNoError();
909 assertThat(result.get(skyKey).getPackage().containsErrors()).isTrue();
laurentlbaf489f22019-07-29 08:19:03 -0700910 assertContainsEvent("Label '//pkg:sub/blah' is invalid because 'pkg/sub' is a subpackage");
nharmata58613102018-10-11 15:10:04 -0700911 }
912
913 @Test
914 public void testSymlinkCycleEncounteredWhileHandlingLabelCrossingSubpackageBoundaries()
915 throws Exception {
916 reporter.removeHandler(failFastHandler);
917
918 scratch.file("pkg/BUILD", "exports_files(['sub/blah'])");
919 Path subBuildFilePath = scratch.dir("pkg/sub").getChild("BUILD");
920 FileSystemUtils.ensureSymbolicLink(subBuildFilePath, subBuildFilePath);
921 invalidatePackages();
922
923 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//pkg"));
laurentlbc0bd2102018-10-17 07:05:25 -0700924 EvaluationResult<PackageValue> result =
925 SkyframeExecutorTestUtils.evaluate(
926 getSkyframeExecutor(), skyKey, /*keepGoing=*/ false, reporter);
nharmata58613102018-10-11 15:10:04 -0700927 assertThatEvaluationResult(result).hasError();
928 assertThatEvaluationResult(result)
929 .hasErrorEntryForKeyThat(skyKey)
930 .hasExceptionThat()
931 .isInstanceOf(BuildFileNotFoundException.class);
932 assertThatEvaluationResult(result)
933 .hasErrorEntryForKeyThat(skyKey)
934 .hasExceptionThat()
935 .hasMessageThat()
936 .contains(
937 "no such package 'pkg/sub': Symlink cycle detected while trying to find BUILD file");
938 assertContainsEvent("circular symlinks detected");
939 }
940
nharmatac9fbe952019-06-13 09:39:23 -0700941 @Test
jmmvbfbd95f2020-08-31 13:12:38 -0700942 public void testGlobAllowEmpty_paramValueMustBeBoolean() throws Exception {
nharmatac9fbe952019-06-13 09:39:23 -0700943 reporter.removeHandler(failFastHandler);
944
945 scratch.file("pkg/BUILD", "x = " + "glob(['*.foo'], allow_empty = 5)");
946 invalidatePackages();
947
948 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//pkg"));
michajloc17b80e2020-07-20 10:00:28 -0700949 validPackage(skyKey);
nharmatac9fbe952019-06-13 09:39:23 -0700950
michajloc17b80e2020-07-20 10:00:28 -0700951 assertContainsEvent("expected boolean for argument `allow_empty`, got `5`");
nharmatac9fbe952019-06-13 09:39:23 -0700952 }
953
954 @Test
jmmvbfbd95f2020-08-31 13:12:38 -0700955 public void testGlobAllowEmpty_functionParam() throws Exception {
nharmatac9fbe952019-06-13 09:39:23 -0700956 scratch.file("pkg/BUILD", "x = " + "glob(['*.foo'], allow_empty=True)");
957 invalidatePackages();
958
959 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//pkg"));
960 Package pkg = validPackage(skyKey);
961 assertThat(pkg.containsErrors()).isFalse();
michajloc17b80e2020-07-20 10:00:28 -0700962 assertNoEvents();
nharmatac9fbe952019-06-13 09:39:23 -0700963 }
964
965 @Test
jmmvbfbd95f2020-08-31 13:12:38 -0700966 public void testGlobAllowEmpty_starlarkOption() throws Exception {
nharmatac9fbe952019-06-13 09:39:23 -0700967 preparePackageLoadingWithCustomStarklarkSemanticsOptions(
adonovan240bdea2020-09-03 15:24:12 -0700968 Options.parse(BuildLanguageOptions.class, "--incompatible_disallow_empty_glob=false")
nharmatac9fbe952019-06-13 09:39:23 -0700969 .getOptions(),
970 rootDirectory);
971
972 scratch.file("pkg/BUILD", "x = " + "glob(['*.foo'])");
973 invalidatePackages();
974
975 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//pkg"));
976 Package pkg = validPackage(skyKey);
977 assertThat(pkg.containsErrors()).isFalse();
michajloc17b80e2020-07-20 10:00:28 -0700978 assertNoEvents();
nharmatac9fbe952019-06-13 09:39:23 -0700979 }
980
981 @Test
jmmvbfbd95f2020-08-31 13:12:38 -0700982 public void testGlobDisallowEmpty_functionParam_wasNonEmptyAndBecomesEmpty() throws Exception {
nharmatac9fbe952019-06-13 09:39:23 -0700983 scratch.file("pkg/BUILD", "x = " + "glob(['*.foo'], allow_empty=False)");
984 scratch.file("pkg/blah.foo");
985 invalidatePackages();
986
987 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//pkg"));
988
989 Package pkg = validPackage(skyKey);
990 assertThat(pkg.containsErrors()).isFalse();
michajloc17b80e2020-07-20 10:00:28 -0700991 assertNoEvents();
nharmatac9fbe952019-06-13 09:39:23 -0700992
993 scratch.deleteFile("pkg/blah.foo");
994 getSkyframeExecutor()
995 .invalidateFilesUnderPathForTesting(
996 reporter,
997 ModifiedFileSet.builder().modify(PathFragment.create("pkg/blah.foo")).build(),
998 Root.fromPath(rootDirectory));
999
1000 reporter.removeHandler(failFastHandler);
1001 pkg = validPackage(skyKey);
1002 assertThat(pkg.containsErrors()).isTrue();
michajloc17b80e2020-07-20 10:00:28 -07001003 assertContainsEvent(
laurentlb7679c302020-07-17 03:16:11 -07001004 "glob pattern '*.foo' didn't match anything, but allow_empty is set to False (the "
michajloc17b80e2020-07-20 10:00:28 -07001005 + "default value of allow_empty can be set with --incompatible_disallow_empty_glob).");
nharmatac9fbe952019-06-13 09:39:23 -07001006 }
1007
1008 @Test
jmmvbfbd95f2020-08-31 13:12:38 -07001009 public void testGlobDisallowEmpty_starlarkOption_wasNonEmptyAndBecomesEmpty() throws Exception {
nharmatac9fbe952019-06-13 09:39:23 -07001010 preparePackageLoadingWithCustomStarklarkSemanticsOptions(
adonovan240bdea2020-09-03 15:24:12 -07001011 Options.parse(BuildLanguageOptions.class, "--incompatible_disallow_empty_glob=true")
nharmatac9fbe952019-06-13 09:39:23 -07001012 .getOptions(),
1013 rootDirectory);
1014
1015 scratch.file("pkg/BUILD", "x = " + "glob(['*.foo'])");
1016 scratch.file("pkg/blah.foo");
1017 invalidatePackages();
1018
1019 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//pkg"));
1020
1021 Package pkg = validPackage(skyKey);
1022 assertThat(pkg.containsErrors()).isFalse();
michajloc17b80e2020-07-20 10:00:28 -07001023 assertNoEvents();
nharmatac9fbe952019-06-13 09:39:23 -07001024
1025 scratch.deleteFile("pkg/blah.foo");
1026 getSkyframeExecutor()
1027 .invalidateFilesUnderPathForTesting(
1028 reporter,
1029 ModifiedFileSet.builder().modify(PathFragment.create("pkg/blah.foo")).build(),
1030 Root.fromPath(rootDirectory));
1031
1032 reporter.removeHandler(failFastHandler);
1033 pkg = validPackage(skyKey);
1034 assertThat(pkg.containsErrors()).isTrue();
michajloc17b80e2020-07-20 10:00:28 -07001035 assertContainsEvent(
laurentlb7679c302020-07-17 03:16:11 -07001036 "glob pattern '*.foo' didn't match anything, but allow_empty is set to False (the "
michajloc17b80e2020-07-20 10:00:28 -07001037 + "default value of allow_empty can be set with --incompatible_disallow_empty_glob).");
nharmatac9fbe952019-06-13 09:39:23 -07001038 }
1039
1040 @Test
jmmvbfbd95f2020-08-31 13:12:38 -07001041 public void testGlobDisallowEmpty_functionParam_wasEmptyAndStaysEmpty() throws Exception {
nharmatac9fbe952019-06-13 09:39:23 -07001042 scratch.file("pkg/BUILD", "x = " + "glob(['*.foo'], allow_empty=False)");
1043 invalidatePackages();
1044
1045 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//pkg"));
1046 reporter.removeHandler(failFastHandler);
1047
1048 Package pkg = validPackage(skyKey);
1049 assertThat(pkg.containsErrors()).isTrue();
1050 String expectedEventString =
laurentlb7679c302020-07-17 03:16:11 -07001051 "glob pattern '*.foo' didn't match anything, but allow_empty is set to False (the "
1052 + "default value of allow_empty can be set with --incompatible_disallow_empty_glob).";
nharmatac9fbe952019-06-13 09:39:23 -07001053 assertContainsEvent(expectedEventString);
1054
1055 scratch.overwriteFile("pkg/BUILD", "x = " + "glob(['*.foo'], allow_empty=False) #comment");
1056 getSkyframeExecutor()
1057 .invalidateFilesUnderPathForTesting(
1058 reporter,
1059 ModifiedFileSet.builder().modify(PathFragment.create("pkg/BUILD")).build(),
1060 Root.fromPath(rootDirectory));
1061
1062 pkg = validPackage(skyKey);
1063 assertThat(pkg.containsErrors()).isTrue();
nharmatac9fbe952019-06-13 09:39:23 -07001064 assertContainsEvent(expectedEventString);
1065 }
1066
1067 @Test
jmmvbfbd95f2020-08-31 13:12:38 -07001068 public void testGlobDisallowEmpty_starlarkOption_wasEmptyAndStaysEmpty() throws Exception {
nharmatac9fbe952019-06-13 09:39:23 -07001069 preparePackageLoadingWithCustomStarklarkSemanticsOptions(
adonovan240bdea2020-09-03 15:24:12 -07001070 Options.parse(BuildLanguageOptions.class, "--incompatible_disallow_empty_glob=true")
nharmatac9fbe952019-06-13 09:39:23 -07001071 .getOptions(),
1072 rootDirectory);
1073
1074 scratch.file("pkg/BUILD", "x = " + "glob(['*.foo'])");
1075 invalidatePackages();
1076
1077 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//pkg"));
1078 reporter.removeHandler(failFastHandler);
1079
1080 Package pkg = validPackage(skyKey);
1081 assertThat(pkg.containsErrors()).isTrue();
1082 String expectedEventString =
laurentlb7679c302020-07-17 03:16:11 -07001083 "glob pattern '*.foo' didn't match anything, but allow_empty is set to False (the "
1084 + "default value of allow_empty can be set with --incompatible_disallow_empty_glob).";
nharmatac9fbe952019-06-13 09:39:23 -07001085 assertContainsEvent(expectedEventString);
1086
1087 scratch.overwriteFile("pkg/BUILD", "x = " + "glob(['*.foo']) #comment");
1088 getSkyframeExecutor()
1089 .invalidateFilesUnderPathForTesting(
1090 reporter,
1091 ModifiedFileSet.builder().modify(PathFragment.create("pkg/BUILD")).build(),
1092 Root.fromPath(rootDirectory));
1093
1094 pkg = validPackage(skyKey);
1095 assertThat(pkg.containsErrors()).isTrue();
nharmatac9fbe952019-06-13 09:39:23 -07001096 assertContainsEvent(expectedEventString);
1097 }
1098
1099 @Test
jmmvbfbd95f2020-08-31 13:12:38 -07001100 public void testGlobDisallowEmpty_functionParam_wasEmptyDueToExcludeAndStaysEmpty()
nharmatac9fbe952019-06-13 09:39:23 -07001101 throws Exception {
1102 scratch.file("pkg/BUILD", "x = glob(include=['*.foo'], exclude=['blah.*'], allow_empty=False)");
1103 scratch.file("pkg/blah.foo");
1104 invalidatePackages();
1105
1106 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//pkg"));
1107 reporter.removeHandler(failFastHandler);
1108
1109 Package pkg = validPackage(skyKey);
1110 assertThat(pkg.containsErrors()).isTrue();
1111 String expectedEventString =
laurentlb7679c302020-07-17 03:16:11 -07001112 "all files in the glob have been excluded, but allow_empty is set to False (the "
1113 + "default value of allow_empty can be set with --incompatible_disallow_empty_glob).";
nharmatac9fbe952019-06-13 09:39:23 -07001114 assertContainsEvent(expectedEventString);
1115
1116 scratch.overwriteFile(
1117 "pkg/BUILD",
1118 "x = glob(include=['*.foo'], exclude=['blah.*'], allow_empty=False) # comment");
1119 getSkyframeExecutor()
1120 .invalidateFilesUnderPathForTesting(
1121 reporter,
1122 ModifiedFileSet.builder().modify(PathFragment.create("pkg/BUILD")).build(),
1123 Root.fromPath(rootDirectory));
1124
1125 pkg = validPackage(skyKey);
1126 assertThat(pkg.containsErrors()).isTrue();
nharmatac9fbe952019-06-13 09:39:23 -07001127 assertContainsEvent(expectedEventString);
1128 }
1129
1130 @Test
jmmvbfbd95f2020-08-31 13:12:38 -07001131 public void testGlobDisallowEmpty_starlarkOption_wasEmptyDueToExcludeAndStaysEmpty()
nharmatac9fbe952019-06-13 09:39:23 -07001132 throws Exception {
1133 preparePackageLoadingWithCustomStarklarkSemanticsOptions(
adonovan240bdea2020-09-03 15:24:12 -07001134 Options.parse(BuildLanguageOptions.class, "--incompatible_disallow_empty_glob=true")
nharmatac9fbe952019-06-13 09:39:23 -07001135 .getOptions(),
1136 rootDirectory);
1137
1138 scratch.file("pkg/BUILD", "x = glob(include=['*.foo'], exclude=['blah.*'])");
1139 scratch.file("pkg/blah.foo");
1140 invalidatePackages();
1141
1142 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//pkg"));
1143 reporter.removeHandler(failFastHandler);
1144
1145 Package pkg = validPackage(skyKey);
1146 assertThat(pkg.containsErrors()).isTrue();
1147 String expectedEventString =
laurentlb7679c302020-07-17 03:16:11 -07001148 "all files in the glob have been excluded, but allow_empty is set to False (the "
1149 + "default value of allow_empty can be set with --incompatible_disallow_empty_glob).";
nharmatac9fbe952019-06-13 09:39:23 -07001150 assertContainsEvent(expectedEventString);
1151
1152 scratch.overwriteFile("pkg/BUILD", "x = glob(include=['*.foo'], exclude=['blah.*']) # comment");
1153 getSkyframeExecutor()
1154 .invalidateFilesUnderPathForTesting(
1155 reporter,
1156 ModifiedFileSet.builder().modify(PathFragment.create("pkg/BUILD")).build(),
1157 Root.fromPath(rootDirectory));
1158
1159 pkg = validPackage(skyKey);
1160 assertThat(pkg.containsErrors()).isTrue();
nharmatac9fbe952019-06-13 09:39:23 -07001161 assertContainsEvent(expectedEventString);
1162 }
1163
1164 @Test
jmmvbfbd95f2020-08-31 13:12:38 -07001165 public void testGlobDisallowEmpty_functionParam_wasEmptyAndBecomesNonEmpty() throws Exception {
nharmatac9fbe952019-06-13 09:39:23 -07001166 scratch.file("pkg/BUILD", "x = " + "glob(['*.foo'], allow_empty=False)");
1167 invalidatePackages();
1168
1169 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//pkg"));
1170
1171 reporter.removeHandler(failFastHandler);
1172 Package pkg = validPackage(skyKey);
1173 assertThat(pkg.containsErrors()).isTrue();
michajloc17b80e2020-07-20 10:00:28 -07001174 assertContainsEvent(
laurentlb7679c302020-07-17 03:16:11 -07001175 "glob pattern '*.foo' didn't match anything, but allow_empty is set to False (the "
michajloc17b80e2020-07-20 10:00:28 -07001176 + "default value of allow_empty can be set with --incompatible_disallow_empty_glob).");
nharmatac9fbe952019-06-13 09:39:23 -07001177
1178 scratch.file("pkg/blah.foo");
1179 getSkyframeExecutor()
1180 .invalidateFilesUnderPathForTesting(
1181 reporter,
1182 ModifiedFileSet.builder().modify(PathFragment.create("pkg/blah.foo")).build(),
1183 Root.fromPath(rootDirectory));
1184
1185 reporter.addHandler(failFastHandler);
michajloc17b80e2020-07-20 10:00:28 -07001186 eventCollector.clear();
nharmatac9fbe952019-06-13 09:39:23 -07001187 pkg = validPackage(skyKey);
1188 assertThat(pkg.containsErrors()).isFalse();
michajloc17b80e2020-07-20 10:00:28 -07001189 assertNoEvents();
nharmatac9fbe952019-06-13 09:39:23 -07001190 }
1191
1192 @Test
jmmvbfbd95f2020-08-31 13:12:38 -07001193 public void testGlobDisallowEmpty_starlarkOption_wasEmptyAndBecomesNonEmpty() throws Exception {
nharmatac9fbe952019-06-13 09:39:23 -07001194 preparePackageLoadingWithCustomStarklarkSemanticsOptions(
adonovan240bdea2020-09-03 15:24:12 -07001195 Options.parse(BuildLanguageOptions.class, "--incompatible_disallow_empty_glob=true")
nharmatac9fbe952019-06-13 09:39:23 -07001196 .getOptions(),
1197 rootDirectory);
1198
1199 scratch.file("pkg/BUILD", "x = " + "glob(['*.foo'])");
1200 invalidatePackages();
1201
1202 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//pkg"));
1203
1204 reporter.removeHandler(failFastHandler);
1205 Package pkg = validPackage(skyKey);
1206 assertThat(pkg.containsErrors()).isTrue();
michajloc17b80e2020-07-20 10:00:28 -07001207
1208 assertContainsEvent(
laurentlb7679c302020-07-17 03:16:11 -07001209 "glob pattern '*.foo' didn't match anything, but allow_empty is set to False (the "
michajloc17b80e2020-07-20 10:00:28 -07001210 + "default value of allow_empty can be set with --incompatible_disallow_empty_glob).");
nharmatac9fbe952019-06-13 09:39:23 -07001211
1212 scratch.file("pkg/blah.foo");
1213 getSkyframeExecutor()
1214 .invalidateFilesUnderPathForTesting(
1215 reporter,
1216 ModifiedFileSet.builder().modify(PathFragment.create("pkg/blah.foo")).build(),
1217 Root.fromPath(rootDirectory));
1218
1219 reporter.addHandler(failFastHandler);
michajloc17b80e2020-07-20 10:00:28 -07001220 eventCollector.clear();
nharmatac9fbe952019-06-13 09:39:23 -07001221 pkg = validPackage(skyKey);
1222 assertThat(pkg.containsErrors()).isFalse();
michajloc17b80e2020-07-20 10:00:28 -07001223 assertNoEvents();
nharmatac9fbe952019-06-13 09:39:23 -07001224 }
1225
Benjamin Peterson723eca62019-07-22 17:24:10 -07001226 @Test
adonovan87b46082020-07-08 15:58:04 -07001227 public void testPackageRecordsLoadedModules() throws Exception {
1228 scratch.file("p/BUILD", "load('a.bzl', 'a'); load(':b.bzl', 'b')");
1229 scratch.file("p/a.bzl", "load('c.bzl', 'c'); a = c");
1230 scratch.file("p/b.bzl", "load(':c.bzl', 'c'); b = c");
1231 scratch.file("p/c.bzl", "c = 0");
1232
1233 // load p
1234 preparePackageLoading(rootDirectory);
1235 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//p"));
1236 Package p = validPackageWithoutErrors(skyKey);
1237
1238 // Keys are load strings as they appear in the source (notice ":" in one of them).
1239 Map<String, Module> pLoads = p.getLoads();
1240 assertThat(pLoads.keySet().toString()).isEqualTo("[a.bzl, :b.bzl]");
1241
1242 // subgraph a
1243 Module a = pLoads.get("a.bzl");
1244 assertThat(a.toString()).isEqualTo("<module //p:a.bzl>");
1245 Map<String, Module> aLoads = BazelModuleContext.of(a).loads();
1246 assertThat(aLoads.keySet().toString()).isEqualTo("[c.bzl]");
1247 Module cViaA = aLoads.get("c.bzl");
1248 assertThat(cViaA.toString()).isEqualTo("<module //p:c.bzl>");
1249
1250 // subgraph b
1251 Module b = pLoads.get(":b.bzl");
1252 assertThat(b.toString()).isEqualTo("<module //p:b.bzl>");
1253 Map<String, Module> bLoads = BazelModuleContext.of(b).loads();
1254 assertThat(bLoads.keySet().toString()).isEqualTo("[:c.bzl]");
1255 Module cViaB = bLoads.get(":c.bzl");
1256 assertThat(cViaB).isSameInstanceAs(cViaA);
1257
adonovan3ed7ed52020-09-30 12:03:28 -07001258 assertThat(cViaA.getGlobal("c")).isEqualTo(StarlarkInt.of(0));
adonovan87b46082020-07-08 15:58:04 -07001259 }
1260
1261 @Test
Benjamin Peterson723eca62019-07-22 17:24:10 -07001262 public void veryBrokenPackagePostsDoneToProgressReceiver() throws Exception {
1263 reporter.removeHandler(failFastHandler);
1264
1265 scratch.file("pkg/BUILD", "load('//does_not:exist.bzl', 'broken'");
1266 SkyKey key = PackageValue.key(PackageIdentifier.parse("@//pkg"));
1267 EvaluationResult<PackageValue> result =
1268 SkyframeExecutorTestUtils.evaluate(getSkyframeExecutor(), key, false, reporter);
1269 assertThatEvaluationResult(result).hasError();
1270 assertThat(getSkyframeExecutor().getPackageProgressReceiver().progressState())
1271 .isEqualTo(new Pair<String, String>("1 packages loaded", ""));
1272 }
1273
nharmatace0335a2019-11-13 15:48:05 -08001274 @Test
1275 public void testLegacyGlobbingEncountersSymlinkCycleAndThrowsIOException() throws Exception {
1276 reporter.removeHandler(failFastHandler);
1277 getSkyframeExecutor().turnOffSyscallCacheForTesting();
1278
1279 // When a package's BUILD file and the relevant filesystem state is such that legacy globbing
1280 // will encounter an IOException due to a directory symlink cycle,
1281 Path fooBUILDPath = scratch.file("foo/BUILD", "glob(['cycle/**/foo.txt'])");
1282 Path fooCyclePath = fooBUILDPath.getParentDirectory().getChild("cycle");
1283 FileSystemUtils.ensureSymbolicLink(fooCyclePath, fooCyclePath);
1284 IOException ioExnFromFS =
1285 assertThrows(IOException.class, () -> fooCyclePath.statIfFound(Symlinks.FOLLOW));
1286 // And it is indeed the case that the FileSystem throws an IOException when the cycle's Path is
1287 // stat'd (following symlinks, as legacy globbing does).
1288 assertThat(ioExnFromFS).hasMessageThat().contains("Too many levels of symbolic links");
1289
1290 // Then, when we evaluate the PackageValue node for the Package in keepGoing mode,
1291 SkyKey pkgKey = PackageValue.key(PackageIdentifier.parse("@//foo"));
1292 EvaluationResult<PackageValue> result =
1293 SkyframeExecutorTestUtils.evaluate(
1294 getSkyframeExecutor(), pkgKey, /*keepGoing=*/ true, reporter);
1295 // The result is a *non-transient* Skyframe error.
1296 assertThatEvaluationResult(result).hasErrorEntryForKeyThat(pkgKey).isNotTransient();
1297 // And that error is a NoSuchPackageException
1298 assertThatEvaluationResult(result)
1299 .hasErrorEntryForKeyThat(pkgKey)
1300 .hasExceptionThat()
1301 .isInstanceOf(NoSuchPackageException.class);
1302 // With a useful error message,
1303 assertThatEvaluationResult(result)
1304 .hasErrorEntryForKeyThat(pkgKey)
1305 .hasExceptionThat()
1306 .hasMessageThat()
1307 .contains("Symlink cycle: /workspace/foo/cycle");
1308 // And appropriate Skyframe root cause (N.B. since we want PackageFunction to rethrow in
1309 // situations like this, we want the PackageValue node to be its own root cause).
1310 assertThatEvaluationResult(result)
1311 .hasErrorEntryForKeyThat(pkgKey)
1312 .rootCauseOfExceptionIs(pkgKey);
1313
1314 // Then, when we modify the BUILD file so as to force package loading,
1315 scratch.overwriteFile(
1316 "foo/BUILD", "glob(['cycle/**/foo.txt']) # dummy comment to force package loading");
1317 // But we don't make any filesystem changes that would invalidate the GlobValues, meaning that
1318 // PackageFunction will observe cache hits from Skyframe globbing,
1319 //
1320 // And we also have our filesystem blow up if the directory symlink cycle is encountered (thus,
1321 // the absence of a crash indicates the lack of legacy globbing),
1322 fs.stubStatError(
1323 fooCyclePath,
1324 new IOException() {
1325 @Override
1326 public String getMessage() {
1327 throw new IllegalStateException("should't get here!");
1328 }
1329 });
1330 // And we evaluate the PackageValue node for the Package in keepGoing mode,
1331 getSkyframeExecutor()
1332 .invalidateFilesUnderPathForTesting(
1333 reporter,
1334 ModifiedFileSet.builder().modify(PathFragment.create("foo/BUILD")).build(),
1335 Root.fromPath(rootDirectory));
1336 // The results are exactly the same as before,
1337 result =
1338 SkyframeExecutorTestUtils.evaluate(
1339 getSkyframeExecutor(), pkgKey, /*keepGoing=*/ true, reporter);
1340 assertThatEvaluationResult(result).hasErrorEntryForKeyThat(pkgKey).isNotTransient();
1341 assertThatEvaluationResult(result)
1342 .hasErrorEntryForKeyThat(pkgKey)
1343 .hasExceptionThat()
1344 .isInstanceOf(NoSuchPackageException.class);
1345 assertThatEvaluationResult(result)
1346 .hasErrorEntryForKeyThat(pkgKey)
1347 .hasExceptionThat()
1348 .hasMessageThat()
1349 .contains("Symlink cycle: /workspace/foo/cycle");
1350 assertThatEvaluationResult(result)
1351 .hasErrorEntryForKeyThat(pkgKey)
1352 .rootCauseOfExceptionIs(pkgKey);
1353 // Thus showing that clean and incremental package loading have the same semantics in the
1354 // presence of a symlink cycle encountered during glob evaluation.
1355 }
1356
Googler74178a52020-06-29 17:42:47 -07001357 private static void assertDetailedExitCode(
1358 Exception exception, PackageLoading.Code expectedPackageLoadingCode) {
1359 assertThat(exception).isInstanceOf(DetailedException.class);
1360 DetailedExitCode detailedExitCode = ((DetailedException) exception).getDetailedExitCode();
1361 assertThat(detailedExitCode.getExitCode()).isEqualTo(ExitCode.BUILD_FAILURE);
1362 assertThat(detailedExitCode.getFailureDetail().getPackageLoading().getCode())
1363 .isEqualTo(expectedPackageLoadingCode);
1364 }
1365
brandjon38dafdd2020-08-06 09:49:13 -07001366 /**
1367 * Tests of the prelude file functionality.
1368 *
1369 * <p>This is in a separate BuildViewTestCase because we override the prelude label for the test.
1370 * (The prelude label is configured differently between Bazel and Blaze.)
1371 */
1372 @RunWith(JUnit4.class)
1373 public static class PreludeTest extends BuildViewTestCase {
1374
1375 private final CustomInMemoryFs fs = new CustomInMemoryFs(new ManualClock());
1376
1377 @Override
1378 protected FileSystem createFileSystem() {
1379 return fs;
1380 }
1381
1382 @Override
1383 protected ConfiguredRuleClassProvider createRuleClassProvider() {
1384 ConfiguredRuleClassProvider.Builder builder = new ConfiguredRuleClassProvider.Builder();
1385 // addStandardRules() may call setPrelude(), so do it first.
1386 TestRuleClassProvider.addStandardRules(builder);
1387 builder.setPrelude("//tools/build_rules:test_prelude");
1388 return builder.build();
1389 }
1390
1391 @Test
1392 public void testPreludeDefinedSymbolIsUsable() throws Exception {
1393 scratch.file("tools/build_rules/BUILD");
1394 scratch.file(
1395 "tools/build_rules/test_prelude", //
1396 "foo = 'FOO'");
1397 scratch.file(
1398 "pkg/BUILD", //
1399 "print(foo)");
1400
1401 getConfiguredTarget("//pkg:BUILD");
1402 assertContainsEvent("FOO");
1403 }
1404
1405 @Test
1406 public void testPreludeAutomaticallyReexportsLoadedSymbols() throws Exception {
1407 scratch.file("tools/build_rules/BUILD");
1408 scratch.file(
1409 "tools/build_rules/test_prelude", //
1410 "load('//util:common.bzl', 'foo')");
1411 scratch.file("util/BUILD");
1412 scratch.file(
1413 "util/common.bzl", //
1414 "foo = 'FOO'");
1415 scratch.file(
1416 "pkg/BUILD", //
1417 "print(foo)");
1418
1419 getConfiguredTarget("//pkg:BUILD");
1420 assertContainsEvent("FOO");
1421 }
1422
1423 // TODO(brandjon): Invert this test once the prelude is a module instead of a syntactic
1424 // mutation on BUILD files.
1425 @Test
1426 public void testPreludeCanExportUnderscoreSymbols() throws Exception {
1427 scratch.file("tools/build_rules/BUILD");
1428 scratch.file(
1429 "tools/build_rules/test_prelude", //
1430 "_foo = 'FOO'");
1431 scratch.file(
1432 "pkg/BUILD", //
1433 "print(_foo)");
1434
1435 getConfiguredTarget("//pkg:BUILD");
1436 assertContainsEvent("FOO");
1437 }
1438
1439 @Test
1440 public void testPreludeCanShadowPredeclareds() throws Exception {
1441 scratch.file("tools/build_rules/BUILD");
1442 scratch.file(
1443 "tools/build_rules/test_prelude", //
1444 "cc_library = 'FOO'");
1445 scratch.file(
1446 "pkg/BUILD", //
1447 "print(cc_library)");
1448
1449 getConfiguredTarget("//pkg:BUILD");
1450 assertContainsEvent("FOO");
1451 }
1452
brandjon38dafdd2020-08-06 09:49:13 -07001453 @Test
brandjon2a73a732020-08-08 06:41:14 -07001454 public void testPreludeSymbolCannotBeMutated() throws Exception {
brandjon38dafdd2020-08-06 09:49:13 -07001455 scratch.file("tools/build_rules/BUILD");
1456 scratch.file(
1457 "tools/build_rules/test_prelude", //
1458 "foo = ['FOO']");
1459 scratch.file(
1460 "pkg/BUILD", //
brandjon2a73a732020-08-08 06:41:14 -07001461 "foo.append('BAR')");
brandjon38dafdd2020-08-06 09:49:13 -07001462
1463 reporter.removeHandler(failFastHandler);
1464 getConfiguredTarget("//pkg:BUILD");
brandjon2a73a732020-08-08 06:41:14 -07001465 assertContainsEvent("trying to mutate a frozen list value");
1466 }
1467
1468 @Test
1469 public void testPreludeCanAccessBzlDialectFeatures() throws Exception {
1470 scratch.file("tools/build_rules/BUILD");
1471 // Test both bzl symbols and syntax (e.g. function defs).
1472 scratch.file(
1473 "tools/build_rules/test_prelude", //
1474 "def foo():",
1475 " return native.glob");
1476 scratch.file(
1477 "pkg/BUILD", //
1478 "print(foo())");
1479
1480 getConfiguredTarget("//pkg:BUILD");
1481 // Prelude can access native.glob (though only a BUILD thread can call it).
adonovan800117e2020-09-18 10:30:06 -07001482 assertContainsEvent("<built-in method glob of native value>");
brandjon38dafdd2020-08-06 09:49:13 -07001483 }
1484
1485 @Test
1486 public void testPreludeNeedNotBePresent() throws Exception {
1487 scratch.file(
1488 "pkg/BUILD", //
1489 "print('FOO')");
1490
1491 getConfiguredTarget("//pkg:BUILD");
1492 assertContainsEvent("FOO");
1493 }
1494
1495 @Test
brandjon2a73a732020-08-08 06:41:14 -07001496 public void testPreludeNeedNotBePresent_evenWhenPackageIs() throws Exception {
1497 scratch.file("tools/build_rules/BUILD");
1498 scratch.file(
1499 "pkg/BUILD", //
1500 "print('FOO')");
1501
1502 getConfiguredTarget("//pkg:BUILD");
1503 assertContainsEvent("FOO");
1504 }
1505
1506 @Test
brandjon38dafdd2020-08-06 09:49:13 -07001507 public void testPreludeFileNotRecognizedWithoutPackage() throws Exception {
1508 scratch.file(
1509 "tools/build_rules/test_prelude", //
1510 "foo = 'FOO'");
1511 scratch.file(
1512 "pkg/BUILD", //
1513 "print(foo)");
1514
1515 // The prelude file is not found without a corresponding package to contain it. BUILD files
1516 // get processed as if no prelude file is present.
1517 reporter.removeHandler(failFastHandler);
1518 getConfiguredTarget("//pkg:BUILD");
1519 assertContainsEvent("name 'foo' is not defined");
1520 }
1521
1522 @Test
1523 public void testPreludeFailsWhenErrorInPreludeFile() throws Exception {
1524 scratch.file("tools/build_rules/BUILD");
1525 scratch.file(
1526 "tools/build_rules/test_prelude", //
1527 "1//0", // <-- dynamic error
1528 "foo = 'FOO'");
1529 scratch.file(
1530 "pkg/BUILD", //
1531 "print(foo)");
1532
1533 reporter.removeHandler(failFastHandler);
1534 getConfiguredTarget("//pkg:BUILD");
1535 assertContainsEvent(
1536 "File \"/workspace/tools/build_rules/test_prelude\", line 1, column 2, in <toplevel>");
1537 assertContainsEvent("Error: integer division by zero");
1538 }
1539
1540 @Test
1541 public void testPreludeWorksEvenWhenPreludePackageInError() throws Exception {
1542 scratch.file(
1543 "tools/build_rules/BUILD", //
1544 "1//0"); // <-- dynamic error
1545 scratch.file(
1546 "tools/build_rules/test_prelude", //
1547 "foo = 'FOO'");
1548 scratch.file(
1549 "pkg/BUILD", //
1550 "print(foo)");
1551
1552 // Succeeds because prelude loading is only dependent on the prelude package's existence, not
1553 // its evaluation.
1554 getConfiguredTarget("//pkg:BUILD");
1555 assertContainsEvent("FOO");
1556 }
1557
1558 // Another hypothetical test case we could try: Confirm that it's possible to explicitly load
1559 // the prelude file as a regular .bzl. We don't bother testing this use case because, aside from
1560 // being arguably pathological, it is currently impossible in practice: The prelude label
1561 // doesn't end with ".bzl" and isn't configurable by the user. We also want to eliminate the
1562 // prelude, so there's no intention of adding such a feature.
1563
1564 // Another possible test case: Verify how prelude applies to WORKSPACE files.
1565 }
1566
Kristina Chodorow335f0672015-11-16 23:19:13 +00001567 private static class CustomInMemoryFs extends InMemoryFileSystem {
Googlerc804c662016-12-01 16:53:28 +00001568 private abstract static class FileStatusOrException {
1569 abstract FileStatus get() throws IOException;
1570
1571 private static class ExceptionImpl extends FileStatusOrException {
1572 private final IOException exn;
1573
1574 private ExceptionImpl(IOException exn) {
1575 this.exn = exn;
1576 }
1577
1578 @Override
1579 FileStatus get() throws IOException {
1580 throw exn;
1581 }
1582 }
1583
1584 private static class FileStatusImpl extends FileStatusOrException {
1585
laurentlbc0bd2102018-10-17 07:05:25 -07001586 @Nullable private final FileStatus fileStatus;
Googlerc804c662016-12-01 16:53:28 +00001587
laurentlbc0bd2102018-10-17 07:05:25 -07001588 private FileStatusImpl(@Nullable FileStatus fileStatus) {
Googlerc804c662016-12-01 16:53:28 +00001589 this.fileStatus = fileStatus;
1590 }
1591
1592 @Override
1593 @Nullable
1594 FileStatus get() {
1595 return fileStatus;
1596 }
1597 }
1598 }
1599
aehligc801c392017-12-19 07:12:25 -08001600 private final Map<Path, FileStatusOrException> stubbedStats = Maps.newHashMap();
1601 private final Set<Path> makeUnreadableAfterReaddir = Sets.newHashSet();
1602 private final Map<Path, IOException> pathsToErrorOnGetInputStream = Maps.newHashMap();
Kristina Chodorow335f0672015-11-16 23:19:13 +00001603
1604 public CustomInMemoryFs(ManualClock manualClock) {
janakr97c0bd12020-09-08 13:19:03 -07001605 super(manualClock, DigestHashFunction.SHA256);
Kristina Chodorow335f0672015-11-16 23:19:13 +00001606 }
1607
aehligc801c392017-12-19 07:12:25 -08001608 public void stubStat(Path path, @Nullable FileStatus stubbedResult) {
Googlerc804c662016-12-01 16:53:28 +00001609 stubbedStats.put(path, new FileStatusOrException.FileStatusImpl(stubbedResult));
Kristina Chodorow335f0672015-11-16 23:19:13 +00001610 }
1611
aehligc801c392017-12-19 07:12:25 -08001612 public void stubStatError(Path path, IOException stubbedResult) {
Googlerc804c662016-12-01 16:53:28 +00001613 stubbedStats.put(path, new FileStatusOrException.ExceptionImpl(stubbedResult));
Kristina Chodorow335f0672015-11-16 23:19:13 +00001614 }
1615
1616 @Override
fellya205ed82018-09-10 11:52:34 -07001617 public FileStatus statIfFound(Path path, boolean followSymlinks) throws IOException {
Googlerc804c662016-12-01 16:53:28 +00001618 if (stubbedStats.containsKey(path)) {
1619 return stubbedStats.get(path).get();
Kristina Chodorow335f0672015-11-16 23:19:13 +00001620 }
fellya205ed82018-09-10 11:52:34 -07001621 return super.statIfFound(path, followSymlinks);
Kristina Chodorow335f0672015-11-16 23:19:13 +00001622 }
1623
aehligc801c392017-12-19 07:12:25 -08001624 public void scheduleMakeUnreadableAfterReaddir(Path path) {
Googlerc804c662016-12-01 16:53:28 +00001625 makeUnreadableAfterReaddir.add(path);
Kristina Chodorow335f0672015-11-16 23:19:13 +00001626 }
1627
1628 @Override
aehligc801c392017-12-19 07:12:25 -08001629 public Collection<Dirent> readdir(Path path, boolean followSymlinks) throws IOException {
Kristina Chodorow335f0672015-11-16 23:19:13 +00001630 Collection<Dirent> result = super.readdir(path, followSymlinks);
Googlerc804c662016-12-01 16:53:28 +00001631 if (makeUnreadableAfterReaddir.contains(path)) {
aehligc801c392017-12-19 07:12:25 -08001632 path.setReadable(false);
Kristina Chodorow335f0672015-11-16 23:19:13 +00001633 }
1634 return result;
1635 }
nharmataff688bf2017-06-07 17:03:52 -04001636
aehligc801c392017-12-19 07:12:25 -08001637 public void throwExceptionOnGetInputStream(Path path, IOException exn) {
nharmataff688bf2017-06-07 17:03:52 -04001638 pathsToErrorOnGetInputStream.put(path, exn);
1639 }
1640
1641 @Override
aehligc801c392017-12-19 07:12:25 -08001642 protected InputStream getInputStream(Path path) throws IOException {
nharmataff688bf2017-06-07 17:03:52 -04001643 IOException exnToThrow = pathsToErrorOnGetInputStream.get(path);
1644 if (exnToThrow != null) {
1645 throw exnToThrow;
1646 }
1647 return super.getInputStream(path);
1648 }
Kristina Chodorow335f0672015-11-16 23:19:13 +00001649 }
Kristina Chodorow335f0672015-11-16 23:19:13 +00001650}