blob: 35a1678f27a1ca73bf2fe6606c614678fb5b1feb [file] [log] [blame]
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +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.
14package com.google.devtools.build.lib.skyframe;
15
16import static com.google.common.truth.Truth.assertThat;
Janak Ramakrishnan112840b2016-12-29 21:49:56 +000017import static com.google.devtools.build.skyframe.WalkableGraphUtils.exists;
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000018
tomlua155b532017-11-08 20:12:47 +010019import com.google.common.base.Preconditions;
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000020import com.google.common.collect.ImmutableList;
21import com.google.common.collect.ImmutableSet;
Florian Weikertcca703a2015-12-07 09:56:38 +000022import com.google.devtools.build.lib.analysis.util.BuildViewTestCase;
Kristina Chodorowa1a31ff2016-07-27 16:34:27 +000023import com.google.devtools.build.lib.cmdline.RepositoryName;
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000024import com.google.devtools.build.lib.vfs.Path;
25import com.google.devtools.build.lib.vfs.PathFragment;
tomluee6a6862018-01-17 14:36:26 -080026import com.google.devtools.build.lib.vfs.Root;
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000027import com.google.devtools.build.lib.vfs.RootedPath;
Googler10028672018-10-25 12:14:34 -070028import com.google.devtools.build.skyframe.EvaluationContext;
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000029import com.google.devtools.build.skyframe.EvaluationResult;
30import com.google.devtools.build.skyframe.SkyKey;
31import com.google.devtools.build.skyframe.WalkableGraph;
Florian Weikert92b22362015-12-03 10:17:18 +000032import org.junit.Test;
33import org.junit.runner.RunWith;
34import org.junit.runners.JUnit4;
35
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000036/**
37 * Tests for {@link RecursivePkgFunction}. Unfortunately, we can't directly test
38 * RecursivePkgFunction as it uses PackageValues, and PackageFunction uses legacy stuff that
39 * isn't easily mockable. So our testing strategy is to make hacky calls to
40 * SequencedSkyframeExecutor.
41 *
42 * <p>Target parsing tests already cover most of the behavior of RecursivePkgFunction, but there
43 * are a couple of corner cases we need to test directly.
44 */
Florian Weikert92b22362015-12-03 10:17:18 +000045@RunWith(JUnit4.class)
Florian Weikertcca703a2015-12-07 09:56:38 +000046public class RecursivePkgFunctionTest extends BuildViewTestCase {
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000047
ajurkowskie2982912020-04-09 10:32:08 -070048 private static SkyKey buildRecursivePkgKey(
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000049 Path root, PathFragment rootRelativePath, ImmutableSet<PathFragment> excludedPaths) {
tomluee6a6862018-01-17 14:36:26 -080050 RootedPath rootedPath = RootedPath.toRootedPath(Root.fromPath(root), rootRelativePath);
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000051 return RecursivePkgValue.key(
Kristina Chodorowa1a31ff2016-07-27 16:34:27 +000052 RepositoryName.MAIN, rootedPath, excludedPaths);
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000053 }
54
55 private RecursivePkgValue buildRecursivePkgValue(Path root, PathFragment rootRelativePath)
56 throws Exception {
carmid6a98282018-03-13 19:19:16 -070057 return buildRecursivePkgValue(root, rootRelativePath, ImmutableSet.of());
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000058 }
59
60 private RecursivePkgValue buildRecursivePkgValue(
61 Path root, PathFragment rootRelativePath, ImmutableSet<PathFragment> excludedPaths)
62 throws Exception {
63 SkyKey key = buildRecursivePkgKey(root, rootRelativePath, excludedPaths);
64 return getEvaluationResult(key).get(key);
65 }
66
67 private EvaluationResult<RecursivePkgValue> getEvaluationResult(SkyKey key)
68 throws InterruptedException {
Googler10028672018-10-25 12:14:34 -070069 EvaluationContext evaluationContext =
70 EvaluationContext.newBuilder()
71 .setKeepGoing(false)
72 .setNumThreads(SequencedSkyframeExecutor.DEFAULT_THREAD_COUNT)
michajlo7a485be2020-07-30 11:08:46 -070073 .setEventHandler(reporter)
Googler10028672018-10-25 12:14:34 -070074 .build();
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000075 EvaluationResult<RecursivePkgValue> evaluationResult =
Googler0592f3f2019-07-12 09:00:46 -070076 skyframeExecutor.getDriver().evaluate(ImmutableList.of(key), evaluationContext);
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000077 Preconditions.checkState(!evaluationResult.hasError());
78 return evaluationResult;
79 }
80
Florian Weikert92b22362015-12-03 10:17:18 +000081 @Test
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000082 public void testStartingAtBuildFile() throws Exception {
83 scratch.file("a/b/c/BUILD");
84 RecursivePkgValue value =
nharmatab4060b62017-04-04 17:11:39 +000085 buildRecursivePkgValue(rootDirectory, PathFragment.create("a/b/c/BUILD"));
lberkiaea56b32017-05-30 12:35:33 +020086 assertThat(value.getPackages().isEmpty()).isTrue();
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000087 }
88
Florian Weikert92b22362015-12-03 10:17:18 +000089 @Test
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000090 public void testPackagesUnderMultipleRoots() throws Exception {
carmie3824d42018-04-03 14:58:26 -070091 // PackageLoader doesn't support --package_path.
92 initializeSkyframeExecutor(/*doPackageLoadingChecks=*/ false);
93 skyframeExecutor = getSkyframeExecutor();
94
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000095 Path root1 = rootDirectory.getRelative("root1");
96 Path root2 = rootDirectory.getRelative("root2");
97 scratch.file(root1 + "/WORKSPACE");
98 scratch.file(root2 + "/WORKSPACE");
99 scratch.file(root1 + "/a/BUILD");
100 scratch.file(root2 + "/a/b/BUILD");
ajurkowskid74b0ec2020-04-13 10:58:21 -0700101 setPackageOptions("--package_path=" + "root1" + ":" + "root2");
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000102
nharmatab4060b62017-04-04 17:11:39 +0000103 RecursivePkgValue valueForRoot1 = buildRecursivePkgValue(root1, PathFragment.create("a"));
ulfjack512244b2020-01-14 05:15:08 -0800104 String root1Pkg = valueForRoot1.getPackages().getSingleton();
lberkiaea56b32017-05-30 12:35:33 +0200105 assertThat(root1Pkg).isEqualTo("a");
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000106
nharmatab4060b62017-04-04 17:11:39 +0000107 RecursivePkgValue valueForRoot2 = buildRecursivePkgValue(root2, PathFragment.create("a"));
ulfjack512244b2020-01-14 05:15:08 -0800108 String root2Pkg = valueForRoot2.getPackages().getSingleton();
lberkiaea56b32017-05-30 12:35:33 +0200109 assertThat(root2Pkg).isEqualTo("a/b");
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000110 }
111
Florian Weikert92b22362015-12-03 10:17:18 +0000112 @Test
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000113 public void testSubdirectoryExclusion() throws Exception {
114 // Given a package "a" with two packages below it, "a/b" and "a/c",
115 scratch.file("a/BUILD");
116 scratch.file("a/b/BUILD");
117 scratch.file("a/c/BUILD");
118
119 // When the top package is evaluated for recursive package values, and "a/b" is excluded,
nharmatab4060b62017-04-04 17:11:39 +0000120 PathFragment excludedPathFragment = PathFragment.create("a/b");
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000121 SkyKey key =
122 buildRecursivePkgKey(
nharmatab4060b62017-04-04 17:11:39 +0000123 rootDirectory, PathFragment.create("a"), ImmutableSet.of(excludedPathFragment));
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000124 EvaluationResult<RecursivePkgValue> evaluationResult = getEvaluationResult(key);
125 RecursivePkgValue value = evaluationResult.get(key);
126
127 // Then the package corresponding to "a/b" is not present in the result,
ulfjack512244b2020-01-14 05:15:08 -0800128 assertThat(value.getPackages().toList()).doesNotContain("a/b");
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000129
130 // And the "a" package and "a/c" package are.
ulfjack512244b2020-01-14 05:15:08 -0800131 assertThat(value.getPackages().toList()).contains("a");
132 assertThat(value.getPackages().toList()).contains("a/c");
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000133
134 // Also, the computation graph does not contain a cached value for "a/b".
135 WalkableGraph graph = Preconditions.checkNotNull(evaluationResult.getWalkableGraph());
lberkiaea56b32017-05-30 12:35:33 +0200136 assertThat(
137 exists(
carmid6a98282018-03-13 19:19:16 -0700138 buildRecursivePkgKey(rootDirectory, excludedPathFragment, ImmutableSet.of()),
lberkiaea56b32017-05-30 12:35:33 +0200139 graph))
140 .isFalse();
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000141
142 // And the computation graph does contain a cached value for "a/c" with the empty set excluded,
143 // because that key was evaluated.
lberkiaea56b32017-05-30 12:35:33 +0200144 assertThat(
145 exists(
carmid6a98282018-03-13 19:19:16 -0700146 buildRecursivePkgKey(rootDirectory, PathFragment.create("a/c"), ImmutableSet.of()),
lberkiaea56b32017-05-30 12:35:33 +0200147 graph))
148 .isTrue();
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000149 }
150
Florian Weikert92b22362015-12-03 10:17:18 +0000151 @Test
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000152 public void testExcludedSubdirectoryGettingPassedDown() throws Exception {
153 // Given a package "a" with two packages below a directory below it, "a/b/c" and "a/b/d",
154 scratch.file("a/BUILD");
155 scratch.file("a/b/c/BUILD");
156 scratch.file("a/b/d/BUILD");
157
158 // When the top package is evaluated for recursive package values, and "a/b/c" is excluded,
nharmatab4060b62017-04-04 17:11:39 +0000159 ImmutableSet<PathFragment> excludedPaths = ImmutableSet.of(PathFragment.create("a/b/c"));
160 SkyKey key = buildRecursivePkgKey(rootDirectory, PathFragment.create("a"), excludedPaths);
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000161 EvaluationResult<RecursivePkgValue> evaluationResult = getEvaluationResult(key);
162 RecursivePkgValue value = evaluationResult.get(key);
163
164 // Then the package corresponding to the excluded subdirectory is not present in the result,
ulfjack512244b2020-01-14 05:15:08 -0800165 assertThat(value.getPackages().toList()).doesNotContain("a/b/c");
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000166
167 // And the top package and other subsubdirectory package are.
ulfjack512244b2020-01-14 05:15:08 -0800168 assertThat(value.getPackages().toList()).contains("a");
169 assertThat(value.getPackages().toList()).contains("a/b/d");
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000170
171 // Also, the computation graph contains a cached value for "a/b" with "a/b/c" excluded, because
172 // "a/b/c" does live underneath "a/b".
173 WalkableGraph graph = Preconditions.checkNotNull(evaluationResult.getWalkableGraph());
lberkiaea56b32017-05-30 12:35:33 +0200174 assertThat(
175 exists(
176 buildRecursivePkgKey(rootDirectory, PathFragment.create("a/b"), excludedPaths),
177 graph))
178 .isTrue();
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000179 }
180}