blob: 16a1ff78dec964ea15952f109ec5981b3c985c45 [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;
22import com.google.common.collect.Iterables;
Florian Weikertcca703a2015-12-07 09:56:38 +000023import com.google.devtools.build.lib.analysis.util.BuildViewTestCase;
Kristina Chodorowa1a31ff2016-07-27 16:34:27 +000024import com.google.devtools.build.lib.cmdline.RepositoryName;
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000025import com.google.devtools.build.lib.vfs.Path;
26import com.google.devtools.build.lib.vfs.PathFragment;
tomluee6a6862018-01-17 14:36:26 -080027import com.google.devtools.build.lib.vfs.Root;
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000028import com.google.devtools.build.lib.vfs.RootedPath;
29import com.google.devtools.build.skyframe.BuildDriver;
Googler10028672018-10-25 12:14:34 -070030import com.google.devtools.build.skyframe.EvaluationContext;
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000031import com.google.devtools.build.skyframe.EvaluationResult;
32import com.google.devtools.build.skyframe.SkyKey;
33import com.google.devtools.build.skyframe.WalkableGraph;
Florian Weikert92b22362015-12-03 10:17:18 +000034import org.junit.Before;
35import org.junit.Test;
36import org.junit.runner.RunWith;
37import org.junit.runners.JUnit4;
38
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000039/**
40 * Tests for {@link RecursivePkgFunction}. Unfortunately, we can't directly test
41 * RecursivePkgFunction as it uses PackageValues, and PackageFunction uses legacy stuff that
42 * isn't easily mockable. So our testing strategy is to make hacky calls to
43 * SequencedSkyframeExecutor.
44 *
45 * <p>Target parsing tests already cover most of the behavior of RecursivePkgFunction, but there
46 * are a couple of corner cases we need to test directly.
47 */
Florian Weikert92b22362015-12-03 10:17:18 +000048@RunWith(JUnit4.class)
Florian Weikertcca703a2015-12-07 09:56:38 +000049public class RecursivePkgFunctionTest extends BuildViewTestCase {
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000050
51 private SkyframeExecutor skyframeExecutor;
52
Florian Weikert92b22362015-12-03 10:17:18 +000053 @Before
54 public final void createSkyframeExecutor() throws Exception {
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000055 skyframeExecutor = getSkyframeExecutor();
56 }
57
58 private SkyKey buildRecursivePkgKey(
59 Path root, PathFragment rootRelativePath, ImmutableSet<PathFragment> excludedPaths) {
tomluee6a6862018-01-17 14:36:26 -080060 RootedPath rootedPath = RootedPath.toRootedPath(Root.fromPath(root), rootRelativePath);
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000061 return RecursivePkgValue.key(
Kristina Chodorowa1a31ff2016-07-27 16:34:27 +000062 RepositoryName.MAIN, rootedPath, excludedPaths);
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000063 }
64
65 private RecursivePkgValue buildRecursivePkgValue(Path root, PathFragment rootRelativePath)
66 throws Exception {
carmid6a98282018-03-13 19:19:16 -070067 return buildRecursivePkgValue(root, rootRelativePath, ImmutableSet.of());
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000068 }
69
70 private RecursivePkgValue buildRecursivePkgValue(
71 Path root, PathFragment rootRelativePath, ImmutableSet<PathFragment> excludedPaths)
72 throws Exception {
73 SkyKey key = buildRecursivePkgKey(root, rootRelativePath, excludedPaths);
74 return getEvaluationResult(key).get(key);
75 }
76
77 private EvaluationResult<RecursivePkgValue> getEvaluationResult(SkyKey key)
78 throws InterruptedException {
79 BuildDriver driver = skyframeExecutor.getDriverForTesting();
Googler10028672018-10-25 12:14:34 -070080 EvaluationContext evaluationContext =
81 EvaluationContext.newBuilder()
82 .setKeepGoing(false)
83 .setNumThreads(SequencedSkyframeExecutor.DEFAULT_THREAD_COUNT)
84 .setEventHander(reporter)
85 .build();
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000086 EvaluationResult<RecursivePkgValue> evaluationResult =
Googler10028672018-10-25 12:14:34 -070087 driver.evaluate(ImmutableList.of(key), evaluationContext);
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000088 Preconditions.checkState(!evaluationResult.hasError());
89 return evaluationResult;
90 }
91
Florian Weikert92b22362015-12-03 10:17:18 +000092 @Test
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000093 public void testStartingAtBuildFile() throws Exception {
94 scratch.file("a/b/c/BUILD");
95 RecursivePkgValue value =
nharmatab4060b62017-04-04 17:11:39 +000096 buildRecursivePkgValue(rootDirectory, PathFragment.create("a/b/c/BUILD"));
lberkiaea56b32017-05-30 12:35:33 +020097 assertThat(value.getPackages().isEmpty()).isTrue();
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000098 }
99
Florian Weikert92b22362015-12-03 10:17:18 +0000100 @Test
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000101 public void testPackagesUnderMultipleRoots() throws Exception {
carmie3824d42018-04-03 14:58:26 -0700102 // PackageLoader doesn't support --package_path.
103 initializeSkyframeExecutor(/*doPackageLoadingChecks=*/ false);
104 skyframeExecutor = getSkyframeExecutor();
105
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000106 Path root1 = rootDirectory.getRelative("root1");
107 Path root2 = rootDirectory.getRelative("root2");
108 scratch.file(root1 + "/WORKSPACE");
109 scratch.file(root2 + "/WORKSPACE");
110 scratch.file(root1 + "/a/BUILD");
111 scratch.file(root2 + "/a/b/BUILD");
112 setPackageCacheOptions("--package_path=" + "root1" + ":" + "root2");
113
nharmatab4060b62017-04-04 17:11:39 +0000114 RecursivePkgValue valueForRoot1 = buildRecursivePkgValue(root1, PathFragment.create("a"));
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000115 String root1Pkg = Iterables.getOnlyElement(valueForRoot1.getPackages());
lberkiaea56b32017-05-30 12:35:33 +0200116 assertThat(root1Pkg).isEqualTo("a");
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000117
nharmatab4060b62017-04-04 17:11:39 +0000118 RecursivePkgValue valueForRoot2 = buildRecursivePkgValue(root2, PathFragment.create("a"));
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000119 String root2Pkg = Iterables.getOnlyElement(valueForRoot2.getPackages());
lberkiaea56b32017-05-30 12:35:33 +0200120 assertThat(root2Pkg).isEqualTo("a/b");
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000121 }
122
Florian Weikert92b22362015-12-03 10:17:18 +0000123 @Test
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000124 public void testSubdirectoryExclusion() throws Exception {
125 // Given a package "a" with two packages below it, "a/b" and "a/c",
126 scratch.file("a/BUILD");
127 scratch.file("a/b/BUILD");
128 scratch.file("a/c/BUILD");
129
130 // When the top package is evaluated for recursive package values, and "a/b" is excluded,
nharmatab4060b62017-04-04 17:11:39 +0000131 PathFragment excludedPathFragment = PathFragment.create("a/b");
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000132 SkyKey key =
133 buildRecursivePkgKey(
nharmatab4060b62017-04-04 17:11:39 +0000134 rootDirectory, PathFragment.create("a"), ImmutableSet.of(excludedPathFragment));
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000135 EvaluationResult<RecursivePkgValue> evaluationResult = getEvaluationResult(key);
136 RecursivePkgValue value = evaluationResult.get(key);
137
138 // Then the package corresponding to "a/b" is not present in the result,
139 assertThat(value.getPackages()).doesNotContain("a/b");
140
141 // And the "a" package and "a/c" package are.
142 assertThat(value.getPackages()).contains("a");
143 assertThat(value.getPackages()).contains("a/c");
144
145 // Also, the computation graph does not contain a cached value for "a/b".
146 WalkableGraph graph = Preconditions.checkNotNull(evaluationResult.getWalkableGraph());
lberkiaea56b32017-05-30 12:35:33 +0200147 assertThat(
148 exists(
carmid6a98282018-03-13 19:19:16 -0700149 buildRecursivePkgKey(rootDirectory, excludedPathFragment, ImmutableSet.of()),
lberkiaea56b32017-05-30 12:35:33 +0200150 graph))
151 .isFalse();
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000152
153 // And the computation graph does contain a cached value for "a/c" with the empty set excluded,
154 // because that key was evaluated.
lberkiaea56b32017-05-30 12:35:33 +0200155 assertThat(
156 exists(
carmid6a98282018-03-13 19:19:16 -0700157 buildRecursivePkgKey(rootDirectory, PathFragment.create("a/c"), ImmutableSet.of()),
lberkiaea56b32017-05-30 12:35:33 +0200158 graph))
159 .isTrue();
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000160 }
161
Florian Weikert92b22362015-12-03 10:17:18 +0000162 @Test
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000163 public void testExcludedSubdirectoryGettingPassedDown() throws Exception {
164 // Given a package "a" with two packages below a directory below it, "a/b/c" and "a/b/d",
165 scratch.file("a/BUILD");
166 scratch.file("a/b/c/BUILD");
167 scratch.file("a/b/d/BUILD");
168
169 // When the top package is evaluated for recursive package values, and "a/b/c" is excluded,
nharmatab4060b62017-04-04 17:11:39 +0000170 ImmutableSet<PathFragment> excludedPaths = ImmutableSet.of(PathFragment.create("a/b/c"));
171 SkyKey key = buildRecursivePkgKey(rootDirectory, PathFragment.create("a"), excludedPaths);
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000172 EvaluationResult<RecursivePkgValue> evaluationResult = getEvaluationResult(key);
173 RecursivePkgValue value = evaluationResult.get(key);
174
175 // Then the package corresponding to the excluded subdirectory is not present in the result,
176 assertThat(value.getPackages()).doesNotContain("a/b/c");
177
178 // And the top package and other subsubdirectory package are.
179 assertThat(value.getPackages()).contains("a");
180 assertThat(value.getPackages()).contains("a/b/d");
181
182 // Also, the computation graph contains a cached value for "a/b" with "a/b/c" excluded, because
183 // "a/b/c" does live underneath "a/b".
184 WalkableGraph graph = Preconditions.checkNotNull(evaluationResult.getWalkableGraph());
lberkiaea56b32017-05-30 12:35:33 +0200185 assertThat(
186 exists(
187 buildRecursivePkgKey(rootDirectory, PathFragment.create("a/b"), excludedPaths),
188 graph))
189 .isTrue();
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000190 }
191}