blob: dcf6ea7bdb8b8429c074b968c93d09985dd8573e [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;
michajlof05777b2021-03-18 05:51:36 -070022import static org.mockito.ArgumentMatchers.eq;
michajlod05a9232020-02-25 16:39:00 -080023import static org.mockito.Mockito.doAnswer;
michajlof05777b2021-03-18 05:51:36 -070024import static org.mockito.Mockito.verify;
25import static org.mockito.Mockito.when;
Kristina Chodorow335f0672015-11-16 23:19:13 +000026
27import com.google.common.base.Predicates;
28import com.google.common.collect.ImmutableList;
29import com.google.common.collect.ImmutableMap;
30import com.google.common.collect.Maps;
Googlerc804c662016-12-01 16:53:28 +000031import com.google.common.collect.Sets;
shahan602cc852018-06-06 20:09:57 -070032import com.google.devtools.build.lib.actions.FileStateValue;
brandjon38dafdd2020-08-06 09:49:13 -070033import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider;
Florian Weikertcca703a2015-12-07 09:56:38 +000034import com.google.devtools.build.lib.analysis.util.BuildViewTestCase;
philwo3bcb9f62017-09-06 12:52:21 +020035import com.google.devtools.build.lib.clock.BlazeClock;
Kristina Chodorow335f0672015-11-16 23:19:13 +000036import com.google.devtools.build.lib.cmdline.Label;
37import com.google.devtools.build.lib.cmdline.PackageIdentifier;
michajloa96b2d22020-02-26 14:54:50 -080038import com.google.devtools.build.lib.events.Event;
39import com.google.devtools.build.lib.events.ExtendedEventHandler;
adonovan87b46082020-07-08 15:58:04 -070040import com.google.devtools.build.lib.packages.BazelModuleContext;
nharmata58613102018-10-11 15:10:04 -070041import com.google.devtools.build.lib.packages.BuildFileNotFoundException;
Kristina Chodorow335f0672015-11-16 23:19:13 +000042import com.google.devtools.build.lib.packages.ConstantRuleVisibility;
nharmataff688bf2017-06-07 17:03:52 -040043import com.google.devtools.build.lib.packages.NoSuchPackageException;
Nathan Harmata2022ad82016-02-22 23:04:14 +000044import com.google.devtools.build.lib.packages.NoSuchTargetException;
nharmatac9fbe952019-06-13 09:39:23 -070045import com.google.devtools.build.lib.packages.Package;
michajlof05777b2021-03-18 05:51:36 -070046import com.google.devtools.build.lib.packages.PackageOverheadEstimator;
michajlod05a9232020-02-25 16:39:00 -080047import com.google.devtools.build.lib.packages.PackageValidator;
48import com.google.devtools.build.lib.packages.PackageValidator.InvalidPackageException;
adonovan240bdea2020-09-03 15:24:12 -070049import com.google.devtools.build.lib.packages.semantics.BuildLanguageOptions;
ajurkowskid74b0ec2020-04-13 10:58:21 -070050import com.google.devtools.build.lib.pkgcache.PackageOptions;
Kristina Chodorow335f0672015-11-16 23:19:13 +000051import com.google.devtools.build.lib.pkgcache.PathPackageLocator;
Klaus Aehlig8eb47482018-09-17 09:14:58 -070052import com.google.devtools.build.lib.rules.repository.RepositoryDelegatorFunction;
Googler74178a52020-06-29 17:42:47 -070053import com.google.devtools.build.lib.server.FailureDetails.PackageLoading;
Kristina Chodorow335f0672015-11-16 23:19:13 +000054import com.google.devtools.build.lib.skyframe.util.SkyframeExecutorTestUtils;
55import com.google.devtools.build.lib.testutil.ManualClock;
brandjon38dafdd2020-08-06 09:49:13 -070056import com.google.devtools.build.lib.testutil.TestRuleClassProvider;
Googler74178a52020-06-29 17:42:47 -070057import com.google.devtools.build.lib.util.DetailedExitCode;
58import com.google.devtools.build.lib.util.ExitCode;
Benjamin Peterson723eca62019-07-22 17:24:10 -070059import com.google.devtools.build.lib.util.Pair;
Ulf Adamsc73051c62016-03-23 09:18:13 +000060import com.google.devtools.build.lib.util.io.TimestampGranularityMonitor;
janakr97c0bd12020-09-08 13:19:03 -070061import com.google.devtools.build.lib.vfs.DigestHashFunction;
Kristina Chodorow335f0672015-11-16 23:19:13 +000062import com.google.devtools.build.lib.vfs.Dirent;
63import com.google.devtools.build.lib.vfs.FileStatus;
64import com.google.devtools.build.lib.vfs.FileSystem;
65import com.google.devtools.build.lib.vfs.FileSystemUtils;
66import com.google.devtools.build.lib.vfs.ModifiedFileSet;
67import com.google.devtools.build.lib.vfs.Path;
68import com.google.devtools.build.lib.vfs.PathFragment;
tomluee6a6862018-01-17 14:36:26 -080069import com.google.devtools.build.lib.vfs.Root;
Kristina Chodorow335f0672015-11-16 23:19:13 +000070import com.google.devtools.build.lib.vfs.RootedPath;
nharmatace0335a2019-11-13 15:48:05 -080071import com.google.devtools.build.lib.vfs.Symlinks;
Kristina Chodorow335f0672015-11-16 23:19:13 +000072import com.google.devtools.build.lib.vfs.inmemoryfs.InMemoryFileSystem;
Kristina Chodorow335f0672015-11-16 23:19:13 +000073import com.google.devtools.build.skyframe.EvaluationResult;
74import com.google.devtools.build.skyframe.RecordingDifferencer;
75import com.google.devtools.build.skyframe.SkyKey;
76import com.google.devtools.build.skyframe.SkyValue;
Janak Ramakrishnan326c6982016-09-27 14:58:26 +000077import com.google.devtools.common.options.Options;
Kristina Chodorow335f0672015-11-16 23:19:13 +000078import java.io.IOException;
nharmataff688bf2017-06-07 17:03:52 -040079import java.io.InputStream;
Janak Ramakrishnanffbc28a2017-02-13 22:51:45 +000080import java.util.ArrayList;
tomluee6a6862018-01-17 14:36:26 -080081import java.util.Arrays;
Kristina Chodorow335f0672015-11-16 23:19:13 +000082import java.util.Collection;
Janak Ramakrishnanffbc28a2017-02-13 22:51:45 +000083import java.util.List;
Kristina Chodorow335f0672015-11-16 23:19:13 +000084import java.util.Map;
jhorvitzdd1d8412020-08-01 05:59:14 -070085import java.util.Optional;
michajlof05777b2021-03-18 05:51:36 -070086import java.util.OptionalLong;
Googlerc804c662016-12-01 16:53:28 +000087import java.util.Set;
Kristina Chodorow335f0672015-11-16 23:19:13 +000088import java.util.UUID;
michajlo90810222020-03-02 09:36:23 -080089import java.util.concurrent.atomic.AtomicInteger;
Kristina Chodorow335f0672015-11-16 23:19:13 +000090import javax.annotation.Nullable;
adonovan450c7ad2020-09-14 13:00:21 -070091import net.starlark.java.eval.Module;
adonovan3ed7ed52020-09-30 12:03:28 -070092import net.starlark.java.eval.StarlarkInt;
michajlod05a9232020-02-25 16:39:00 -080093import org.junit.Rule;
John Cater94695912016-08-03 12:09:39 +000094import org.junit.Test;
95import org.junit.runner.RunWith;
96import org.junit.runners.JUnit4;
michajlod05a9232020-02-25 16:39:00 -080097import org.mockito.Mock;
98import org.mockito.junit.MockitoJUnit;
99import org.mockito.junit.MockitoRule;
Kristina Chodorow335f0672015-11-16 23:19:13 +0000100
101/**
laurentlbc0bd2102018-10-17 07:05:25 -0700102 * Unit tests of specific functionality of PackageFunction. Note that it's already tested indirectly
103 * in several other places.
Kristina Chodorow335f0672015-11-16 23:19:13 +0000104 */
Florian Weikert92b22362015-12-03 10:17:18 +0000105@RunWith(JUnit4.class)
Florian Weikertcca703a2015-12-07 09:56:38 +0000106public class PackageFunctionTest extends BuildViewTestCase {
Kristina Chodorow335f0672015-11-16 23:19:13 +0000107
michajlod05a9232020-02-25 16:39:00 -0800108 @Rule public final MockitoRule mockito = MockitoJUnit.rule();
109
110 @Mock private PackageValidator mockPackageValidator;
111
michajlof05777b2021-03-18 05:51:36 -0700112 @Mock private PackageOverheadEstimator mockPackageOverheadEstimator;
113
Kristina Chodorow335f0672015-11-16 23:19:13 +0000114 private CustomInMemoryFs fs = new CustomInMemoryFs(new ManualClock());
115
Ulf Adamsc73051c62016-03-23 09:18:13 +0000116 private void preparePackageLoading(Path... roots) {
nharmatac9fbe952019-06-13 09:39:23 -0700117 preparePackageLoadingWithCustomStarklarkSemanticsOptions(
adonovan240bdea2020-09-03 15:24:12 -0700118 Options.getDefaults(BuildLanguageOptions.class), roots);
nharmatac9fbe952019-06-13 09:39:23 -0700119 }
120
121 private void preparePackageLoadingWithCustomStarklarkSemanticsOptions(
brandjon6dbfa3e2020-10-06 19:31:08 -0700122 BuildLanguageOptions buildLanguageOptions, Path... roots) {
ajurkowskid74b0ec2020-04-13 10:58:21 -0700123 PackageOptions packageOptions = Options.getDefaults(PackageOptions.class);
124 packageOptions.defaultVisibility = ConstantRuleVisibility.PUBLIC;
125 packageOptions.showLoadingProgress = true;
126 packageOptions.globbingThreads = 7;
Klaus Aehlig6f33a1c2016-09-13 16:46:10 +0000127 getSkyframeExecutor()
128 .preparePackageLoading(
John Catere0d1d0e2017-11-28 20:47:41 -0800129 new PathPackageLocator(
130 outputBase,
tomluee6a6862018-01-17 14:36:26 -0800131 Arrays.stream(roots).map(Root::fromPath).collect(ImmutableList.toImmutableList()),
John Catere0d1d0e2017-11-28 20:47:41 -0800132 BazelSkyframeExecutorConstants.BUILD_FILES_BY_PRIORITY),
ajurkowskid74b0ec2020-04-13 10:58:21 -0700133 packageOptions,
brandjon6dbfa3e2020-10-06 19:31:08 -0700134 buildLanguageOptions,
Klaus Aehlig6f33a1c2016-09-13 16:46:10 +0000135 UUID.randomUUID(),
136 ImmutableMap.<String, String>of(),
137 new TimestampGranularityMonitor(BlazeClock.instance()));
juliexxia651797f2018-08-01 11:45:13 -0700138 skyframeExecutor.setActionEnv(ImmutableMap.<String, String>of());
Ulf Adamsc73051c62016-03-23 09:18:13 +0000139 }
140
Kristina Chodorow335f0672015-11-16 23:19:13 +0000141 @Override
Kristina Chodorow335f0672015-11-16 23:19:13 +0000142 protected FileSystem createFileSystem() {
143 return fs;
144 }
145
michajlod05a9232020-02-25 16:39:00 -0800146 @Override
147 protected PackageValidator getPackageValidator() {
148 return mockPackageValidator;
149 }
150
michajlof05777b2021-03-18 05:51:36 -0700151 @Override
152 protected PackageOverheadEstimator getPackageOverheadEstimator() {
153 return mockPackageOverheadEstimator;
154 }
155
nharmatac9fbe952019-06-13 09:39:23 -0700156 private Package validPackageWithoutErrors(SkyKey skyKey) throws InterruptedException {
157 return validPackageInternal(skyKey, /*checkPackageError=*/ true);
158 }
159
160 private Package validPackage(SkyKey skyKey) throws InterruptedException {
161 return validPackageInternal(skyKey, /*checkPackageError=*/ false);
162 }
163
164 private Package validPackageInternal(SkyKey skyKey, boolean checkPackageError)
165 throws InterruptedException {
Klaus Aehlig8eb47482018-09-17 09:14:58 -0700166 SkyframeExecutor skyframeExecutor = getSkyframeExecutor();
167 skyframeExecutor.injectExtraPrecomputedValues(
168 ImmutableList.of(
169 PrecomputedValue.injected(
jhorvitzdd1d8412020-08-01 05:59:14 -0700170 RepositoryDelegatorFunction.RESOLVED_FILE_INSTEAD_OF_WORKSPACE, Optional.empty())));
Klaus Aehlig8eb47482018-09-17 09:14:58 -0700171 EvaluationResult<PackageValue> result =
172 SkyframeExecutorTestUtils.evaluate(
173 skyframeExecutor, skyKey, /*keepGoing=*/ false, reporter);
Kristina Chodorow335f0672015-11-16 23:19:13 +0000174 if (result.hasError()) {
175 fail(result.getError(skyKey).getException().getMessage());
176 }
177 PackageValue value = result.get(skyKey);
nharmatac9fbe952019-06-13 09:39:23 -0700178 if (checkPackageError) {
179 assertThat(value.getPackage().containsErrors()).isFalse();
180 }
181 return value.getPackage();
Kristina Chodorow335f0672015-11-16 23:19:13 +0000182 }
183
brandjon54a7fcf2021-02-01 09:16:42 -0800184 /**
185 * Helper that evaluates the given package and returns the expected exception.
186 *
187 * <p>Disables the failFastHandler as a side-effect.
188 */
189 private Exception evaluatePackageToException(String pkg) throws Exception {
190 reporter.removeHandler(failFastHandler);
191
192 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse(pkg));
193 EvaluationResult<PackageValue> result =
194 SkyframeExecutorTestUtils.evaluate(
195 getSkyframeExecutor(), skyKey, /*keepGoing=*/ false, reporter);
196 assertThat(result.hasError()).isTrue();
197 return result.getError(skyKey).getException();
198 }
199
Florian Weikert92b22362015-12-03 10:17:18 +0000200 @Test
John Cater94695912016-08-03 12:09:39 +0000201 public void testValidPackage() throws Exception {
202 scratch.file("pkg/BUILD");
nharmatac9fbe952019-06-13 09:39:23 -0700203 validPackageWithoutErrors(PackageValue.key(PackageIdentifier.parse("@//pkg")));
John Cater94695912016-08-03 12:09:39 +0000204 }
205
206 @Test
michajlod05a9232020-02-25 16:39:00 -0800207 public void testInvalidPackage() throws Exception {
208 scratch.file("pkg/BUILD", "sh_library(name='foo', srcs=['foo.sh'])");
209 scratch.file("pkg/foo.sh");
210
211 doAnswer(
212 inv -> {
213 Package pkg = inv.getArgument(0, Package.class);
214 if (pkg.getName().equals("pkg")) {
michajlof05777b2021-03-18 05:51:36 -0700215 inv.getArgument(2, ExtendedEventHandler.class).handle(Event.warn("warning event"));
michajlod05a9232020-02-25 16:39:00 -0800216 throw new InvalidPackageException(pkg.getPackageIdentifier(), "no good");
217 }
218 return null;
219 })
220 .when(mockPackageValidator)
michajlof05777b2021-03-18 05:51:36 -0700221 .validate(any(Package.class), any(OptionalLong.class), any(ExtendedEventHandler.class));
michajlod05a9232020-02-25 16:39:00 -0800222
223 invalidatePackages();
224
brandjon54a7fcf2021-02-01 09:16:42 -0800225 Exception ex = evaluatePackageToException("@//pkg");
226 assertThat(ex).isInstanceOf(InvalidPackageException.class);
227 assertThat(ex).hasMessageThat().contains("no such package 'pkg': no good");
michajloa96b2d22020-02-26 14:54:50 -0800228 assertContainsEvent("warning event");
michajlod05a9232020-02-25 16:39:00 -0800229 }
230
231 @Test
michajlof05777b2021-03-18 05:51:36 -0700232 public void testPackageOverheadPassedToValidationLogic() throws Exception {
233 scratch.file("pkg/BUILD", "# Contents doesn't matter, it's all fake");
234
235 when(mockPackageOverheadEstimator.estimatePackageOverhead(any(Package.class)))
236 .thenReturn(OptionalLong.of(42));
237
238 invalidatePackages();
239
240 SkyframeExecutorTestUtils.evaluate(
241 getSkyframeExecutor(),
242 PackageValue.key(PackageIdentifier.parse("@//pkg")),
243 /*keepGoing=*/ false,
244 reporter);
245
246 verify(mockPackageValidator)
247 .validate(any(Package.class), eq(OptionalLong.of(42)), any(ExtendedEventHandler.class));
248 }
249
250 @Test
michajlo90810222020-03-02 09:36:23 -0800251 public void testSkyframeExecutorClearedPackagesResultsInReload() throws Exception {
252 scratch.file("pkg/BUILD", "sh_library(name='foo', srcs=['foo.sh'])");
253 scratch.file("pkg/foo.sh");
254
255 invalidatePackages();
256
257 // Use number of times the package was validated as a proxy for number of times it was loaded.
258 AtomicInteger validationCount = new AtomicInteger();
259 doAnswer(
260 inv -> {
261 if (inv.getArgument(0, Package.class).getName().equals("pkg")) {
262 validationCount.incrementAndGet();
263 }
264 return null;
265 })
266 .when(mockPackageValidator)
michajlof05777b2021-03-18 05:51:36 -0700267 .validate(any(Package.class), any(OptionalLong.class), any(ExtendedEventHandler.class));
michajlo90810222020-03-02 09:36:23 -0800268
269 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//pkg"));
270 EvaluationResult<PackageValue> result1 =
271 SkyframeExecutorTestUtils.evaluate(
272 getSkyframeExecutor(), skyKey, /*keepGoing=*/ false, reporter);
273 assertThatEvaluationResult(result1).hasNoError();
274
275 skyframeExecutor.clearLoadedPackages();
276
277 EvaluationResult<PackageValue> result2 =
278 SkyframeExecutorTestUtils.evaluate(
279 getSkyframeExecutor(), skyKey, /*keepGoing=*/ false, reporter);
280 assertThatEvaluationResult(result2).hasNoError();
281
282 assertThat(validationCount.get()).isEqualTo(2);
283 }
284
285 @Test
Kristina Chodorow335f0672015-11-16 23:19:13 +0000286 public void testPropagatesFilesystemInconsistencies() throws Exception {
Kristina Chodorow335f0672015-11-16 23:19:13 +0000287 RecordingDifferencer differencer = getSkyframeExecutor().getDifferencerForTesting();
tomluee6a6862018-01-17 14:36:26 -0800288 Root pkgRoot = getSkyframeExecutor().getPathEntries().get(0);
Kristina Chodorow335f0672015-11-16 23:19:13 +0000289 Path fooBuildFile = scratch.file("foo/BUILD");
290 Path fooDir = fooBuildFile.getParentDirectory();
291
neerajen89188eb2018-07-19 13:03:43 -0700292 // Our custom filesystem says that fooDir is neither a file nor directory nor symlink
laurentlbc0bd2102018-10-17 07:05:25 -0700293 FileStatus inconsistentFileStatus =
294 new FileStatus() {
295 @Override
296 public boolean isFile() {
297 return false;
298 }
Kristina Chodorow335f0672015-11-16 23:19:13 +0000299
laurentlbc0bd2102018-10-17 07:05:25 -0700300 @Override
301 public boolean isDirectory() {
302 return false;
303 }
Kristina Chodorow335f0672015-11-16 23:19:13 +0000304
laurentlbc0bd2102018-10-17 07:05:25 -0700305 @Override
306 public boolean isSymbolicLink() {
307 return false;
308 }
Kristina Chodorow335f0672015-11-16 23:19:13 +0000309
laurentlbc0bd2102018-10-17 07:05:25 -0700310 @Override
311 public boolean isSpecialFile() {
312 return false;
313 }
Kristina Chodorow335f0672015-11-16 23:19:13 +0000314
laurentlbc0bd2102018-10-17 07:05:25 -0700315 @Override
316 public long getSize() throws IOException {
317 return 0;
318 }
Kristina Chodorow335f0672015-11-16 23:19:13 +0000319
laurentlbc0bd2102018-10-17 07:05:25 -0700320 @Override
321 public long getLastModifiedTime() throws IOException {
322 return 0;
323 }
Kristina Chodorow335f0672015-11-16 23:19:13 +0000324
laurentlbc0bd2102018-10-17 07:05:25 -0700325 @Override
326 public long getLastChangeTime() throws IOException {
327 return 0;
328 }
Kristina Chodorow335f0672015-11-16 23:19:13 +0000329
laurentlbc0bd2102018-10-17 07:05:25 -0700330 @Override
331 public long getNodeId() throws IOException {
332 return 0;
333 }
334 };
neerajen89188eb2018-07-19 13:03:43 -0700335
336 fs.stubStat(fooBuildFile, inconsistentFileStatus);
Kristina Chodorow335f0672015-11-16 23:19:13 +0000337 RootedPath pkgRootedPath = RootedPath.toRootedPath(pkgRoot, fooDir);
Ulf Adamsc73051c62016-03-23 09:18:13 +0000338 SkyValue fooDirValue = FileStateValue.create(pkgRootedPath, tsgm);
Kristina Chodorow335f0672015-11-16 23:19:13 +0000339 differencer.inject(ImmutableMap.of(FileStateValue.key(pkgRootedPath), fooDirValue));
brandjon54a7fcf2021-02-01 09:16:42 -0800340
341 Exception ex = evaluatePackageToException("@//foo");
342 String msg = ex.getMessage();
343 assertThat(msg).contains("Inconsistent filesystem operations");
344 assertThat(msg)
345 .contains(
346 "according to stat, existing path /workspace/foo/BUILD is neither"
347 + " a file nor directory nor symlink.");
janakra4a564a2021-03-18 12:40:11 -0700348 assertDetailedExitCode(
349 ex,
350 PackageLoading.Code.PERSISTENT_INCONSISTENT_FILESYSTEM_ERROR,
351 ExitCode.LOCAL_ENVIRONMENTAL_ERROR);
Kristina Chodorow335f0672015-11-16 23:19:13 +0000352 }
353
Florian Weikert92b22362015-12-03 10:17:18 +0000354 @Test
jmmvbfbd95f2020-08-31 13:12:38 -0700355 public void testPropagatesFilesystemInconsistencies_globbing() throws Exception {
djasper7faa0ef2019-03-28 10:00:00 -0700356 getSkyframeExecutor().turnOffSyscallCacheForTesting();
Kristina Chodorow335f0672015-11-16 23:19:13 +0000357 RecordingDifferencer differencer = getSkyframeExecutor().getDifferencerForTesting();
tomluee6a6862018-01-17 14:36:26 -0800358 Root pkgRoot = getSkyframeExecutor().getPathEntries().get(0);
laurentlbc0bd2102018-10-17 07:05:25 -0700359 scratch.file(
360 "foo/BUILD",
Googlerbb0d36a2019-09-26 13:19:28 -0700361 "sh_library(name = 'foo', srcs = glob(['bar/**/baz.sh']))",
362 "x = 1//0" // causes 'foo' to be marked in error
363 );
Kristina Chodorow335f0672015-11-16 23:19:13 +0000364 Path bazFile = scratch.file("foo/bar/baz/baz.sh");
365 Path bazDir = bazFile.getParentDirectory();
366 Path barDir = bazDir.getParentDirectory();
367
Kristina Chodorow335f0672015-11-16 23:19:13 +0000368 // Our custom filesystem says "foo/bar/baz" does not exist but it also says that "foo/bar"
369 // has a child directory "baz".
aehligc801c392017-12-19 07:12:25 -0800370 fs.stubStat(bazDir, null);
Kristina Chodorow335f0672015-11-16 23:19:13 +0000371 RootedPath barDirRootedPath = RootedPath.toRootedPath(pkgRoot, barDir);
janakre54491e2018-07-11 16:29:13 -0700372 differencer.inject(
373 ImmutableMap.of(
374 DirectoryListingStateValue.key(barDirRootedPath),
375 DirectoryListingStateValue.create(
376 ImmutableList.of(new Dirent("baz", Dirent.Type.DIRECTORY)))));
brandjon54a7fcf2021-02-01 09:16:42 -0800377
378 Exception ex = evaluatePackageToException("@//foo");
379 String msg = ex.getMessage();
380 assertThat(msg).contains("Inconsistent filesystem operations");
381 assertThat(msg).contains("/workspace/foo/bar/baz is no longer an existing directory");
janakra4a564a2021-03-18 12:40:11 -0700382 assertDetailedExitCode(
383 ex,
384 PackageLoading.Code.PERSISTENT_INCONSISTENT_FILESYSTEM_ERROR,
385 ExitCode.LOCAL_ENVIRONMENTAL_ERROR);
Kristina Chodorow335f0672015-11-16 23:19:13 +0000386 }
387
388 /** Regression test for unexpected exception type from PackageValue. */
Florian Weikert92b22362015-12-03 10:17:18 +0000389 @Test
nharmata11d8ecf2021-06-09 12:27:08 -0700390 public void testDiscrepancyBetweenGlobbingErrors() throws Exception {
391 // Normally, non-Skyframe globbing and skyframe globbing share a cache for `readdir` filesystem
392 // calls. In order to exercise a situation where they observe different results for filesystem
393 // calls, we disable the cache. This might happen in a real scenario, e.g. if the cache hits a
394 // limit and evicts entries.
djasperb109a5f2019-02-14 01:05:34 -0800395 getSkyframeExecutor().turnOffSyscallCacheForTesting();
laurentlbc0bd2102018-10-17 07:05:25 -0700396 Path fooBuildFile =
397 scratch.file("foo/BUILD", "sh_library(name = 'foo', srcs = glob(['bar/*.sh']))");
Kristina Chodorow335f0672015-11-16 23:19:13 +0000398 Path fooDir = fooBuildFile.getParentDirectory();
399 Path barDir = fooDir.getRelative("bar");
400 scratch.file("foo/bar/baz.sh");
aehligc801c392017-12-19 07:12:25 -0800401 fs.scheduleMakeUnreadableAfterReaddir(barDir);
Kristina Chodorow335f0672015-11-16 23:19:13 +0000402
brandjon54a7fcf2021-02-01 09:16:42 -0800403 Exception ex = evaluatePackageToException("@//foo");
404 String msg = ex.getMessage();
405 assertThat(msg).contains("Inconsistent filesystem operations");
jhorvitz4e5e52b2021-02-26 14:02:45 -0800406 assertThat(msg).contains("Encountered error '/workspace/foo/bar (Permission denied)'");
janakra4a564a2021-03-18 12:40:11 -0700407 assertDetailedExitCode(
408 ex,
409 PackageLoading.Code.TRANSIENT_INCONSISTENT_FILESYSTEM_ERROR,
410 ExitCode.LOCAL_ENVIRONMENTAL_ERROR);
Kristina Chodorow335f0672015-11-16 23:19:13 +0000411 }
412
Janak Ramakrishnan063b4882016-07-18 20:33:28 +0000413 @SuppressWarnings("unchecked") // Cast of srcs attribute to Iterable<Label>.
414 @Test
415 public void testGlobOrderStable() throws Exception {
416 scratch.file("foo/BUILD", "sh_library(name = 'foo', srcs = glob(['**/*.txt']))");
417 scratch.file("foo/b.txt");
418 scratch.file("foo/c/c.txt");
419 preparePackageLoading(rootDirectory);
420 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//foo"));
nharmatac9fbe952019-06-13 09:39:23 -0700421 Package pkg = validPackageWithoutErrors(skyKey);
Googlera40c64a2020-08-11 16:39:39 -0700422 assertThat((Iterable<Label>) pkg.getTarget("foo").getAssociatedRule().getAttr("srcs"))
Janak Ramakrishnan063b4882016-07-18 20:33:28 +0000423 .containsExactly(
424 Label.parseAbsoluteUnchecked("//foo:b.txt"),
425 Label.parseAbsoluteUnchecked("//foo:c/c.txt"))
426 .inOrder();
427 scratch.file("foo/d.txt");
428 getSkyframeExecutor()
429 .invalidateFilesUnderPathForTesting(
430 reporter,
nharmatab4060b62017-04-04 17:11:39 +0000431 ModifiedFileSet.builder().modify(PathFragment.create("foo/d.txt")).build(),
tomluee6a6862018-01-17 14:36:26 -0800432 Root.fromPath(rootDirectory));
nharmatac9fbe952019-06-13 09:39:23 -0700433 pkg = validPackageWithoutErrors(skyKey);
Googlera40c64a2020-08-11 16:39:39 -0700434 assertThat((Iterable<Label>) pkg.getTarget("foo").getAssociatedRule().getAttr("srcs"))
Janak Ramakrishnan063b4882016-07-18 20:33:28 +0000435 .containsExactly(
436 Label.parseAbsoluteUnchecked("//foo:b.txt"),
437 Label.parseAbsoluteUnchecked("//foo:c/c.txt"),
438 Label.parseAbsoluteUnchecked("//foo:d.txt"))
439 .inOrder();
440 }
441
Janak Ramakrishnan063b4882016-07-18 20:33:28 +0000442 @Test
nharmata11d8ecf2021-06-09 12:27:08 -0700443 public void testGlobOrderStableWithNonSkyframeAndSkyframeComponents() throws Exception {
Janak Ramakrishnan063b4882016-07-18 20:33:28 +0000444 scratch.file("foo/BUILD", "sh_library(name = 'foo', srcs = glob(['*.txt']))");
445 scratch.file("foo/b.txt");
446 scratch.file("foo/a.config");
447 preparePackageLoading(rootDirectory);
448 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//foo"));
nharmatac9fbe952019-06-13 09:39:23 -0700449 assertSrcs(validPackageWithoutErrors(skyKey), "foo", "//foo:b.txt");
Janak Ramakrishnan063b4882016-07-18 20:33:28 +0000450 scratch.overwriteFile(
451 "foo/BUILD", "sh_library(name = 'foo', srcs = glob(['*.txt', '*.config']))");
452 getSkyframeExecutor()
453 .invalidateFilesUnderPathForTesting(
454 reporter,
nharmatab4060b62017-04-04 17:11:39 +0000455 ModifiedFileSet.builder().modify(PathFragment.create("foo/BUILD")).build(),
tomluee6a6862018-01-17 14:36:26 -0800456 Root.fromPath(rootDirectory));
nharmatac9fbe952019-06-13 09:39:23 -0700457 assertSrcs(validPackageWithoutErrors(skyKey), "foo", "//foo:a.config", "//foo:b.txt");
Janak Ramakrishnan063b4882016-07-18 20:33:28 +0000458 scratch.overwriteFile(
459 "foo/BUILD", "sh_library(name = 'foo', srcs = glob(['*.txt', '*.config'])) # comment");
460 getSkyframeExecutor()
461 .invalidateFilesUnderPathForTesting(
462 reporter,
nharmatab4060b62017-04-04 17:11:39 +0000463 ModifiedFileSet.builder().modify(PathFragment.create("foo/BUILD")).build(),
tomluee6a6862018-01-17 14:36:26 -0800464 Root.fromPath(rootDirectory));
nharmatac9fbe952019-06-13 09:39:23 -0700465 assertSrcs(validPackageWithoutErrors(skyKey), "foo", "//foo:a.config", "//foo:b.txt");
Nathan Harmata44e1e3a2016-08-23 21:22:17 +0000466 getSkyframeExecutor().resetEvaluator();
ajurkowskid74b0ec2020-04-13 10:58:21 -0700467 PackageOptions packageOptions = Options.getDefaults(PackageOptions.class);
468 packageOptions.defaultVisibility = ConstantRuleVisibility.PUBLIC;
469 packageOptions.showLoadingProgress = true;
470 packageOptions.globbingThreads = 7;
Klaus Aehlig6f33a1c2016-09-13 16:46:10 +0000471 getSkyframeExecutor()
472 .preparePackageLoading(
John Catere0d1d0e2017-11-28 20:47:41 -0800473 new PathPackageLocator(
474 outputBase,
tomluee6a6862018-01-17 14:36:26 -0800475 ImmutableList.of(Root.fromPath(rootDirectory)),
John Catere0d1d0e2017-11-28 20:47:41 -0800476 BazelSkyframeExecutorConstants.BUILD_FILES_BY_PRIORITY),
ajurkowskid74b0ec2020-04-13 10:58:21 -0700477 packageOptions,
adonovan240bdea2020-09-03 15:24:12 -0700478 Options.getDefaults(BuildLanguageOptions.class),
Klaus Aehlig6f33a1c2016-09-13 16:46:10 +0000479 UUID.randomUUID(),
Klaus Aehlig03b9cfd2016-09-14 13:14:39 +0000480 ImmutableMap.<String, String>of(),
Klaus Aehlig6f33a1c2016-09-13 16:46:10 +0000481 tsgm);
juliexxia651797f2018-08-01 11:45:13 -0700482 getSkyframeExecutor().setActionEnv(ImmutableMap.<String, String>of());
nharmatac9fbe952019-06-13 09:39:23 -0700483 assertSrcs(validPackageWithoutErrors(skyKey), "foo", "//foo:a.config", "//foo:b.txt");
Janak Ramakrishnan063b4882016-07-18 20:33:28 +0000484 }
485
Benjamin Peterson3b39e1e2020-01-31 10:21:38 -0800486 @Test
487 public void globEscapesAt() throws Exception {
488 scratch.file("foo/BUILD", "filegroup(name = 'foo', srcs = glob(['*.txt']))");
489 scratch.file("foo/@f.txt");
490 preparePackageLoading(rootDirectory);
491 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//foo"));
492 assertSrcs(validPackageWithoutErrors(skyKey), "foo", "//foo:@f.txt");
493
494 scratch.overwriteFile("foo/BUILD", "filegroup(name = 'foo', srcs = glob(['*.txt'])) # comment");
495 getSkyframeExecutor()
496 .invalidateFilesUnderPathForTesting(
497 reporter,
498 ModifiedFileSet.builder().modify(PathFragment.create("foo/BUILD")).build(),
499 Root.fromPath(rootDirectory));
500 assertSrcs(validPackageWithoutErrors(skyKey), "foo", "//foo:@f.txt");
501 }
502
Janak Ramakrishnanffbc28a2017-02-13 22:51:45 +0000503 /**
504 * Tests that a symlink to a file outside of the package root is handled consistently. If the
505 * default behavior of Bazel was changed from {@code
506 * ExternalFileAction#DEPEND_ON_EXTERNAL_PKG_FOR_EXTERNAL_REPO_PATHS} to {@code
507 * ExternalFileAction#ASSUME_NON_EXISTENT_AND_IMMUTABLE_FOR_EXTERNAL_PATHS} then foo/link.sh
508 * should no longer appear in the srcs of //foo:foo. However, either way the srcs should be the
509 * same independent of the evaluation being incremental or clean.
510 */
511 @Test
512 public void testGlobWithExternalSymlink() throws Exception {
513 scratch.file(
514 "foo/BUILD",
515 "sh_library(name = 'foo', srcs = glob(['*.sh']))",
516 "sh_library(name = 'bar', srcs = glob(['link.sh']))",
517 "sh_library(name = 'baz', srcs = glob(['subdir_link/*.txt']))");
518 scratch.file("foo/ordinary.sh");
519 Path externalTarget = scratch.file("../ops/target.txt");
520 FileSystemUtils.ensureSymbolicLink(scratch.resolve("foo/link.sh"), externalTarget);
521 FileSystemUtils.ensureSymbolicLink(
522 scratch.resolve("foo/subdir_link"), externalTarget.getParentDirectory());
523 preparePackageLoading(rootDirectory);
524 SkyKey fooKey = PackageValue.key(PackageIdentifier.parse("@//foo"));
nharmatac9fbe952019-06-13 09:39:23 -0700525 Package fooPkg = validPackageWithoutErrors(fooKey);
526 assertSrcs(fooPkg, "foo", "//foo:link.sh", "//foo:ordinary.sh");
527 assertSrcs(fooPkg, "bar", "//foo:link.sh");
528 assertSrcs(fooPkg, "baz", "//foo:subdir_link/target.txt");
Janak Ramakrishnanffbc28a2017-02-13 22:51:45 +0000529 scratch.overwriteFile(
530 "foo/BUILD",
531 "sh_library(name = 'foo', srcs = glob(['*.sh'])) #comment",
532 "sh_library(name = 'bar', srcs = glob(['link.sh']))",
533 "sh_library(name = 'baz', srcs = glob(['subdir_link/*.txt']))");
534 getSkyframeExecutor()
535 .invalidateFilesUnderPathForTesting(
536 reporter,
nharmatab4060b62017-04-04 17:11:39 +0000537 ModifiedFileSet.builder().modify(PathFragment.create("foo/BUILD")).build(),
tomluee6a6862018-01-17 14:36:26 -0800538 Root.fromPath(rootDirectory));
nharmatac9fbe952019-06-13 09:39:23 -0700539 Package fooPkg2 = validPackageWithoutErrors(fooKey);
540 assertThat(fooPkg2).isNotEqualTo(fooPkg);
541 assertSrcs(fooPkg2, "foo", "//foo:link.sh", "//foo:ordinary.sh");
542 assertSrcs(fooPkg2, "bar", "//foo:link.sh");
543 assertSrcs(fooPkg2, "baz", "//foo:subdir_link/target.txt");
Janak Ramakrishnanffbc28a2017-02-13 22:51:45 +0000544 }
545
nharmatac9fbe952019-06-13 09:39:23 -0700546 private static void assertSrcs(Package pkg, String targetName, String... expected)
Janak Ramakrishnanffbc28a2017-02-13 22:51:45 +0000547 throws NoSuchTargetException {
548 List<Label> expectedLabels = new ArrayList<>();
549 for (String item : expected) {
550 expectedLabels.add(Label.parseAbsoluteUnchecked(item));
551 }
nharmatac9fbe952019-06-13 09:39:23 -0700552 assertThat(getSrcs(pkg, targetName)).containsExactlyElementsIn(expectedLabels).inOrder();
Janak Ramakrishnanffbc28a2017-02-13 22:51:45 +0000553 }
554
555 @SuppressWarnings("unchecked")
nharmatac9fbe952019-06-13 09:39:23 -0700556 private static Iterable<Label> getSrcs(Package pkg, String targetName)
Janak Ramakrishnanffbc28a2017-02-13 22:51:45 +0000557 throws NoSuchTargetException {
Googlera40c64a2020-08-11 16:39:39 -0700558 return (Iterable<Label>) pkg.getTarget(targetName).getAssociatedRule().getAttr("srcs");
Janak Ramakrishnanffbc28a2017-02-13 22:51:45 +0000559 }
laurentlbc0bd2102018-10-17 07:05:25 -0700560
Florian Weikert92b22362015-12-03 10:17:18 +0000561 @Test
Janak Ramakrishnan4e2e4082017-01-06 06:28:45 +0000562 public void testOneNewElementInMultipleGlob() throws Exception {
563 scratch.file(
564 "foo/BUILD",
565 "sh_library(name = 'foo', srcs = glob(['*.sh']))",
566 "sh_library(name = 'bar', srcs = glob(['*.sh', '*.txt']))");
567 preparePackageLoading(rootDirectory);
568 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//foo"));
nharmatac9fbe952019-06-13 09:39:23 -0700569 Package pkg = validPackageWithoutErrors(skyKey);
570 scratch.file("foo/irrelevant");
Janak Ramakrishnan4e2e4082017-01-06 06:28:45 +0000571 getSkyframeExecutor()
572 .invalidateFilesUnderPathForTesting(
573 reporter,
nharmatab4060b62017-04-04 17:11:39 +0000574 ModifiedFileSet.builder().modify(PathFragment.create("foo/irrelevant")).build(),
tomluee6a6862018-01-17 14:36:26 -0800575 Root.fromPath(rootDirectory));
nharmatac9fbe952019-06-13 09:39:23 -0700576 assertThat(validPackageWithoutErrors(skyKey)).isSameInstanceAs(pkg);
Janak Ramakrishnan4e2e4082017-01-06 06:28:45 +0000577 }
578
579 @Test
580 public void testNoNewElementInMultipleGlob() throws Exception {
581 scratch.file(
582 "foo/BUILD",
583 "sh_library(name = 'foo', srcs = glob(['*.sh', '*.txt']))",
584 "sh_library(name = 'bar', srcs = glob(['*.sh', '*.txt']))");
585 preparePackageLoading(rootDirectory);
586 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//foo"));
nharmatac9fbe952019-06-13 09:39:23 -0700587 Package pkg = validPackageWithoutErrors(skyKey);
588 scratch.file("foo/irrelevant");
Janak Ramakrishnan4e2e4082017-01-06 06:28:45 +0000589 getSkyframeExecutor()
590 .invalidateFilesUnderPathForTesting(
591 reporter,
nharmatab4060b62017-04-04 17:11:39 +0000592 ModifiedFileSet.builder().modify(PathFragment.create("foo/irrelevant")).build(),
tomluee6a6862018-01-17 14:36:26 -0800593 Root.fromPath(rootDirectory));
nharmatac9fbe952019-06-13 09:39:23 -0700594 assertThat(validPackageWithoutErrors(skyKey)).isSameInstanceAs(pkg);
Janak Ramakrishnan4e2e4082017-01-06 06:28:45 +0000595 }
596
597 @Test
gregceb100b1d2020-05-20 10:22:17 -0700598 public void testTransitiveStarlarkDepsStoredInPackage() throws Exception {
laurentlbc0bd2102018-10-17 07:05:25 -0700599 scratch.file("foo/BUILD", "load('//bar:ext.bzl', 'a')");
Kristina Chodorow335f0672015-11-16 23:19:13 +0000600 scratch.file("bar/BUILD");
laurentlbc0bd2102018-10-17 07:05:25 -0700601 scratch.file("bar/ext.bzl", "load('//baz:ext.bzl', 'b')", "a = b");
Kristina Chodorow335f0672015-11-16 23:19:13 +0000602 scratch.file("baz/BUILD");
laurentlbc0bd2102018-10-17 07:05:25 -0700603 scratch.file("baz/ext.bzl", "b = 1");
Kristina Chodorow335f0672015-11-16 23:19:13 +0000604 scratch.file("qux/BUILD");
laurentlbc0bd2102018-10-17 07:05:25 -0700605 scratch.file("qux/ext.bzl", "c = 1");
Kristina Chodorow335f0672015-11-16 23:19:13 +0000606
Ulf Adamsc73051c62016-03-23 09:18:13 +0000607 preparePackageLoading(rootDirectory);
Kristina Chodorow335f0672015-11-16 23:19:13 +0000608
Brian Silvermand7d6d622016-03-17 09:53:39 +0000609 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//foo"));
nharmatac9fbe952019-06-13 09:39:23 -0700610 Package pkg = validPackageWithoutErrors(skyKey);
gregce7ecc2d62020-04-17 15:32:47 -0700611 assertThat(pkg.getStarlarkFileDependencies())
dannark90e2b4b2018-06-27 13:35:04 -0700612 .containsExactly(
613 Label.parseAbsolute("//bar:ext.bzl", ImmutableMap.of()),
614 Label.parseAbsolute("//baz:ext.bzl", ImmutableMap.of()));
Kristina Chodorow335f0672015-11-16 23:19:13 +0000615
laurentlbc0bd2102018-10-17 07:05:25 -0700616 scratch.overwriteFile("bar/ext.bzl", "load('//qux:ext.bzl', 'c')", "a = c");
tomluee6a6862018-01-17 14:36:26 -0800617 getSkyframeExecutor()
618 .invalidateFilesUnderPathForTesting(
619 reporter,
620 ModifiedFileSet.builder().modify(PathFragment.create("bar/ext.bzl")).build(),
621 Root.fromPath(rootDirectory));
Kristina Chodorow335f0672015-11-16 23:19:13 +0000622
nharmatac9fbe952019-06-13 09:39:23 -0700623 pkg = validPackageWithoutErrors(skyKey);
gregce7ecc2d62020-04-17 15:32:47 -0700624 assertThat(pkg.getStarlarkFileDependencies())
dannark90e2b4b2018-06-27 13:35:04 -0700625 .containsExactly(
626 Label.parseAbsolute("//bar:ext.bzl", ImmutableMap.of()),
627 Label.parseAbsolute("//qux:ext.bzl", ImmutableMap.of()));
Kristina Chodorow335f0672015-11-16 23:19:13 +0000628 }
629
Florian Weikert92b22362015-12-03 10:17:18 +0000630 @Test
gregceb100b1d2020-05-20 10:22:17 -0700631 public void testNonExistingStarlarkExtension() throws Exception {
adonovanc0e86902020-11-19 15:50:29 -0800632 scratch.file("test/starlark/BUILD", "load('//test/starlark:bad_extension.bzl', 'some_symbol')");
Kristina Chodorow335f0672015-11-16 23:19:13 +0000633 invalidatePackages();
634
brandjon54a7fcf2021-02-01 09:16:42 -0800635 Exception ex = evaluatePackageToException("@//test/starlark");
636 assertThat(ex)
637 .hasMessageThat()
638 .isEqualTo(
639 "error loading package 'test/starlark': "
640 + "cannot load '//test/starlark:bad_extension.bzl': no such file");
janakra4a564a2021-03-18 12:40:11 -0700641 assertDetailedExitCode(
642 ex, PackageLoading.Code.IMPORT_STARLARK_FILE_ERROR, ExitCode.BUILD_FAILURE);
Kristina Chodorow335f0672015-11-16 23:19:13 +0000643 }
644
Florian Weikert92b22362015-12-03 10:17:18 +0000645 @Test
gregceb100b1d2020-05-20 10:22:17 -0700646 public void testNonExistingStarlarkExtensionFromExtension() throws Exception {
laurentlbc0bd2102018-10-17 07:05:25 -0700647 scratch.file(
gregce0503fee2020-06-11 09:22:27 -0700648 "test/starlark/extension.bzl",
649 "load('//test/starlark:bad_extension.bzl', 'some_symbol')",
Kristina Chodorow335f0672015-11-16 23:19:13 +0000650 "a = 'a'");
adonovanc0e86902020-11-19 15:50:29 -0800651 scratch.file("test/starlark/BUILD", "load('//test/starlark:extension.bzl', 'a')");
Kristina Chodorow335f0672015-11-16 23:19:13 +0000652 invalidatePackages();
653
brandjon54a7fcf2021-02-01 09:16:42 -0800654 Exception ex = evaluatePackageToException("@//test/starlark");
655 assertThat(ex)
diamondmd6df9802019-03-19 06:53:43 -0700656 .hasMessageThat()
657 .isEqualTo(
gregce0503fee2020-06-11 09:22:27 -0700658 "error loading package 'test/starlark': "
adonovandcc23002020-12-10 12:09:16 -0800659 + "at /workspace/test/starlark/extension.bzl:1:6: "
gregce0503fee2020-06-11 09:22:27 -0700660 + "cannot load '//test/starlark:bad_extension.bzl': no such file");
janakra4a564a2021-03-18 12:40:11 -0700661 assertDetailedExitCode(
662 ex, PackageLoading.Code.IMPORT_STARLARK_FILE_ERROR, ExitCode.BUILD_FAILURE);
Kristina Chodorow335f0672015-11-16 23:19:13 +0000663 }
664
Florian Weikert92b22362015-12-03 10:17:18 +0000665 @Test
brandjon6c63b8f2021-02-01 10:17:42 -0800666 public void testBuiltinsInjectionFailure() throws Exception {
667 setBuildLanguageOptions("--experimental_builtins_bzl_path=tools/builtins_staging");
668 scratch.file(
669 "tools/builtins_staging/exports.bzl",
670 "1 // 0 # <-- dynamic error",
671 "exported_toplevels = {}",
672 "exported_rules = {}",
673 "exported_to_java = {}");
674 scratch.file("pkg/BUILD");
675
676 Exception ex = evaluatePackageToException("@//pkg");
677 assertThat(ex)
678 .hasMessageThat()
679 .isEqualTo(
680 "error loading package 'pkg': Internal error while loading Starlark builtins: Failed"
681 + " to load builtins sources: initialization of module 'exports.bzl' (internal)"
682 + " failed");
janakra4a564a2021-03-18 12:40:11 -0700683 assertDetailedExitCode(
684 ex, PackageLoading.Code.BUILTINS_INJECTION_FAILURE, ExitCode.BUILD_FAILURE);
brandjon6c63b8f2021-02-01 10:17:42 -0800685 }
686
687 @Test
gregceb100b1d2020-05-20 10:22:17 -0700688 public void testSymlinkCycleWithStarlarkExtension() throws Exception {
gregce0503fee2020-06-11 09:22:27 -0700689 Path extensionFilePath = scratch.resolve("/workspace/test/starlark/extension.bzl");
nharmatab4060b62017-04-04 17:11:39 +0000690 FileSystemUtils.ensureSymbolicLink(extensionFilePath, PathFragment.create("extension.bzl"));
adonovanc0e86902020-11-19 15:50:29 -0800691 scratch.file("test/starlark/BUILD", "load('//test/starlark:extension.bzl', 'a')");
Kristina Chodorow335f0672015-11-16 23:19:13 +0000692 invalidatePackages();
693
brandjon54a7fcf2021-02-01 09:16:42 -0800694 Exception ex = evaluatePackageToException("@//test/starlark");
695 assertThat(ex)
diamondmd6df9802019-03-19 06:53:43 -0700696 .hasMessageThat()
697 .isEqualTo(
gregce0503fee2020-06-11 09:22:27 -0700698 "error loading package 'test/starlark': Encountered error while reading extension "
699 + "file 'test/starlark/extension.bzl': Symlink cycle");
janakra4a564a2021-03-18 12:40:11 -0700700 assertDetailedExitCode(
701 ex, PackageLoading.Code.IMPORT_STARLARK_FILE_ERROR, ExitCode.BUILD_FAILURE);
Kristina Chodorow335f0672015-11-16 23:19:13 +0000702 }
703
Florian Weikert92b22362015-12-03 10:17:18 +0000704 @Test
Kristina Chodorow335f0672015-11-16 23:19:13 +0000705 public void testIOErrorLookingForSubpackageForLabelIsHandled() throws Exception {
brandjon54a7fcf2021-02-01 09:16:42 -0800706 scratch.file(
707 "foo/BUILD", //
708 "sh_library(name = 'foo', srcs = ['bar/baz.sh'])");
Kristina Chodorow335f0672015-11-16 23:19:13 +0000709 Path barBuildFile = scratch.file("foo/bar/BUILD");
aehligc801c392017-12-19 07:12:25 -0800710 fs.stubStatError(barBuildFile, new IOException("nope"));
brandjon54a7fcf2021-02-01 09:16:42 -0800711
712 evaluatePackageToException("@//foo");
Kristina Chodorow335f0672015-11-16 23:19:13 +0000713 assertContainsEvent("nope");
714 }
715
Florian Weikert92b22362015-12-03 10:17:18 +0000716 @Test
Googler83439e62019-09-24 12:11:30 -0700717 public void testLoadOK() throws Exception {
718 scratch.file("p/a.bzl", "a = 1; b = 1; d = 1");
719 scratch.file("p/subdir/a.bzl", "c = 1; e = 1");
720 scratch.file(
721 "p/BUILD",
722 //
723 "load(':a.bzl', 'a')",
724 "load('a.bzl', 'b')",
725 "load('subdir/a.bzl', 'c')",
726 "load('//p:a.bzl', 'd')",
727 "load('//p:subdir/a.bzl', 'e')");
728 validPackageWithoutErrors(PackageValue.key(PackageIdentifier.parse("@//p")));
729 }
730
adonovane0bd9d32020-09-18 12:51:15 -0700731 // See WorkspaceFileFunctionTest for tests that exercise load('@repo...').
Googler83439e62019-09-24 12:11:30 -0700732
733 @Test
734 public void testLoadBadLabel() throws Exception {
735 scratch.file("p/BUILD", "load('this\tis not a label', 'a')");
736 reporter.removeHandler(failFastHandler);
737 SkyKey key = PackageValue.key(PackageIdentifier.parse("@//p"));
738 SkyframeExecutorTestUtils.evaluate(skyframeExecutor, key, /*keepGoing=*/ false, reporter);
739 assertContainsEvent(
740 "in load statement: invalid target name 'this<?>is not a label': target names may not"
741 + " contain non-printable characters");
Kristina Chodorow335f0672015-11-16 23:19:13 +0000742 }
743
Florian Weikert92b22362015-12-03 10:17:18 +0000744 @Test
Googler83439e62019-09-24 12:11:30 -0700745 public void testLoadFromExternalPackage() throws Exception {
746 scratch.file("p/BUILD", "load('//external:file.bzl', 'a')");
747 reporter.removeHandler(failFastHandler);
748 SkyKey key = PackageValue.key(PackageIdentifier.parse("@//p"));
749 SkyframeExecutorTestUtils.evaluate(skyframeExecutor, key, /*keepGoing=*/ false, reporter);
750 assertContainsEvent("Starlark files may not be loaded from the //external package");
751 }
752
753 @Test
754 public void testLoadWithoutBzlSuffix() throws Exception {
755 scratch.file("p/BUILD", "load('//p:file.starlark', 'a')");
756 reporter.removeHandler(failFastHandler);
757 SkyKey key = PackageValue.key(PackageIdentifier.parse("@//p"));
758 SkyframeExecutorTestUtils.evaluate(skyframeExecutor, key, /*keepGoing=*/ false, reporter);
759 assertContainsEvent("The label must reference a file with extension '.bzl'");
Kristina Chodorow335f0672015-11-16 23:19:13 +0000760 }
761
Florian Weikert92b22362015-12-03 10:17:18 +0000762 @Test
Kristina Chodorow335f0672015-11-16 23:19:13 +0000763 public void testBadWorkspaceFile() throws Exception {
764 Path workspacePath = scratch.overwriteFile("WORKSPACE", "junk");
Brian Silvermand7d6d622016-03-17 09:53:39 +0000765 SkyKey skyKey = PackageValue.key(PackageIdentifier.createInMainRepo("external"));
Kristina Chodorow335f0672015-11-16 23:19:13 +0000766 getSkyframeExecutor()
767 .invalidate(
768 Predicates.equalTo(
shahan602cc852018-06-06 20:09:57 -0700769 FileStateValue.key(
Kristina Chodorow335f0672015-11-16 23:19:13 +0000770 RootedPath.toRootedPath(
tomluee6a6862018-01-17 14:36:26 -0800771 Root.fromPath(workspacePath.getParentDirectory()),
nharmatab4060b62017-04-04 17:11:39 +0000772 PathFragment.create(workspacePath.getBaseName())))));
Kristina Chodorow335f0672015-11-16 23:19:13 +0000773
774 reporter.removeHandler(failFastHandler);
775 EvaluationResult<PackageValue> result =
776 SkyframeExecutorTestUtils.evaluate(
777 getSkyframeExecutor(), skyKey, /*keepGoing=*/ false, reporter);
lberkiaea56b32017-05-30 12:35:33 +0200778 assertThat(result.hasError()).isFalse();
779 assertThat(result.get(skyKey).getPackage().containsErrors()).isTrue();
Kristina Chodorow335f0672015-11-16 23:19:13 +0000780 }
781
Nathan Harmata2022ad82016-02-22 23:04:14 +0000782 // Regression test for the two ugly consequences of a bug where GlobFunction incorrectly matched
783 // dangling symlinks.
784 @Test
785 public void testIncrementalSkyframeHybridGlobbingOnDanglingSymlink() throws Exception {
laurentlbc0bd2102018-10-17 07:05:25 -0700786 Path packageDirPath =
787 scratch.file("foo/BUILD", "exports_files(glob(['*.txt']))").getParentDirectory();
Nathan Harmata2022ad82016-02-22 23:04:14 +0000788 scratch.file("foo/existing.txt");
789 FileSystemUtils.ensureSymbolicLink(packageDirPath.getChild("dangling.txt"), "nope");
790
Ulf Adamsc73051c62016-03-23 09:18:13 +0000791 preparePackageLoading(rootDirectory);
Nathan Harmata2022ad82016-02-22 23:04:14 +0000792
Brian Silvermand7d6d622016-03-17 09:53:39 +0000793 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//foo"));
nharmatac9fbe952019-06-13 09:39:23 -0700794 Package pkg = validPackageWithoutErrors(skyKey);
795 assertThat(pkg.containsErrors()).isFalse();
796 assertThat(pkg.getTarget("existing.txt").getName()).isEqualTo("existing.txt");
797 assertThrows(NoSuchTargetException.class, () -> pkg.getTarget("dangling.txt"));
Nathan Harmata2022ad82016-02-22 23:04:14 +0000798
laurentlbc0bd2102018-10-17 07:05:25 -0700799 scratch.overwriteFile(
800 "foo/BUILD", "exports_files(glob(['*.txt']))", "#some-irrelevant-comment");
Nathan Harmata2022ad82016-02-22 23:04:14 +0000801
tomluee6a6862018-01-17 14:36:26 -0800802 getSkyframeExecutor()
803 .invalidateFilesUnderPathForTesting(
804 reporter,
805 ModifiedFileSet.builder().modify(PathFragment.create("foo/BUILD")).build(),
806 Root.fromPath(rootDirectory));
Nathan Harmata2022ad82016-02-22 23:04:14 +0000807
nharmatac9fbe952019-06-13 09:39:23 -0700808 Package pkg2 = validPackageWithoutErrors(skyKey);
809 assertThat(pkg2.containsErrors()).isFalse();
810 assertThat(pkg2.getTarget("existing.txt").getName()).isEqualTo("existing.txt");
811 assertThrows(NoSuchTargetException.class, () -> pkg2.getTarget("dangling.txt"));
jcater83130f42019-04-30 14:29:28 -0700812 // One consequence of the bug was that dangling symlinks were matched by globs evaluated by
813 // Skyframe globbing, meaning there would incorrectly be corresponding targets in packages
814 // that had skyframe cache hits during skyframe hybrid globbing.
Nathan Harmata2022ad82016-02-22 23:04:14 +0000815
816 scratch.file("foo/nope");
tomluee6a6862018-01-17 14:36:26 -0800817 getSkyframeExecutor()
818 .invalidateFilesUnderPathForTesting(
819 reporter,
820 ModifiedFileSet.builder().modify(PathFragment.create("foo/nope")).build(),
821 Root.fromPath(rootDirectory));
Nathan Harmata2022ad82016-02-22 23:04:14 +0000822
nharmatac9fbe952019-06-13 09:39:23 -0700823 Package newPkg = validPackageWithoutErrors(skyKey);
824 assertThat(newPkg.containsErrors()).isFalse();
825 assertThat(newPkg.getTarget("existing.txt").getName()).isEqualTo("existing.txt");
Nathan Harmata2022ad82016-02-22 23:04:14 +0000826 // Another consequence of the bug is that change pruning would incorrectly cut off changes that
827 // caused a dangling symlink potentially matched by a glob to come into existence.
nharmatac9fbe952019-06-13 09:39:23 -0700828 assertThat(newPkg.getTarget("dangling.txt").getName()).isEqualTo("dangling.txt");
829 assertThat(newPkg).isNotSameInstanceAs(pkg);
Nathan Harmata2022ad82016-02-22 23:04:14 +0000830 }
831
Nathan Harmata86c319e2016-02-25 01:12:22 +0000832 // Regression test for Skyframe globbing incorrectly matching the package's directory path on
833 // 'glob(['**'], exclude_directories = 0)'. We test for this directly by triggering
nharmata11d8ecf2021-06-09 12:27:08 -0700834 // hybrid globbing (gives coverage for both non-skyframe globbing and skyframe globbing).
Nathan Harmata86c319e2016-02-25 01:12:22 +0000835 @Test
836 public void testRecursiveGlobNeverMatchesPackageDirectory() throws Exception {
laurentlbc0bd2102018-10-17 07:05:25 -0700837 scratch.file(
838 "foo/BUILD",
Nathan Harmata86c319e2016-02-25 01:12:22 +0000839 "[sh_library(name = x + '-matched') for x in glob(['**'], exclude_directories = 0)]");
840 scratch.file("foo/bar");
841
Ulf Adamsc73051c62016-03-23 09:18:13 +0000842 preparePackageLoading(rootDirectory);
Nathan Harmata86c319e2016-02-25 01:12:22 +0000843
Brian Silvermand7d6d622016-03-17 09:53:39 +0000844 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//foo"));
nharmatac9fbe952019-06-13 09:39:23 -0700845 Package pkg = validPackageWithoutErrors(skyKey);
846 assertThat(pkg.containsErrors()).isFalse();
847 assertThat(pkg.getTarget("bar-matched").getName()).isEqualTo("bar-matched");
848 assertThrows(NoSuchTargetException.class, () -> pkg.getTarget("-matched"));
Nathan Harmata86c319e2016-02-25 01:12:22 +0000849
laurentlbc0bd2102018-10-17 07:05:25 -0700850 scratch.overwriteFile(
851 "foo/BUILD",
Nathan Harmata86c319e2016-02-25 01:12:22 +0000852 "[sh_library(name = x + '-matched') for x in glob(['**'], exclude_directories = 0)]",
853 "#some-irrelevant-comment");
tomluee6a6862018-01-17 14:36:26 -0800854 getSkyframeExecutor()
855 .invalidateFilesUnderPathForTesting(
856 reporter,
857 ModifiedFileSet.builder().modify(PathFragment.create("foo/BUILD")).build(),
858 Root.fromPath(rootDirectory));
Nathan Harmata86c319e2016-02-25 01:12:22 +0000859
nharmatac9fbe952019-06-13 09:39:23 -0700860 Package pkg2 = validPackageWithoutErrors(skyKey);
861 assertThat(pkg2.containsErrors()).isFalse();
862 assertThat(pkg2.getTarget("bar-matched").getName()).isEqualTo("bar-matched");
863 assertThrows(NoSuchTargetException.class, () -> pkg2.getTarget("-matched"));
Nathan Harmata86c319e2016-02-25 01:12:22 +0000864 }
865
nharmataff688bf2017-06-07 17:03:52 -0400866 @Test
867 public void testPackageLoadingErrorOnIOExceptionReadingBuildFile() throws Exception {
868 Path fooBuildFilePath = scratch.file("foo/BUILD");
869 IOException exn = new IOException("nope");
aehligc801c392017-12-19 07:12:25 -0800870 fs.throwExceptionOnGetInputStream(fooBuildFilePath, exn);
nharmataff688bf2017-06-07 17:03:52 -0400871
brandjon54a7fcf2021-02-01 09:16:42 -0800872 Exception ex = evaluatePackageToException("@//foo");
873 assertThat(ex).hasMessageThat().contains("nope");
874 assertThat(ex).isInstanceOf(NoSuchPackageException.class);
875 assertThat(ex).hasCauseThat().isInstanceOf(IOException.class);
janakra4a564a2021-03-18 12:40:11 -0700876 assertDetailedExitCode(ex, PackageLoading.Code.BUILD_FILE_MISSING, ExitCode.BUILD_FAILURE);
nharmataff688bf2017-06-07 17:03:52 -0400877 }
878
nharmatabea67e92017-06-16 00:26:27 +0200879 @Test
880 public void testPackageLoadingErrorOnIOExceptionReadingBzlFile() throws Exception {
881 scratch.file("foo/BUILD", "load('//foo:bzl.bzl', 'x')");
882 Path fooBzlFilePath = scratch.file("foo/bzl.bzl");
883 IOException exn = new IOException("nope");
aehligc801c392017-12-19 07:12:25 -0800884 fs.throwExceptionOnGetInputStream(fooBzlFilePath, exn);
nharmatabea67e92017-06-16 00:26:27 +0200885
brandjon54a7fcf2021-02-01 09:16:42 -0800886 Exception ex = evaluatePackageToException("@//foo");
887 assertThat(ex).hasMessageThat().contains("nope");
888 assertThat(ex).isInstanceOf(NoSuchPackageException.class);
889 assertThat(ex).hasCauseThat().isInstanceOf(IOException.class);
janakra4a564a2021-03-18 12:40:11 -0700890 assertDetailedExitCode(
891 ex, PackageLoading.Code.IMPORT_STARLARK_FILE_ERROR, ExitCode.BUILD_FAILURE);
nharmatabea67e92017-06-16 00:26:27 +0200892 }
893
nharmata58613102018-10-11 15:10:04 -0700894 @Test
895 public void testLabelsCrossesSubpackageBoundaries() throws Exception {
896 reporter.removeHandler(failFastHandler);
897
898 scratch.file("pkg/BUILD", "exports_files(['sub/blah'])");
899 scratch.file("pkg/sub/BUILD");
900 invalidatePackages();
901
902 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//pkg"));
laurentlbc0bd2102018-10-17 07:05:25 -0700903 EvaluationResult<PackageValue> result =
904 SkyframeExecutorTestUtils.evaluate(
905 getSkyframeExecutor(), skyKey, /*keepGoing=*/ false, reporter);
nharmata58613102018-10-11 15:10:04 -0700906 assertThatEvaluationResult(result).hasNoError();
907 assertThat(result.get(skyKey).getPackage().containsErrors()).isTrue();
laurentlbaf489f22019-07-29 08:19:03 -0700908 assertContainsEvent("Label '//pkg:sub/blah' is invalid because 'pkg/sub' is a subpackage");
nharmata58613102018-10-11 15:10:04 -0700909 }
910
911 @Test
912 public void testSymlinkCycleEncounteredWhileHandlingLabelCrossingSubpackageBoundaries()
913 throws Exception {
nharmata58613102018-10-11 15:10:04 -0700914 scratch.file("pkg/BUILD", "exports_files(['sub/blah'])");
915 Path subBuildFilePath = scratch.dir("pkg/sub").getChild("BUILD");
916 FileSystemUtils.ensureSymbolicLink(subBuildFilePath, subBuildFilePath);
917 invalidatePackages();
918
brandjon54a7fcf2021-02-01 09:16:42 -0800919 Exception ex = evaluatePackageToException("@//pkg");
920 assertThat(ex).isInstanceOf(BuildFileNotFoundException.class);
921 assertThat(ex)
nharmata58613102018-10-11 15:10:04 -0700922 .hasMessageThat()
923 .contains(
924 "no such package 'pkg/sub': Symlink cycle detected while trying to find BUILD file");
925 assertContainsEvent("circular symlinks detected");
926 }
927
nharmatac9fbe952019-06-13 09:39:23 -0700928 @Test
jmmvbfbd95f2020-08-31 13:12:38 -0700929 public void testGlobAllowEmpty_paramValueMustBeBoolean() throws Exception {
nharmatac9fbe952019-06-13 09:39:23 -0700930 reporter.removeHandler(failFastHandler);
931
932 scratch.file("pkg/BUILD", "x = " + "glob(['*.foo'], allow_empty = 5)");
933 invalidatePackages();
934
935 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//pkg"));
michajloc17b80e2020-07-20 10:00:28 -0700936 validPackage(skyKey);
nharmatac9fbe952019-06-13 09:39:23 -0700937
michajloc17b80e2020-07-20 10:00:28 -0700938 assertContainsEvent("expected boolean for argument `allow_empty`, got `5`");
nharmatac9fbe952019-06-13 09:39:23 -0700939 }
940
941 @Test
jmmvbfbd95f2020-08-31 13:12:38 -0700942 public void testGlobAllowEmpty_functionParam() throws Exception {
nharmatac9fbe952019-06-13 09:39:23 -0700943 scratch.file("pkg/BUILD", "x = " + "glob(['*.foo'], allow_empty=True)");
944 invalidatePackages();
945
946 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//pkg"));
947 Package pkg = validPackage(skyKey);
948 assertThat(pkg.containsErrors()).isFalse();
michajloc17b80e2020-07-20 10:00:28 -0700949 assertNoEvents();
nharmatac9fbe952019-06-13 09:39:23 -0700950 }
951
952 @Test
jmmvbfbd95f2020-08-31 13:12:38 -0700953 public void testGlobAllowEmpty_starlarkOption() throws Exception {
nharmatac9fbe952019-06-13 09:39:23 -0700954 preparePackageLoadingWithCustomStarklarkSemanticsOptions(
adonovan240bdea2020-09-03 15:24:12 -0700955 Options.parse(BuildLanguageOptions.class, "--incompatible_disallow_empty_glob=false")
nharmatac9fbe952019-06-13 09:39:23 -0700956 .getOptions(),
957 rootDirectory);
958
959 scratch.file("pkg/BUILD", "x = " + "glob(['*.foo'])");
960 invalidatePackages();
961
962 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//pkg"));
963 Package pkg = validPackage(skyKey);
964 assertThat(pkg.containsErrors()).isFalse();
michajloc17b80e2020-07-20 10:00:28 -0700965 assertNoEvents();
nharmatac9fbe952019-06-13 09:39:23 -0700966 }
967
968 @Test
jmmvbfbd95f2020-08-31 13:12:38 -0700969 public void testGlobDisallowEmpty_functionParam_wasNonEmptyAndBecomesEmpty() throws Exception {
nharmatac9fbe952019-06-13 09:39:23 -0700970 scratch.file("pkg/BUILD", "x = " + "glob(['*.foo'], allow_empty=False)");
971 scratch.file("pkg/blah.foo");
972 invalidatePackages();
973
974 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//pkg"));
975
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 scratch.deleteFile("pkg/blah.foo");
981 getSkyframeExecutor()
982 .invalidateFilesUnderPathForTesting(
983 reporter,
984 ModifiedFileSet.builder().modify(PathFragment.create("pkg/blah.foo")).build(),
985 Root.fromPath(rootDirectory));
986
987 reporter.removeHandler(failFastHandler);
988 pkg = validPackage(skyKey);
989 assertThat(pkg.containsErrors()).isTrue();
michajloc17b80e2020-07-20 10:00:28 -0700990 assertContainsEvent(
laurentlb7679c302020-07-17 03:16:11 -0700991 "glob pattern '*.foo' didn't match anything, but allow_empty is set to False (the "
michajloc17b80e2020-07-20 10:00:28 -0700992 + "default value of allow_empty can be set with --incompatible_disallow_empty_glob).");
nharmatac9fbe952019-06-13 09:39:23 -0700993 }
994
995 @Test
jmmvbfbd95f2020-08-31 13:12:38 -0700996 public void testGlobDisallowEmpty_starlarkOption_wasNonEmptyAndBecomesEmpty() throws Exception {
nharmatac9fbe952019-06-13 09:39:23 -0700997 preparePackageLoadingWithCustomStarklarkSemanticsOptions(
adonovan240bdea2020-09-03 15:24:12 -0700998 Options.parse(BuildLanguageOptions.class, "--incompatible_disallow_empty_glob=true")
nharmatac9fbe952019-06-13 09:39:23 -0700999 .getOptions(),
1000 rootDirectory);
1001
1002 scratch.file("pkg/BUILD", "x = " + "glob(['*.foo'])");
1003 scratch.file("pkg/blah.foo");
1004 invalidatePackages();
1005
1006 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//pkg"));
1007
1008 Package pkg = validPackage(skyKey);
1009 assertThat(pkg.containsErrors()).isFalse();
michajloc17b80e2020-07-20 10:00:28 -07001010 assertNoEvents();
nharmatac9fbe952019-06-13 09:39:23 -07001011
1012 scratch.deleteFile("pkg/blah.foo");
1013 getSkyframeExecutor()
1014 .invalidateFilesUnderPathForTesting(
1015 reporter,
1016 ModifiedFileSet.builder().modify(PathFragment.create("pkg/blah.foo")).build(),
1017 Root.fromPath(rootDirectory));
1018
1019 reporter.removeHandler(failFastHandler);
1020 pkg = validPackage(skyKey);
1021 assertThat(pkg.containsErrors()).isTrue();
michajloc17b80e2020-07-20 10:00:28 -07001022 assertContainsEvent(
laurentlb7679c302020-07-17 03:16:11 -07001023 "glob pattern '*.foo' didn't match anything, but allow_empty is set to False (the "
michajloc17b80e2020-07-20 10:00:28 -07001024 + "default value of allow_empty can be set with --incompatible_disallow_empty_glob).");
nharmatac9fbe952019-06-13 09:39:23 -07001025 }
1026
1027 @Test
jmmvbfbd95f2020-08-31 13:12:38 -07001028 public void testGlobDisallowEmpty_functionParam_wasEmptyAndStaysEmpty() throws Exception {
nharmatac9fbe952019-06-13 09:39:23 -07001029 scratch.file("pkg/BUILD", "x = " + "glob(['*.foo'], allow_empty=False)");
1030 invalidatePackages();
1031
1032 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//pkg"));
1033 reporter.removeHandler(failFastHandler);
1034
1035 Package pkg = validPackage(skyKey);
1036 assertThat(pkg.containsErrors()).isTrue();
1037 String expectedEventString =
laurentlb7679c302020-07-17 03:16:11 -07001038 "glob pattern '*.foo' didn't match anything, but allow_empty is set to False (the "
1039 + "default value of allow_empty can be set with --incompatible_disallow_empty_glob).";
nharmatac9fbe952019-06-13 09:39:23 -07001040 assertContainsEvent(expectedEventString);
1041
1042 scratch.overwriteFile("pkg/BUILD", "x = " + "glob(['*.foo'], allow_empty=False) #comment");
1043 getSkyframeExecutor()
1044 .invalidateFilesUnderPathForTesting(
1045 reporter,
1046 ModifiedFileSet.builder().modify(PathFragment.create("pkg/BUILD")).build(),
1047 Root.fromPath(rootDirectory));
1048
1049 pkg = validPackage(skyKey);
1050 assertThat(pkg.containsErrors()).isTrue();
nharmatac9fbe952019-06-13 09:39:23 -07001051 assertContainsEvent(expectedEventString);
1052 }
1053
1054 @Test
jmmvbfbd95f2020-08-31 13:12:38 -07001055 public void testGlobDisallowEmpty_starlarkOption_wasEmptyAndStaysEmpty() throws Exception {
nharmatac9fbe952019-06-13 09:39:23 -07001056 preparePackageLoadingWithCustomStarklarkSemanticsOptions(
adonovan240bdea2020-09-03 15:24:12 -07001057 Options.parse(BuildLanguageOptions.class, "--incompatible_disallow_empty_glob=true")
nharmatac9fbe952019-06-13 09:39:23 -07001058 .getOptions(),
1059 rootDirectory);
1060
1061 scratch.file("pkg/BUILD", "x = " + "glob(['*.foo'])");
1062 invalidatePackages();
1063
1064 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//pkg"));
1065 reporter.removeHandler(failFastHandler);
1066
1067 Package pkg = validPackage(skyKey);
1068 assertThat(pkg.containsErrors()).isTrue();
1069 String expectedEventString =
laurentlb7679c302020-07-17 03:16:11 -07001070 "glob pattern '*.foo' didn't match anything, but allow_empty is set to False (the "
1071 + "default value of allow_empty can be set with --incompatible_disallow_empty_glob).";
nharmatac9fbe952019-06-13 09:39:23 -07001072 assertContainsEvent(expectedEventString);
1073
1074 scratch.overwriteFile("pkg/BUILD", "x = " + "glob(['*.foo']) #comment");
1075 getSkyframeExecutor()
1076 .invalidateFilesUnderPathForTesting(
1077 reporter,
1078 ModifiedFileSet.builder().modify(PathFragment.create("pkg/BUILD")).build(),
1079 Root.fromPath(rootDirectory));
1080
1081 pkg = validPackage(skyKey);
1082 assertThat(pkg.containsErrors()).isTrue();
nharmatac9fbe952019-06-13 09:39:23 -07001083 assertContainsEvent(expectedEventString);
1084 }
1085
1086 @Test
jmmvbfbd95f2020-08-31 13:12:38 -07001087 public void testGlobDisallowEmpty_functionParam_wasEmptyDueToExcludeAndStaysEmpty()
nharmatac9fbe952019-06-13 09:39:23 -07001088 throws Exception {
1089 scratch.file("pkg/BUILD", "x = glob(include=['*.foo'], exclude=['blah.*'], allow_empty=False)");
1090 scratch.file("pkg/blah.foo");
1091 invalidatePackages();
1092
1093 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//pkg"));
1094 reporter.removeHandler(failFastHandler);
1095
1096 Package pkg = validPackage(skyKey);
1097 assertThat(pkg.containsErrors()).isTrue();
1098 String expectedEventString =
laurentlb7679c302020-07-17 03:16:11 -07001099 "all files in the glob have been excluded, but allow_empty is set to False (the "
1100 + "default value of allow_empty can be set with --incompatible_disallow_empty_glob).";
nharmatac9fbe952019-06-13 09:39:23 -07001101 assertContainsEvent(expectedEventString);
1102
1103 scratch.overwriteFile(
1104 "pkg/BUILD",
1105 "x = glob(include=['*.foo'], exclude=['blah.*'], allow_empty=False) # comment");
1106 getSkyframeExecutor()
1107 .invalidateFilesUnderPathForTesting(
1108 reporter,
1109 ModifiedFileSet.builder().modify(PathFragment.create("pkg/BUILD")).build(),
1110 Root.fromPath(rootDirectory));
1111
1112 pkg = validPackage(skyKey);
1113 assertThat(pkg.containsErrors()).isTrue();
nharmatac9fbe952019-06-13 09:39:23 -07001114 assertContainsEvent(expectedEventString);
1115 }
1116
1117 @Test
jmmvbfbd95f2020-08-31 13:12:38 -07001118 public void testGlobDisallowEmpty_starlarkOption_wasEmptyDueToExcludeAndStaysEmpty()
nharmatac9fbe952019-06-13 09:39:23 -07001119 throws Exception {
1120 preparePackageLoadingWithCustomStarklarkSemanticsOptions(
adonovan240bdea2020-09-03 15:24:12 -07001121 Options.parse(BuildLanguageOptions.class, "--incompatible_disallow_empty_glob=true")
nharmatac9fbe952019-06-13 09:39:23 -07001122 .getOptions(),
1123 rootDirectory);
1124
1125 scratch.file("pkg/BUILD", "x = glob(include=['*.foo'], exclude=['blah.*'])");
1126 scratch.file("pkg/blah.foo");
1127 invalidatePackages();
1128
1129 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//pkg"));
1130 reporter.removeHandler(failFastHandler);
1131
1132 Package pkg = validPackage(skyKey);
1133 assertThat(pkg.containsErrors()).isTrue();
1134 String expectedEventString =
laurentlb7679c302020-07-17 03:16:11 -07001135 "all files in the glob have been excluded, but allow_empty is set to False (the "
1136 + "default value of allow_empty can be set with --incompatible_disallow_empty_glob).";
nharmatac9fbe952019-06-13 09:39:23 -07001137 assertContainsEvent(expectedEventString);
1138
1139 scratch.overwriteFile("pkg/BUILD", "x = glob(include=['*.foo'], exclude=['blah.*']) # comment");
1140 getSkyframeExecutor()
1141 .invalidateFilesUnderPathForTesting(
1142 reporter,
1143 ModifiedFileSet.builder().modify(PathFragment.create("pkg/BUILD")).build(),
1144 Root.fromPath(rootDirectory));
1145
1146 pkg = validPackage(skyKey);
1147 assertThat(pkg.containsErrors()).isTrue();
nharmatac9fbe952019-06-13 09:39:23 -07001148 assertContainsEvent(expectedEventString);
1149 }
1150
1151 @Test
jmmvbfbd95f2020-08-31 13:12:38 -07001152 public void testGlobDisallowEmpty_functionParam_wasEmptyAndBecomesNonEmpty() throws Exception {
nharmatac9fbe952019-06-13 09:39:23 -07001153 scratch.file("pkg/BUILD", "x = " + "glob(['*.foo'], allow_empty=False)");
1154 invalidatePackages();
1155
1156 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//pkg"));
1157
1158 reporter.removeHandler(failFastHandler);
1159 Package pkg = validPackage(skyKey);
1160 assertThat(pkg.containsErrors()).isTrue();
michajloc17b80e2020-07-20 10:00:28 -07001161 assertContainsEvent(
laurentlb7679c302020-07-17 03:16:11 -07001162 "glob pattern '*.foo' didn't match anything, but allow_empty is set to False (the "
michajloc17b80e2020-07-20 10:00:28 -07001163 + "default value of allow_empty can be set with --incompatible_disallow_empty_glob).");
nharmatac9fbe952019-06-13 09:39:23 -07001164
1165 scratch.file("pkg/blah.foo");
1166 getSkyframeExecutor()
1167 .invalidateFilesUnderPathForTesting(
1168 reporter,
1169 ModifiedFileSet.builder().modify(PathFragment.create("pkg/blah.foo")).build(),
1170 Root.fromPath(rootDirectory));
1171
1172 reporter.addHandler(failFastHandler);
michajloc17b80e2020-07-20 10:00:28 -07001173 eventCollector.clear();
nharmatac9fbe952019-06-13 09:39:23 -07001174 pkg = validPackage(skyKey);
1175 assertThat(pkg.containsErrors()).isFalse();
michajloc17b80e2020-07-20 10:00:28 -07001176 assertNoEvents();
nharmatac9fbe952019-06-13 09:39:23 -07001177 }
1178
1179 @Test
jmmvbfbd95f2020-08-31 13:12:38 -07001180 public void testGlobDisallowEmpty_starlarkOption_wasEmptyAndBecomesNonEmpty() throws Exception {
nharmatac9fbe952019-06-13 09:39:23 -07001181 preparePackageLoadingWithCustomStarklarkSemanticsOptions(
adonovan240bdea2020-09-03 15:24:12 -07001182 Options.parse(BuildLanguageOptions.class, "--incompatible_disallow_empty_glob=true")
nharmatac9fbe952019-06-13 09:39:23 -07001183 .getOptions(),
1184 rootDirectory);
1185
1186 scratch.file("pkg/BUILD", "x = " + "glob(['*.foo'])");
1187 invalidatePackages();
1188
1189 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//pkg"));
1190
1191 reporter.removeHandler(failFastHandler);
1192 Package pkg = validPackage(skyKey);
1193 assertThat(pkg.containsErrors()).isTrue();
michajloc17b80e2020-07-20 10:00:28 -07001194
1195 assertContainsEvent(
laurentlb7679c302020-07-17 03:16:11 -07001196 "glob pattern '*.foo' didn't match anything, but allow_empty is set to False (the "
michajloc17b80e2020-07-20 10:00:28 -07001197 + "default value of allow_empty can be set with --incompatible_disallow_empty_glob).");
nharmatac9fbe952019-06-13 09:39:23 -07001198
1199 scratch.file("pkg/blah.foo");
1200 getSkyframeExecutor()
1201 .invalidateFilesUnderPathForTesting(
1202 reporter,
1203 ModifiedFileSet.builder().modify(PathFragment.create("pkg/blah.foo")).build(),
1204 Root.fromPath(rootDirectory));
1205
1206 reporter.addHandler(failFastHandler);
michajloc17b80e2020-07-20 10:00:28 -07001207 eventCollector.clear();
nharmatac9fbe952019-06-13 09:39:23 -07001208 pkg = validPackage(skyKey);
1209 assertThat(pkg.containsErrors()).isFalse();
michajloc17b80e2020-07-20 10:00:28 -07001210 assertNoEvents();
nharmatac9fbe952019-06-13 09:39:23 -07001211 }
1212
Benjamin Peterson723eca62019-07-22 17:24:10 -07001213 @Test
adonovan87b46082020-07-08 15:58:04 -07001214 public void testPackageRecordsLoadedModules() throws Exception {
1215 scratch.file("p/BUILD", "load('a.bzl', 'a'); load(':b.bzl', 'b')");
1216 scratch.file("p/a.bzl", "load('c.bzl', 'c'); a = c");
1217 scratch.file("p/b.bzl", "load(':c.bzl', 'c'); b = c");
1218 scratch.file("p/c.bzl", "c = 0");
1219
1220 // load p
1221 preparePackageLoading(rootDirectory);
1222 SkyKey skyKey = PackageValue.key(PackageIdentifier.parse("@//p"));
1223 Package p = validPackageWithoutErrors(skyKey);
1224
1225 // Keys are load strings as they appear in the source (notice ":" in one of them).
1226 Map<String, Module> pLoads = p.getLoads();
1227 assertThat(pLoads.keySet().toString()).isEqualTo("[a.bzl, :b.bzl]");
1228
1229 // subgraph a
1230 Module a = pLoads.get("a.bzl");
1231 assertThat(a.toString()).isEqualTo("<module //p:a.bzl>");
1232 Map<String, Module> aLoads = BazelModuleContext.of(a).loads();
1233 assertThat(aLoads.keySet().toString()).isEqualTo("[c.bzl]");
1234 Module cViaA = aLoads.get("c.bzl");
1235 assertThat(cViaA.toString()).isEqualTo("<module //p:c.bzl>");
1236
1237 // subgraph b
1238 Module b = pLoads.get(":b.bzl");
1239 assertThat(b.toString()).isEqualTo("<module //p:b.bzl>");
1240 Map<String, Module> bLoads = BazelModuleContext.of(b).loads();
1241 assertThat(bLoads.keySet().toString()).isEqualTo("[:c.bzl]");
1242 Module cViaB = bLoads.get(":c.bzl");
1243 assertThat(cViaB).isSameInstanceAs(cViaA);
1244
adonovan3ed7ed52020-09-30 12:03:28 -07001245 assertThat(cViaA.getGlobal("c")).isEqualTo(StarlarkInt.of(0));
adonovan87b46082020-07-08 15:58:04 -07001246 }
1247
1248 @Test
Benjamin Peterson723eca62019-07-22 17:24:10 -07001249 public void veryBrokenPackagePostsDoneToProgressReceiver() throws Exception {
1250 reporter.removeHandler(failFastHandler);
1251
adonovanc0e86902020-11-19 15:50:29 -08001252 // Note: syntax error (recovered), non-existent .bzl file.
Benjamin Peterson723eca62019-07-22 17:24:10 -07001253 scratch.file("pkg/BUILD", "load('//does_not:exist.bzl', 'broken'");
1254 SkyKey key = PackageValue.key(PackageIdentifier.parse("@//pkg"));
1255 EvaluationResult<PackageValue> result =
1256 SkyframeExecutorTestUtils.evaluate(getSkyframeExecutor(), key, false, reporter);
adonovanc0e86902020-11-19 15:50:29 -08001257 assertThatEvaluationResult(result).hasErrorEntryForKeyThat(key);
1258 assertContainsEvent("syntax error at 'newline': expected ,");
Benjamin Peterson723eca62019-07-22 17:24:10 -07001259 assertThat(getSkyframeExecutor().getPackageProgressReceiver().progressState())
1260 .isEqualTo(new Pair<String, String>("1 packages loaded", ""));
1261 }
1262
nharmatace0335a2019-11-13 15:48:05 -08001263 @Test
nharmata11d8ecf2021-06-09 12:27:08 -07001264 public void testNonSkyframeGlobbingEncountersSymlinkCycleAndThrowsIOException() throws Exception {
nharmatace0335a2019-11-13 15:48:05 -08001265 reporter.removeHandler(failFastHandler);
1266 getSkyframeExecutor().turnOffSyscallCacheForTesting();
1267
nharmata11d8ecf2021-06-09 12:27:08 -07001268 // When a package's BUILD file and the relevant filesystem state is such that non-Skyframe
1269 // globbing will encounter an IOException due to a directory symlink cycle,
nharmatace0335a2019-11-13 15:48:05 -08001270 Path fooBUILDPath = scratch.file("foo/BUILD", "glob(['cycle/**/foo.txt'])");
1271 Path fooCyclePath = fooBUILDPath.getParentDirectory().getChild("cycle");
1272 FileSystemUtils.ensureSymbolicLink(fooCyclePath, fooCyclePath);
1273 IOException ioExnFromFS =
1274 assertThrows(IOException.class, () -> fooCyclePath.statIfFound(Symlinks.FOLLOW));
1275 // And it is indeed the case that the FileSystem throws an IOException when the cycle's Path is
nharmata11d8ecf2021-06-09 12:27:08 -07001276 // stat'd (following symlinks, as non-Skyframe globbing does).
nharmatace0335a2019-11-13 15:48:05 -08001277 assertThat(ioExnFromFS).hasMessageThat().contains("Too many levels of symbolic links");
1278
1279 // Then, when we evaluate the PackageValue node for the Package in keepGoing mode,
1280 SkyKey pkgKey = PackageValue.key(PackageIdentifier.parse("@//foo"));
1281 EvaluationResult<PackageValue> result =
1282 SkyframeExecutorTestUtils.evaluate(
1283 getSkyframeExecutor(), pkgKey, /*keepGoing=*/ true, reporter);
1284 // The result is a *non-transient* Skyframe error.
1285 assertThatEvaluationResult(result).hasErrorEntryForKeyThat(pkgKey).isNotTransient();
1286 // And that error is a NoSuchPackageException
1287 assertThatEvaluationResult(result)
1288 .hasErrorEntryForKeyThat(pkgKey)
1289 .hasExceptionThat()
1290 .isInstanceOf(NoSuchPackageException.class);
1291 // With a useful error message,
1292 assertThatEvaluationResult(result)
1293 .hasErrorEntryForKeyThat(pkgKey)
1294 .hasExceptionThat()
1295 .hasMessageThat()
1296 .contains("Symlink cycle: /workspace/foo/cycle");
1297 // And appropriate Skyframe root cause (N.B. since we want PackageFunction to rethrow in
1298 // situations like this, we want the PackageValue node to be its own root cause).
janakr4aeb7b32020-11-16 13:11:38 -08001299 assertThatEvaluationResult(result).hasErrorEntryForKeyThat(pkgKey);
nharmatace0335a2019-11-13 15:48:05 -08001300
1301 // Then, when we modify the BUILD file so as to force package loading,
1302 scratch.overwriteFile(
1303 "foo/BUILD", "glob(['cycle/**/foo.txt']) # dummy comment to force package loading");
1304 // But we don't make any filesystem changes that would invalidate the GlobValues, meaning that
1305 // PackageFunction will observe cache hits from Skyframe globbing,
1306 //
1307 // And we also have our filesystem blow up if the directory symlink cycle is encountered (thus,
nharmata11d8ecf2021-06-09 12:27:08 -07001308 // the absence of a crash indicates the lack of non-Skyframe globbing),
nharmatace0335a2019-11-13 15:48:05 -08001309 fs.stubStatError(
1310 fooCyclePath,
1311 new IOException() {
1312 @Override
1313 public String getMessage() {
1314 throw new IllegalStateException("should't get here!");
1315 }
1316 });
1317 // And we evaluate the PackageValue node for the Package in keepGoing mode,
1318 getSkyframeExecutor()
1319 .invalidateFilesUnderPathForTesting(
1320 reporter,
1321 ModifiedFileSet.builder().modify(PathFragment.create("foo/BUILD")).build(),
1322 Root.fromPath(rootDirectory));
1323 // The results are exactly the same as before,
1324 result =
1325 SkyframeExecutorTestUtils.evaluate(
1326 getSkyframeExecutor(), pkgKey, /*keepGoing=*/ true, reporter);
1327 assertThatEvaluationResult(result).hasErrorEntryForKeyThat(pkgKey).isNotTransient();
1328 assertThatEvaluationResult(result)
1329 .hasErrorEntryForKeyThat(pkgKey)
1330 .hasExceptionThat()
1331 .isInstanceOf(NoSuchPackageException.class);
1332 assertThatEvaluationResult(result)
1333 .hasErrorEntryForKeyThat(pkgKey)
1334 .hasExceptionThat()
1335 .hasMessageThat()
1336 .contains("Symlink cycle: /workspace/foo/cycle");
nharmatace0335a2019-11-13 15:48:05 -08001337 // Thus showing that clean and incremental package loading have the same semantics in the
1338 // presence of a symlink cycle encountered during glob evaluation.
1339 }
1340
Googler74178a52020-06-29 17:42:47 -07001341 private static void assertDetailedExitCode(
janakra4a564a2021-03-18 12:40:11 -07001342 Exception exception, PackageLoading.Code expectedPackageLoadingCode, ExitCode exitCode) {
Googler74178a52020-06-29 17:42:47 -07001343 assertThat(exception).isInstanceOf(DetailedException.class);
1344 DetailedExitCode detailedExitCode = ((DetailedException) exception).getDetailedExitCode();
janakra4a564a2021-03-18 12:40:11 -07001345 assertThat(detailedExitCode.getExitCode()).isEqualTo(exitCode);
Googler74178a52020-06-29 17:42:47 -07001346 assertThat(detailedExitCode.getFailureDetail().getPackageLoading().getCode())
1347 .isEqualTo(expectedPackageLoadingCode);
janakra4a564a2021-03-18 12:40:11 -07001348 assertThat(DetailedExitCode.getExitCode(detailedExitCode.getFailureDetail()))
1349 .isEqualTo(exitCode);
Googler74178a52020-06-29 17:42:47 -07001350 }
1351
brandjon38dafdd2020-08-06 09:49:13 -07001352 /**
1353 * Tests of the prelude file functionality.
1354 *
1355 * <p>This is in a separate BuildViewTestCase because we override the prelude label for the test.
1356 * (The prelude label is configured differently between Bazel and Blaze.)
1357 */
1358 @RunWith(JUnit4.class)
1359 public static class PreludeTest extends BuildViewTestCase {
1360
1361 private final CustomInMemoryFs fs = new CustomInMemoryFs(new ManualClock());
1362
1363 @Override
1364 protected FileSystem createFileSystem() {
1365 return fs;
1366 }
1367
1368 @Override
1369 protected ConfiguredRuleClassProvider createRuleClassProvider() {
1370 ConfiguredRuleClassProvider.Builder builder = new ConfiguredRuleClassProvider.Builder();
1371 // addStandardRules() may call setPrelude(), so do it first.
1372 TestRuleClassProvider.addStandardRules(builder);
1373 builder.setPrelude("//tools/build_rules:test_prelude");
1374 return builder.build();
1375 }
1376
1377 @Test
1378 public void testPreludeDefinedSymbolIsUsable() throws Exception {
1379 scratch.file("tools/build_rules/BUILD");
1380 scratch.file(
1381 "tools/build_rules/test_prelude", //
1382 "foo = 'FOO'");
1383 scratch.file(
1384 "pkg/BUILD", //
1385 "print(foo)");
1386
1387 getConfiguredTarget("//pkg:BUILD");
1388 assertContainsEvent("FOO");
1389 }
1390
1391 @Test
1392 public void testPreludeAutomaticallyReexportsLoadedSymbols() throws Exception {
1393 scratch.file("tools/build_rules/BUILD");
1394 scratch.file(
1395 "tools/build_rules/test_prelude", //
1396 "load('//util:common.bzl', 'foo')");
1397 scratch.file("util/BUILD");
1398 scratch.file(
1399 "util/common.bzl", //
1400 "foo = 'FOO'");
1401 scratch.file(
1402 "pkg/BUILD", //
1403 "print(foo)");
1404
1405 getConfiguredTarget("//pkg:BUILD");
1406 assertContainsEvent("FOO");
1407 }
1408
1409 // TODO(brandjon): Invert this test once the prelude is a module instead of a syntactic
1410 // mutation on BUILD files.
1411 @Test
1412 public void testPreludeCanExportUnderscoreSymbols() throws Exception {
1413 scratch.file("tools/build_rules/BUILD");
1414 scratch.file(
1415 "tools/build_rules/test_prelude", //
1416 "_foo = 'FOO'");
1417 scratch.file(
1418 "pkg/BUILD", //
1419 "print(_foo)");
1420
1421 getConfiguredTarget("//pkg:BUILD");
1422 assertContainsEvent("FOO");
1423 }
1424
1425 @Test
brandjon6c63b8f2021-02-01 10:17:42 -08001426 public void testPreludeCanShadowUniversal() throws Exception {
1427 scratch.file("tools/build_rules/BUILD");
1428 scratch.file(
1429 "tools/build_rules/test_prelude", //
1430 "len = 'FOO'");
1431 scratch.file(
1432 "pkg/BUILD", //
1433 "print(len)");
1434
1435 getConfiguredTarget("//pkg:BUILD");
1436 assertContainsEvent("FOO");
1437 }
1438
1439 @Test
brandjon38dafdd2020-08-06 09:49:13 -07001440 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
brandjon6c63b8f2021-02-01 10:17:42 -08001454 public void testPreludeCanShadowInjectedPredeclareds() throws Exception {
1455 setBuildLanguageOptions("--experimental_builtins_bzl_path=tools/builtins_staging");
1456 scratch.file(
1457 "tools/builtins_staging/exports.bzl",
1458 "exported_toplevels = {}",
1459 "exported_rules = {'cc_library': 'BAR'}",
1460 "exported_to_java = {}");
1461 scratch.file("tools/build_rules/BUILD");
1462 scratch.file(
1463 "tools/build_rules/test_prelude", //
1464 "cc_library = 'FOO'");
1465 scratch.file(
1466 "pkg/BUILD", //
1467 "print(cc_library)");
1468
1469 getConfiguredTarget("//pkg:BUILD");
1470 assertContainsEvent("FOO");
1471 }
1472
1473 @Test
brandjon2a73a732020-08-08 06:41:14 -07001474 public void testPreludeSymbolCannotBeMutated() throws Exception {
brandjon38dafdd2020-08-06 09:49:13 -07001475 scratch.file("tools/build_rules/BUILD");
1476 scratch.file(
1477 "tools/build_rules/test_prelude", //
1478 "foo = ['FOO']");
1479 scratch.file(
1480 "pkg/BUILD", //
brandjon2a73a732020-08-08 06:41:14 -07001481 "foo.append('BAR')");
brandjon38dafdd2020-08-06 09:49:13 -07001482
1483 reporter.removeHandler(failFastHandler);
1484 getConfiguredTarget("//pkg:BUILD");
brandjon2a73a732020-08-08 06:41:14 -07001485 assertContainsEvent("trying to mutate a frozen list value");
1486 }
1487
1488 @Test
1489 public void testPreludeCanAccessBzlDialectFeatures() throws Exception {
1490 scratch.file("tools/build_rules/BUILD");
1491 // Test both bzl symbols and syntax (e.g. function defs).
1492 scratch.file(
1493 "tools/build_rules/test_prelude", //
1494 "def foo():",
1495 " return native.glob");
1496 scratch.file(
1497 "pkg/BUILD", //
1498 "print(foo())");
1499
1500 getConfiguredTarget("//pkg:BUILD");
1501 // Prelude can access native.glob (though only a BUILD thread can call it).
adonovan800117e2020-09-18 10:30:06 -07001502 assertContainsEvent("<built-in method glob of native value>");
brandjon38dafdd2020-08-06 09:49:13 -07001503 }
1504
1505 @Test
1506 public void testPreludeNeedNotBePresent() throws Exception {
1507 scratch.file(
1508 "pkg/BUILD", //
1509 "print('FOO')");
1510
1511 getConfiguredTarget("//pkg:BUILD");
1512 assertContainsEvent("FOO");
1513 }
1514
1515 @Test
brandjon2a73a732020-08-08 06:41:14 -07001516 public void testPreludeNeedNotBePresent_evenWhenPackageIs() throws Exception {
1517 scratch.file("tools/build_rules/BUILD");
1518 scratch.file(
1519 "pkg/BUILD", //
1520 "print('FOO')");
1521
1522 getConfiguredTarget("//pkg:BUILD");
1523 assertContainsEvent("FOO");
1524 }
1525
1526 @Test
brandjon38dafdd2020-08-06 09:49:13 -07001527 public void testPreludeFileNotRecognizedWithoutPackage() throws Exception {
1528 scratch.file(
1529 "tools/build_rules/test_prelude", //
1530 "foo = 'FOO'");
1531 scratch.file(
1532 "pkg/BUILD", //
1533 "print(foo)");
1534
1535 // The prelude file is not found without a corresponding package to contain it. BUILD files
1536 // get processed as if no prelude file is present.
1537 reporter.removeHandler(failFastHandler);
1538 getConfiguredTarget("//pkg:BUILD");
1539 assertContainsEvent("name 'foo' is not defined");
1540 }
1541
1542 @Test
1543 public void testPreludeFailsWhenErrorInPreludeFile() throws Exception {
1544 scratch.file("tools/build_rules/BUILD");
1545 scratch.file(
1546 "tools/build_rules/test_prelude", //
1547 "1//0", // <-- dynamic error
1548 "foo = 'FOO'");
1549 scratch.file(
1550 "pkg/BUILD", //
1551 "print(foo)");
1552
1553 reporter.removeHandler(failFastHandler);
1554 getConfiguredTarget("//pkg:BUILD");
1555 assertContainsEvent(
1556 "File \"/workspace/tools/build_rules/test_prelude\", line 1, column 2, in <toplevel>");
1557 assertContainsEvent("Error: integer division by zero");
1558 }
1559
1560 @Test
1561 public void testPreludeWorksEvenWhenPreludePackageInError() throws Exception {
1562 scratch.file(
1563 "tools/build_rules/BUILD", //
1564 "1//0"); // <-- dynamic error
1565 scratch.file(
1566 "tools/build_rules/test_prelude", //
1567 "foo = 'FOO'");
1568 scratch.file(
1569 "pkg/BUILD", //
1570 "print(foo)");
1571
1572 // Succeeds because prelude loading is only dependent on the prelude package's existence, not
1573 // its evaluation.
1574 getConfiguredTarget("//pkg:BUILD");
1575 assertContainsEvent("FOO");
1576 }
1577
1578 // Another hypothetical test case we could try: Confirm that it's possible to explicitly load
1579 // the prelude file as a regular .bzl. We don't bother testing this use case because, aside from
1580 // being arguably pathological, it is currently impossible in practice: The prelude label
1581 // doesn't end with ".bzl" and isn't configurable by the user. We also want to eliminate the
1582 // prelude, so there's no intention of adding such a feature.
1583
1584 // Another possible test case: Verify how prelude applies to WORKSPACE files.
1585 }
1586
Kristina Chodorow335f0672015-11-16 23:19:13 +00001587 private static class CustomInMemoryFs extends InMemoryFileSystem {
Googlerc804c662016-12-01 16:53:28 +00001588 private abstract static class FileStatusOrException {
1589 abstract FileStatus get() throws IOException;
1590
1591 private static class ExceptionImpl extends FileStatusOrException {
1592 private final IOException exn;
1593
1594 private ExceptionImpl(IOException exn) {
1595 this.exn = exn;
1596 }
1597
1598 @Override
1599 FileStatus get() throws IOException {
1600 throw exn;
1601 }
1602 }
1603
1604 private static class FileStatusImpl extends FileStatusOrException {
1605
laurentlbc0bd2102018-10-17 07:05:25 -07001606 @Nullable private final FileStatus fileStatus;
Googlerc804c662016-12-01 16:53:28 +00001607
laurentlbc0bd2102018-10-17 07:05:25 -07001608 private FileStatusImpl(@Nullable FileStatus fileStatus) {
Googlerc804c662016-12-01 16:53:28 +00001609 this.fileStatus = fileStatus;
1610 }
1611
1612 @Override
1613 @Nullable
1614 FileStatus get() {
1615 return fileStatus;
1616 }
1617 }
1618 }
1619
ajurkowski8883c612021-03-08 08:12:37 -08001620 private final Map<PathFragment, FileStatusOrException> stubbedStats = Maps.newHashMap();
1621 private final Set<PathFragment> makeUnreadableAfterReaddir = Sets.newHashSet();
1622 private final Map<PathFragment, IOException> pathsToErrorOnGetInputStream = Maps.newHashMap();
Kristina Chodorow335f0672015-11-16 23:19:13 +00001623
1624 public CustomInMemoryFs(ManualClock manualClock) {
janakr97c0bd12020-09-08 13:19:03 -07001625 super(manualClock, DigestHashFunction.SHA256);
Kristina Chodorow335f0672015-11-16 23:19:13 +00001626 }
1627
aehligc801c392017-12-19 07:12:25 -08001628 public void stubStat(Path path, @Nullable FileStatus stubbedResult) {
ajurkowski8883c612021-03-08 08:12:37 -08001629 stubbedStats.put(path.asFragment(), new FileStatusOrException.FileStatusImpl(stubbedResult));
Kristina Chodorow335f0672015-11-16 23:19:13 +00001630 }
1631
aehligc801c392017-12-19 07:12:25 -08001632 public void stubStatError(Path path, IOException stubbedResult) {
ajurkowski8883c612021-03-08 08:12:37 -08001633 stubbedStats.put(path.asFragment(), new FileStatusOrException.ExceptionImpl(stubbedResult));
Kristina Chodorow335f0672015-11-16 23:19:13 +00001634 }
1635
1636 @Override
ajurkowski8883c612021-03-08 08:12:37 -08001637 public FileStatus statIfFound(PathFragment path, boolean followSymlinks) throws IOException {
Googlerc804c662016-12-01 16:53:28 +00001638 if (stubbedStats.containsKey(path)) {
1639 return stubbedStats.get(path).get();
Kristina Chodorow335f0672015-11-16 23:19:13 +00001640 }
fellya205ed82018-09-10 11:52:34 -07001641 return super.statIfFound(path, followSymlinks);
Kristina Chodorow335f0672015-11-16 23:19:13 +00001642 }
1643
aehligc801c392017-12-19 07:12:25 -08001644 public void scheduleMakeUnreadableAfterReaddir(Path path) {
ajurkowski8883c612021-03-08 08:12:37 -08001645 makeUnreadableAfterReaddir.add(path.asFragment());
Kristina Chodorow335f0672015-11-16 23:19:13 +00001646 }
1647
1648 @Override
ajurkowski8883c612021-03-08 08:12:37 -08001649 public Collection<Dirent> readdir(PathFragment path, boolean followSymlinks)
1650 throws IOException {
Kristina Chodorow335f0672015-11-16 23:19:13 +00001651 Collection<Dirent> result = super.readdir(path, followSymlinks);
Googlerc804c662016-12-01 16:53:28 +00001652 if (makeUnreadableAfterReaddir.contains(path)) {
ajurkowski8883c612021-03-08 08:12:37 -08001653 setReadable(path, false);
Kristina Chodorow335f0672015-11-16 23:19:13 +00001654 }
1655 return result;
1656 }
nharmataff688bf2017-06-07 17:03:52 -04001657
aehligc801c392017-12-19 07:12:25 -08001658 public void throwExceptionOnGetInputStream(Path path, IOException exn) {
ajurkowski8883c612021-03-08 08:12:37 -08001659 pathsToErrorOnGetInputStream.put(path.asFragment(), exn);
nharmataff688bf2017-06-07 17:03:52 -04001660 }
1661
1662 @Override
janakra4a564a2021-03-18 12:40:11 -07001663 protected synchronized InputStream getInputStream(PathFragment path) throws IOException {
nharmataff688bf2017-06-07 17:03:52 -04001664 IOException exnToThrow = pathsToErrorOnGetInputStream.get(path);
1665 if (exnToThrow != null) {
1666 throw exnToThrow;
1667 }
1668 return super.getInputStream(path);
1669 }
Kristina Chodorow335f0672015-11-16 23:19:13 +00001670 }
Kristina Chodorow335f0672015-11-16 23:19:13 +00001671}