blob: f5ef62433665e5b21b84cc0855b32deedb341265 [file] [log] [blame]
ajmichaeledcd9152017-05-01 19:56:06 +02001// 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.
14package com.google.devtools.build.lib.packages;
15
16import static com.google.common.truth.Truth.assertThat;
michajlo660d17f2020-03-27 09:01:57 -070017import static org.junit.Assert.assertThrows;
ajmichaeledcd9152017-05-01 19:56:06 +020018
lberki7abdcb42019-10-22 02:17:13 -070019import com.google.common.collect.ImmutableSet;
ajmichaeledcd9152017-05-01 19:56:06 +020020import com.google.common.collect.Lists;
janakr13b737a2021-07-02 14:24:25 -070021import com.google.devtools.build.lib.actions.ThreadStateReceiver;
Googler298da7b2024-10-15 05:18:43 -070022import com.google.devtools.build.lib.cmdline.IgnoredSubdirectories;
ajmichaeledcd9152017-05-01 19:56:06 +020023import com.google.devtools.build.lib.cmdline.PackageIdentifier;
24import com.google.devtools.build.lib.packages.Globber.BadGlobException;
25import com.google.devtools.build.lib.testutil.Scratch;
ajmichaeledcd9152017-05-01 19:56:06 +020026import com.google.devtools.build.lib.util.Pair;
ajmichaeledcd9152017-05-01 19:56:06 +020027import com.google.devtools.build.lib.vfs.Path;
lberki7abdcb42019-10-22 02:17:13 -070028import com.google.devtools.build.lib.vfs.PathFragment;
janakrfc1d79c2022-01-27 13:02:07 -080029import com.google.devtools.build.lib.vfs.SyscallCache;
ajmichaeledcd9152017-05-01 19:56:06 +020030import java.util.ArrayList;
31import java.util.Arrays;
32import java.util.Collection;
33import java.util.Collections;
34import java.util.List;
michajloa731acd12021-12-29 12:34:00 -080035import java.util.concurrent.ExecutorService;
36import java.util.concurrent.Executors;
ajmichaeledcd9152017-05-01 19:56:06 +020037import org.junit.After;
38import org.junit.Before;
39import org.junit.Test;
40import org.junit.runner.RunWith;
41import org.junit.runners.JUnit4;
42
43/**
44 * Tests for {@link GlobCache}
45 */
46@RunWith(JUnit4.class)
47public class GlobCacheTest {
48
49 private static final List<String> NONE = Collections.emptyList();
50
51 private Scratch scratch = new Scratch("/workspace");
52
53 private Path packageDirectory;
54 private Path buildFile;
michajloa731acd12021-12-29 12:34:00 -080055 private ExecutorService cacheThreadPool;
ajmichaeledcd9152017-05-01 19:56:06 +020056 private GlobCache cache;
57
58 @Before
59 public final void createFiles() throws Exception {
60 buildFile = scratch.file("isolated/BUILD",
61 "# contents don't matter in this test");
62 scratch.file("isolated/sub/BUILD",
63 "# contents don't matter in this test");
64
65 packageDirectory = buildFile.getParentDirectory();
66
67 scratch.file("isolated/first.txt",
68 "# this is first.txt");
69
70 scratch.file("isolated/second.txt",
71 "# this is second.txt");
72
73 scratch.file("isolated/first.js",
74 "# this is first.js");
75
76 scratch.file("isolated/second.js",
77 "# this is second.js");
78
79 // Files in subdirectories
80
81 scratch.file("isolated/foo/first.js",
82 "# this is foo/first.js");
83
84 scratch.file("isolated/foo/second.js",
85 "# this is foo/second.js");
86
87 scratch.file("isolated/bar/first.js",
88 "# this is bar/first.js");
89
90 scratch.file("isolated/bar/second.js",
91 "# this is bar/second.js");
92
93 scratch.file("isolated/sub/sub.js",
94 "# this is sub/sub.js");
95
lberki7abdcb42019-10-22 02:17:13 -070096 createCache();
97 }
98
michajloa731acd12021-12-29 12:34:00 -080099 @After
100 public void shutDownThreadPoolIfExists() {
101 if (cacheThreadPool != null) {
102 cacheThreadPool.shutdownNow();
103 }
104 }
105
kkress1847a012020-06-24 12:30:11 -0700106 private void createCache(PathFragment... ignoredDirectories) {
michajloa731acd12021-12-29 12:34:00 -0800107 shutDownThreadPoolIfExists();
108 cacheThreadPool = Executors.newFixedThreadPool(10);
ajmichaeledcd9152017-05-01 19:56:06 +0200109 cache =
110 new GlobCache(
111 packageDirectory,
112 PackageIdentifier.createInMainRepo("isolated"),
Googler298da7b2024-10-15 05:18:43 -0700113 IgnoredSubdirectories.of(ImmutableSet.copyOf(ignoredDirectories)),
ajmichaeledcd9152017-05-01 19:56:06 +0200114 new CachingPackageLocator() {
115 @Override
116 public Path getBuildFileForPackage(PackageIdentifier packageId) {
117 String packageName = packageId.getPackageFragment().getPathString();
118 if (packageName.equals("isolated")) {
119 return scratch.resolve("isolated/BUILD");
120 } else if (packageName.equals("isolated/sub")) {
121 return scratch.resolve("isolated/sub/BUILD");
122 } else {
123 return null;
124 }
125 }
janakr845f7c12021-08-10 13:14:03 -0700126
127 @Override
128 public String getBaseNameForLoadedPackage(PackageIdentifier packageName) {
129 Path buildFileForPackage = getBuildFileForPackage(packageName);
130 return buildFileForPackage == null ? null : buildFileForPackage.getBaseName();
131 }
ajmichaeledcd9152017-05-01 19:56:06 +0200132 },
janakrfc1d79c2022-01-27 13:02:07 -0800133 SyscallCache.NO_CACHE,
michajloa731acd12021-12-29 12:34:00 -0800134 cacheThreadPool,
janakr13b737a2021-07-02 14:24:25 -0700135 -1,
136 ThreadStateReceiver.NULL_INSTANCE);
ajmichaeledcd9152017-05-01 19:56:06 +0200137 }
138
139 @After
140 public final void deleteFiles() throws Exception {
jmmv5cc1f652019-03-20 09:34:08 -0700141 scratch.getFileSystem().getPath("/").deleteTreesBelow();
ajmichaeledcd9152017-05-01 19:56:06 +0200142 }
143
144 @Test
kkress1847a012020-06-24 12:30:11 -0700145 public void testIgnoredDirectory() throws Exception {
lberki7abdcb42019-10-22 02:17:13 -0700146 createCache(PathFragment.create("isolated/foo"));
kkress7dbabb42022-01-11 14:24:38 -0800147 List<Path> paths = cache.safeGlobUnsorted("**/*.js", Globber.Operation.FILES).get();
lberki7abdcb42019-10-22 02:17:13 -0700148 assertPathsAre(
149 paths,
150 "/workspace/isolated/first.js",
151 "/workspace/isolated/second.js",
152 "/workspace/isolated/bar/first.js",
153 "/workspace/isolated/bar/second.js");
154 }
155
156 @Test
ajmichaeledcd9152017-05-01 19:56:06 +0200157 public void testSafeGlob() throws Exception {
kkress7dbabb42022-01-11 14:24:38 -0800158 List<Path> paths = cache.safeGlobUnsorted("*.js", Globber.Operation.FILES_AND_DIRS).get();
ajmichaeledcd9152017-05-01 19:56:06 +0200159 assertPathsAre(paths,
160 "/workspace/isolated/first.js", "/workspace/isolated/second.js");
161 }
162
163 @Test
Jonathan Bluett-Duncan52c04172017-06-21 16:37:42 +0200164 public void testSafeGlobInvalidPattern() throws Exception {
165 String invalidPattern = "Foo?.txt";
kkress7dbabb42022-01-11 14:24:38 -0800166 assertThrows(
167 BadGlobException.class,
168 () -> cache.safeGlobUnsorted(invalidPattern, Globber.Operation.FILES_AND_DIRS).get());
ajmichaeledcd9152017-05-01 19:56:06 +0200169 }
170
171 @Test
172 public void testGetGlob() throws Exception {
173 List<String> glob = cache.getGlobUnsorted("*.js");
174 assertThat(glob).containsExactly("first.js", "second.js");
175 }
176
177 @Test
178 public void testGetGlob_subdirectory() throws Exception {
179 List<String> glob = cache.getGlobUnsorted("foo/*.js");
180 assertThat(glob).containsExactly("foo/first.js", "foo/second.js");
181 }
182
183 @Test
184 public void testGetKeySet() throws Exception {
185 assertThat(cache.getKeySet()).isEmpty();
186
187 cache.getGlobUnsorted("*.java");
kkress7dbabb42022-01-11 14:24:38 -0800188 assertThat(cache.getKeySet())
189 .containsExactly(Pair.of("*.java", Globber.Operation.FILES_AND_DIRS));
ajmichaeledcd9152017-05-01 19:56:06 +0200190
191 cache.getGlobUnsorted("*.java");
kkress7dbabb42022-01-11 14:24:38 -0800192 assertThat(cache.getKeySet())
193 .containsExactly(Pair.of("*.java", Globber.Operation.FILES_AND_DIRS));
ajmichaeledcd9152017-05-01 19:56:06 +0200194
195 cache.getGlobUnsorted("*.js");
kkress7dbabb42022-01-11 14:24:38 -0800196 assertThat(cache.getKeySet())
197 .containsExactly(
198 Pair.of("*.java", Globber.Operation.FILES_AND_DIRS),
199 Pair.of("*.js", Globber.Operation.FILES_AND_DIRS));
ajmichaeledcd9152017-05-01 19:56:06 +0200200
kkress7dbabb42022-01-11 14:24:38 -0800201 cache.getGlobUnsorted("*.java", Globber.Operation.FILES);
202 assertThat(cache.getKeySet())
203 .containsExactly(
204 Pair.of("*.java", Globber.Operation.FILES_AND_DIRS),
205 Pair.of("*.js", Globber.Operation.FILES_AND_DIRS),
206 Pair.of("*.java", Globber.Operation.FILES));
ajmichaeledcd9152017-05-01 19:56:06 +0200207
jcaterb9226772019-04-29 12:04:52 -0700208 assertThrows(BadGlobException.class, () -> cache.getGlobUnsorted("invalid?"));
kkress7dbabb42022-01-11 14:24:38 -0800209 assertThat(cache.getKeySet())
210 .containsExactly(
211 Pair.of("*.java", Globber.Operation.FILES_AND_DIRS),
212 Pair.of("*.js", Globber.Operation.FILES_AND_DIRS),
213 Pair.of("*.java", Globber.Operation.FILES));
ajmichaeledcd9152017-05-01 19:56:06 +0200214
215 cache.getGlobUnsorted("foo/first.*");
kkress7dbabb42022-01-11 14:24:38 -0800216 assertThat(cache.getKeySet())
217 .containsExactly(
218 Pair.of("*.java", Globber.Operation.FILES_AND_DIRS),
219 Pair.of("*.java", Globber.Operation.FILES),
220 Pair.of("*.js", Globber.Operation.FILES_AND_DIRS),
221 Pair.of("foo/first.*", Globber.Operation.FILES_AND_DIRS));
ajmichaeledcd9152017-05-01 19:56:06 +0200222 }
223
224 @Test
225 public void testGlob() throws Exception {
kkress7dbabb42022-01-11 14:24:38 -0800226 assertEmpty(cache.globUnsorted(list("*.java"), NONE, Globber.Operation.FILES, true));
ajmichaeledcd9152017-05-01 19:56:06 +0200227
kkress7dbabb42022-01-11 14:24:38 -0800228 assertThat(cache.globUnsorted(list("*.*"), NONE, Globber.Operation.FILES, true))
laurentlbb340fb02019-04-29 09:38:19 -0700229 .containsExactly("first.js", "first.txt", "second.js", "second.txt");
ajmichaeledcd9152017-05-01 19:56:06 +0200230
kkress7dbabb42022-01-11 14:24:38 -0800231 assertThat(cache.globUnsorted(list("*.*"), list("first.js"), Globber.Operation.FILES, true))
laurentlbb340fb02019-04-29 09:38:19 -0700232 .containsExactly("first.txt", "second.js", "second.txt");
ajmichaeledcd9152017-05-01 19:56:06 +0200233
kkress7dbabb42022-01-11 14:24:38 -0800234 assertThat(cache.globUnsorted(list("*.txt", "first.*"), NONE, Globber.Operation.FILES, true))
laurentlbb340fb02019-04-29 09:38:19 -0700235 .containsExactly("first.txt", "second.txt", "first.js");
ajmichaeledcd9152017-05-01 19:56:06 +0200236 }
237
238 @Test
239 public void testRecursiveGlobDoesNotMatchSubpackage() throws Exception {
240 List<String> glob = cache.getGlobUnsorted("**/*.js");
241 assertThat(glob).containsExactly("first.js", "second.js", "foo/first.js", "bar/first.js",
242 "foo/second.js", "bar/second.js");
243 }
244
245 @Test
jmmvbfbd95f2020-08-31 13:12:38 -0700246 public void testSingleFileExclude_star() throws Exception {
kkress7dbabb42022-01-11 14:24:38 -0800247 assertThat(
248 cache.globUnsorted(
249 list("*"), list("first.txt"), Globber.Operation.FILES_AND_DIRS, true))
laurentlbb340fb02019-04-29 09:38:19 -0700250 .containsExactly("BUILD", "bar", "first.js", "foo", "second.js", "second.txt");
ajmichaeledcd9152017-05-01 19:56:06 +0200251 }
252
253 @Test
jmmvbfbd95f2020-08-31 13:12:38 -0700254 public void testSingleFileExclude_starStar() throws Exception {
kkress7dbabb42022-01-11 14:24:38 -0800255 assertThat(
256 cache.globUnsorted(
257 list("**"), list("first.txt"), Globber.Operation.FILES_AND_DIRS, true))
laurentlbb340fb02019-04-29 09:38:19 -0700258 .containsExactly(
259 "BUILD",
260 "bar",
261 "bar/first.js",
262 "bar/second.js",
263 "first.js",
264 "foo",
265 "foo/first.js",
266 "foo/second.js",
267 "second.js",
268 "second.txt");
ajmichaeledcd9152017-05-01 19:56:06 +0200269 }
270
271 @Test
jmmvbfbd95f2020-08-31 13:12:38 -0700272 public void testExcludeAll_star() throws Exception {
kkress7dbabb42022-01-11 14:24:38 -0800273 assertThat(cache.globUnsorted(list("*"), list("*"), Globber.Operation.FILES_AND_DIRS, true))
274 .isEmpty();
ajmichaeledcd9152017-05-01 19:56:06 +0200275 }
276
277 @Test
jmmvbfbd95f2020-08-31 13:12:38 -0700278 public void testExcludeAll_star_noMatchesAnyway() throws Exception {
kkress7dbabb42022-01-11 14:24:38 -0800279 assertThat(cache.globUnsorted(list("nope"), list("*"), Globber.Operation.FILES_AND_DIRS, true))
280 .isEmpty();
ajmichaeledcd9152017-05-01 19:56:06 +0200281 }
282
283 @Test
jmmvbfbd95f2020-08-31 13:12:38 -0700284 public void testExcludeAll_starStar() throws Exception {
kkress7dbabb42022-01-11 14:24:38 -0800285 assertThat(cache.globUnsorted(list("**"), list("**"), Globber.Operation.FILES_AND_DIRS, true))
286 .isEmpty();
ajmichaeledcd9152017-05-01 19:56:06 +0200287 }
288
289 @Test
jmmvbfbd95f2020-08-31 13:12:38 -0700290 public void testExcludeAll_manual() throws Exception {
kkress7dbabb42022-01-11 14:24:38 -0800291 assertThat(
292 cache.globUnsorted(
293 list("**"), list("*", "*/*", "*/*/*"), Globber.Operation.FILES_AND_DIRS, true))
294 .isEmpty();
ajmichaeledcd9152017-05-01 19:56:06 +0200295 }
296
297 @Test
298 public void testSingleFileExcludeDoesntMatch() throws Exception {
kkress7dbabb42022-01-11 14:24:38 -0800299 assertThat(
300 cache.globUnsorted(
301 list("first.txt"), list("nope.txt"), Globber.Operation.FILES_AND_DIRS, true))
laurentlbb340fb02019-04-29 09:38:19 -0700302 .containsExactly("first.txt");
ajmichaeledcd9152017-05-01 19:56:06 +0200303 }
304
305 @Test
306 public void testExcludeDirectory() throws Exception {
kkress7dbabb42022-01-11 14:24:38 -0800307 assertThat(cache.globUnsorted(list("foo/*"), NONE, Globber.Operation.FILES, true))
laurentlbb340fb02019-04-29 09:38:19 -0700308 .containsExactly("foo/first.js", "foo/second.js");
kkress7dbabb42022-01-11 14:24:38 -0800309 assertThat(
310 cache.globUnsorted(list("foo/*"), list("foo"), Globber.Operation.FILES_AND_DIRS, true))
laurentlbb340fb02019-04-29 09:38:19 -0700311 .containsExactly("foo/first.js", "foo/second.js");
312 }
313
314 @Test
ajmichaeledcd9152017-05-01 19:56:06 +0200315 public void testChildGlobWithChildExclude() throws Exception {
ajmichaeledcd9152017-05-01 19:56:06 +0200316 assertThat(
kkress7dbabb42022-01-11 14:24:38 -0800317 cache.globUnsorted(
318 list("foo/*"), list("foo/*"), Globber.Operation.FILES_AND_DIRS, true))
laurentlbb340fb02019-04-29 09:38:19 -0700319 .isEmpty();
kkress7dbabb42022-01-11 14:24:38 -0800320 assertThat(
321 cache.globUnsorted(
322 list("foo/first.js", "foo/second.js"),
323 list("foo/*"),
324 Globber.Operation.FILES_AND_DIRS,
325 true))
laurentlbb340fb02019-04-29 09:38:19 -0700326 .isEmpty();
kkress7dbabb42022-01-11 14:24:38 -0800327 assertThat(
328 cache.globUnsorted(
329 list("foo/first.js"), list("foo/first.js"), Globber.Operation.FILES_AND_DIRS, true))
330 .isEmpty();
331 assertThat(
332 cache.globUnsorted(
333 list("foo/first.js"), list("*/first.js"), Globber.Operation.FILES_AND_DIRS, true))
334 .isEmpty();
335 assertThat(
336 cache.globUnsorted(
337 list("foo/first.js"), list("*/*"), Globber.Operation.FILES_AND_DIRS, true))
338 .isEmpty();
339 }
340
341 @Test
Googleref758fa2023-12-18 09:13:50 -0800342 public void testSubpackages_noWildcard() throws Exception {
343 assertThat(cache.globUnsorted(list("sub/sub.js"), list(), Globber.Operation.SUBPACKAGES, true))
344 .isEmpty();
345 }
346
347 @Test
348 public void testSubpackages_simpleDoubleStar() throws Exception {
kkress7dbabb42022-01-11 14:24:38 -0800349 assertThat(cache.globUnsorted(list("**"), list(), Globber.Operation.SUBPACKAGES, true))
350 .containsExactly("sub");
ajmichaeledcd9152017-05-01 19:56:06 +0200351 }
352
Googleref758fa2023-12-18 09:13:50 -0800353 @Test
354 public void testSubpackages_onlySub() throws Exception {
355 assertThat(cache.globUnsorted(list("sub"), list(), Globber.Operation.SUBPACKAGES, true))
356 .containsExactly("sub");
357 }
358
359 @Test
360 public void testSubpackages_singleStarsAfterSub() throws Exception {
361 assertThat(cache.globUnsorted(list("sub/*"), list(), Globber.Operation.SUBPACKAGES, true))
362 .isEmpty();
363 }
364
365 @Test
366 public void testSubpackages_doubleStarsAfterSub() throws Exception {
367 assertThat(cache.globUnsorted(list("sub/**"), list(), Globber.Operation.SUBPACKAGES, true))
368 .containsExactly("sub");
369 }
370
371 @Test
372 public void testSubpackages_twoDoubleStarsAfterSub() throws Exception {
373 // Both `**`s are considered to match no path fragments.
374 assertThat(cache.globUnsorted(list("sub/**/**"), list(), Globber.Operation.SUBPACKAGES, true))
375 .containsExactly("sub");
376 }
377
378 @Test
379 public void testSubpackages_doubleStarsAndOtherPathAfterSub() throws Exception {
380 assertThat(cache.globUnsorted(list("sub/**/foo"), list(), Globber.Operation.SUBPACKAGES, true))
381 .isEmpty();
382 }
383
384 @Test
385 public void testSubpackages_doubleStarWithTrailingPattern() throws Exception {
386 assertThat(cache.globUnsorted(list("**/bar"), list(), Globber.Operation.SUBPACKAGES, true))
387 .isEmpty();
388 }
389
ajmichaeledcd9152017-05-01 19:56:06 +0200390 private void assertEmpty(Collection<?> glob) {
391 assertThat(glob).isEmpty();
392 }
393
394 private void assertPathsAre(List<Path> paths, String... strings) {
395 List<String> pathStrings = new ArrayList<>();
396 for (Path path : paths) {
397 pathStrings.add(path.getPathString());
398 }
399 assertThat(pathStrings).containsExactlyElementsIn(Arrays.asList(strings));
400 }
401
402 /* syntactic shorthand for Lists.newArrayList(strings) */
Ulf Adams83763ee2015-05-04 15:36:12 +0000403 private List<String> list(String... strings) {
404 return Lists.newArrayList(strings);
405 }
406}