blob: b29ec04b0d083193ce71559eb06782f9ace96f73 [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 Ramakrishnan8d239cd2016-01-27 21:06:01 +000017import static com.google.devtools.build.skyframe.EvaluationResultSubjectFactory.assertThatEvaluationResult;
Florian Weikert92b22362015-12-03 10:17:18 +000018import static org.junit.Assert.assertFalse;
19import static org.junit.Assert.assertNotNull;
20import static org.junit.Assert.assertNull;
21import static org.junit.Assert.assertTrue;
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000022
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000023import com.google.common.collect.ImmutableList;
Florian Weikertcca703a2015-12-07 09:56:38 +000024import com.google.devtools.build.lib.analysis.util.BuildViewTestCase;
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000025import com.google.devtools.build.lib.cmdline.Label;
26import com.google.devtools.build.lib.packages.NoSuchPackageException;
27import com.google.devtools.build.lib.packages.NoSuchTargetException;
Mark Schaller6df81792015-12-10 18:47:47 +000028import com.google.devtools.build.lib.util.Preconditions;
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.SkyValue;
32import com.google.devtools.build.skyframe.WalkableGraph;
Janak Ramakrishnan3c0adb22016-08-15 21:54:55 +000033import java.io.IOException;
Florian Weikert92b22362015-12-03 10:17:18 +000034import org.junit.Test;
35import org.junit.runner.RunWith;
36import org.junit.runners.JUnit4;
37
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000038/** Tests for {@link com.google.devtools.build.lib.skyframe.PrepareDepsOfPatternsFunction}. */
Florian Weikert92b22362015-12-03 10:17:18 +000039@RunWith(JUnit4.class)
Florian Weikertcca703a2015-12-07 09:56:38 +000040public class PrepareDepsOfPatternsFunctionTest extends BuildViewTestCase {
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000041
42 private static SkyKey getKeyForLabel(Label label) {
43 // Note that these tests used to look for TargetMarker SkyKeys before TargetMarker was
44 // inlined in TransitiveTraversalFunction. Because TargetMarker is now inlined, it doesn't
45 // appear in the graph. Instead, these tests now look for TransitiveTraversal keys.
46 return TransitiveTraversalValue.key(label);
47 }
48
Florian Weikert92b22362015-12-03 10:17:18 +000049 @Test
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000050 public void testFunctionLoadsTargetAndNotUnspecifiedTargets() throws Exception {
51 // Given a package "//foo" with independent target rules ":foo" and ":foo2",
52 createFooAndFoo2(/*dependent=*/ false);
53
54 // Given a target pattern sequence consisting of a single-target pattern for "//foo",
55 ImmutableList<String> patternSequence = ImmutableList.of("//foo");
56
57 // When PrepareDepsOfPatternsFunction successfully completes evaluation,
Janak Ramakrishnan8d239cd2016-01-27 21:06:01 +000058 WalkableGraph walkableGraph = getGraphFromPatternsEvaluation(patternSequence);
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000059
Brian Silvermand7d6d622016-03-17 09:53:39 +000060 // Then the graph contains a value for the target "@//foo:foo",
61 assertValidValue(walkableGraph, getKeyForLabel(Label.create("@//foo", "foo")));
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000062
Brian Silvermand7d6d622016-03-17 09:53:39 +000063 // And the graph does not contain a value for the target "@//foo:foo2".
64 assertFalse(walkableGraph.exists(getKeyForLabel(Label.create("@//foo", "foo2"))));
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000065 }
66
Florian Weikert92b22362015-12-03 10:17:18 +000067 @Test
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000068 public void testFunctionLoadsTargetDependencies() throws Exception {
69 // Given a package "//foo" with target rules ":foo" and ":foo2",
70 // And given ":foo" depends on ":foo2",
71 createFooAndFoo2(/*dependent=*/ true);
72
73 // Given a target pattern sequence consisting of a single-target pattern for "//foo",
74 ImmutableList<String> patternSequence = ImmutableList.of("//foo");
75
76 // When PrepareDepsOfPatternsFunction successfully completes evaluation,
Janak Ramakrishnan8d239cd2016-01-27 21:06:01 +000077 WalkableGraph walkableGraph = getGraphFromPatternsEvaluation(patternSequence);
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000078
79 // Then the graph contains an entry for ":foo"'s dependency, ":foo2".
Brian Silvermand7d6d622016-03-17 09:53:39 +000080 assertValidValue(walkableGraph, getKeyForLabel(Label.create("@//foo", "foo2")));
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000081 }
82
Florian Weikert92b22362015-12-03 10:17:18 +000083 @Test
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000084 public void testFunctionExpandsTargetPatterns() throws Exception {
Brian Silvermand7d6d622016-03-17 09:53:39 +000085 // Given a package "@//foo" with independent target rules ":foo" and ":foo2",
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000086 createFooAndFoo2(/*dependent=*/ false);
87
88 // Given a target pattern sequence consisting of a pattern for "//foo:*",
89 ImmutableList<String> patternSequence = ImmutableList.of("//foo:*");
90
91 // When PrepareDepsOfPatternsFunction successfully completes evaluation,
Janak Ramakrishnan8d239cd2016-01-27 21:06:01 +000092 WalkableGraph walkableGraph = getGraphFromPatternsEvaluation(patternSequence);
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000093
94 // Then the graph contains an entry for ":foo" and ":foo2".
Brian Silvermand7d6d622016-03-17 09:53:39 +000095 assertValidValue(walkableGraph, getKeyForLabel(Label.create("@//foo", "foo")));
96 assertValidValue(walkableGraph, getKeyForLabel(Label.create("@//foo", "foo2")));
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000097 }
98
Florian Weikert92b22362015-12-03 10:17:18 +000099 @Test
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000100 public void testTargetParsingException() throws Exception {
101 // Given no packages, and a target pattern sequence referring to a non-existent target,
102 String nonexistentTarget = "//foo:foo";
103 ImmutableList<String> patternSequence = ImmutableList.of(nonexistentTarget);
104
105 // When PrepareDepsOfPatternsFunction completes evaluation,
Janak Ramakrishnan8d239cd2016-01-27 21:06:01 +0000106 WalkableGraph walkableGraph = getGraphFromPatternsEvaluation(patternSequence);
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000107
108 // Then the graph does not contain an entry for ":foo",
Brian Silvermand7d6d622016-03-17 09:53:39 +0000109 assertFalse(walkableGraph.exists(getKeyForLabel(Label.create("@//foo", "foo"))));
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 testDependencyTraversalNoSuchPackageException() throws Exception {
114 // Given a package "//foo" with a target ":foo" that has a dependency on a non-existent target
115 // "//bar:bar" in a non-existent package "//bar",
116 createFooWithDependencyOnMissingBarPackage();
117
118 // Given a target pattern sequence consisting of a single-target pattern for "//foo",
119 ImmutableList<String> patternSequence = ImmutableList.of("//foo");
120
121 // When PrepareDepsOfPatternsFunction completes evaluation,
Janak Ramakrishnan8d239cd2016-01-27 21:06:01 +0000122 WalkableGraph walkableGraph = getGraphFromPatternsEvaluation(patternSequence);
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000123
124 // Then the graph contains an entry for ":foo",
125 assertValidValue(
126 walkableGraph,
Brian Silvermand7d6d622016-03-17 09:53:39 +0000127 getKeyForLabel(Label.create("@//foo", "foo")),
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000128 /*expectTransitiveException=*/ true);
129
130 // And an entry with a NoSuchPackageException for "//bar:bar",
Brian Silvermand7d6d622016-03-17 09:53:39 +0000131 Exception e = assertException(walkableGraph, getKeyForLabel(Label.create("@//bar", "bar")));
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000132 assertThat(e).isInstanceOf(NoSuchPackageException.class);
133 }
134
Florian Weikert92b22362015-12-03 10:17:18 +0000135 @Test
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000136 public void testDependencyTraversalNoSuchTargetException() throws Exception {
137 // Given a package "//foo" with a target ":foo" that has a dependency on a non-existent target
138 // "//bar:bar" in an existing package "//bar",
139 createFooWithDependencyOnBarPackageWithMissingTarget();
140
141 // Given a target pattern sequence consisting of a single-target pattern for "//foo",
142 ImmutableList<String> patternSequence = ImmutableList.of("//foo");
143
144 // When PrepareDepsOfPatternsFunction completes evaluation,
Janak Ramakrishnan8d239cd2016-01-27 21:06:01 +0000145 WalkableGraph walkableGraph = getGraphFromPatternsEvaluation(patternSequence);
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000146
147 // Then the graph contains an entry for ":foo" which has both a value and an exception,
148 assertValidValue(
149 walkableGraph,
Brian Silvermand7d6d622016-03-17 09:53:39 +0000150 getKeyForLabel(Label.create("@//foo", "foo")),
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000151 /*expectTransitiveException=*/ true);
152
153 // And an entry with a NoSuchTargetException for "//bar:bar",
Brian Silvermand7d6d622016-03-17 09:53:39 +0000154 Exception e = assertException(walkableGraph, getKeyForLabel(Label.create("@//bar", "bar")));
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000155 assertThat(e).isInstanceOf(NoSuchTargetException.class);
156 }
157
Florian Weikert92b22362015-12-03 10:17:18 +0000158 @Test
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000159 public void testParsingProblemsKeepGoing() throws Exception {
160 parsingProblem(/*keepGoing=*/ true);
161 }
162
163 /**
Janak Ramakrishnan18d0a5d2016-11-16 19:35:48 +0000164 * PrepareDepsOfPatternsFunction always keeps going despite any target pattern parsing errors, in
165 * keeping with the original behavior of {@link WalkableGraph.WalkableGraphFactory#prepareAndGet},
166 * which always used {@code keepGoing=true} during target pattern parsing because it was
167 * responsible for ensuring that queries had a complete graph to work on.
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000168 */
Florian Weikert92b22362015-12-03 10:17:18 +0000169 @Test
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000170 public void testParsingProblemsNoKeepGoing() throws Exception {
171 parsingProblem(/*keepGoing=*/ false);
172 }
173
174 private void parsingProblem(boolean keepGoing) throws Exception {
175 // Given a package "//foo" with target rule ":foo",
176 createFooAndFoo2(/*dependent=*/ false);
177
178 // Given a target pattern sequence consisting of a pattern with parsing problems followed by
179 // a legit target pattern,
180 String bogusPattern = "//foo/....";
181 ImmutableList<String> patternSequence = ImmutableList.of(bogusPattern, "//foo:foo");
182
183 // When PrepareDepsOfPatternsFunction runs in the selected keep-going mode,
184 WalkableGraph walkableGraph =
Janak Ramakrishnan8d239cd2016-01-27 21:06:01 +0000185 getGraphFromPatternsEvaluation(patternSequence, /*keepGoing=*/ keepGoing);
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000186
187 // Then it skips evaluation of the malformed target pattern, but logs about it,
188 assertContainsEvent("Skipping '" + bogusPattern + "': ");
189
Brian Silvermand7d6d622016-03-17 09:53:39 +0000190 // And then the graph contains a value for the legit target pattern's target "@//foo:foo".
191 assertTrue(walkableGraph.exists(getKeyForLabel(Label.create("@//foo", "foo"))));
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000192 }
193
194 // Helpers:
195
Janak Ramakrishnan8d239cd2016-01-27 21:06:01 +0000196 private WalkableGraph getGraphFromPatternsEvaluation(ImmutableList<String> patternSequence)
197 throws InterruptedException {
198 return getGraphFromPatternsEvaluation(patternSequence, /*keepGoing=*/ true);
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000199 }
200
201 private WalkableGraph getGraphFromPatternsEvaluation(
Janak Ramakrishnan8d239cd2016-01-27 21:06:01 +0000202 ImmutableList<String> patternSequence, boolean keepGoing) throws InterruptedException {
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000203 SkyKey independentTarget = PrepareDepsOfPatternsValue.key(patternSequence, "");
204 ImmutableList<SkyKey> singletonTargetPattern = ImmutableList.of(independentTarget);
205
206 // When PrepareDepsOfPatternsFunction completes evaluation,
207 EvaluationResult<SkyValue> evaluationResult =
208 getSkyframeExecutor()
209 .getDriverForTesting()
210 .evaluate(singletonTargetPattern, keepGoing, LOADING_PHASE_THREADS, eventCollector);
Janak Ramakrishnan8d239cd2016-01-27 21:06:01 +0000211 // Currently all callers either expect success or pass keepGoing=true, which implies success,
212 // since PrepareDepsOfPatternsFunction swallows all errors. Will need to be changed if a test
213 // that evaluates with keepGoing=false and expects errors is added.
214 assertThatEvaluationResult(evaluationResult).hasNoError();
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000215
216 return Preconditions.checkNotNull(evaluationResult.getWalkableGraph());
217 }
218
219 private void createFooAndFoo2(boolean dependent) throws IOException {
220 String dependencyIfAny = dependent ? "srcs = [':foo2']," : "";
221 scratch.file(
222 "foo/BUILD",
223 "genrule(name = 'foo',",
224 dependencyIfAny,
225 " outs = ['out.txt'],",
226 " cmd = 'touch $@')",
227 "genrule(name = 'foo2',",
228 " outs = ['out2.txt'],",
229 " cmd = 'touch $@')");
230 }
231
232 private void createFooWithDependencyOnMissingBarPackage() throws IOException {
233 scratch.file(
234 "foo/BUILD",
235 "genrule(name = 'foo',",
236 " srcs = ['//bar:bar'],",
237 " outs = ['out.txt'],",
238 " cmd = 'touch $@')");
239 }
240
241 private void createFooWithDependencyOnBarPackageWithMissingTarget() throws IOException {
242 scratch.file(
243 "foo/BUILD",
244 "genrule(name = 'foo',",
245 " srcs = ['//bar:bar'],",
246 " outs = ['out.txt'],",
247 " cmd = 'touch $@')");
248 scratch.file("bar/BUILD");
249 }
250
Janak Ramakrishnan3c0adb22016-08-15 21:54:55 +0000251 private static void assertValidValue(WalkableGraph graph, SkyKey key)
252 throws InterruptedException {
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000253 assertValidValue(graph, key, /*expectTransitiveException=*/ false);
254 }
255
256 /**
Janak Ramakrishnan3c0adb22016-08-15 21:54:55 +0000257 * A node in the walkable graph may have both a value and an exception. This happens when one of a
258 * node's transitive dependencies throws an exception, but its parent recovers from it.
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000259 */
Janak Ramakrishnan3c0adb22016-08-15 21:54:55 +0000260 private static void assertValidValue(
261 WalkableGraph graph, SkyKey key, boolean expectTransitiveException)
262 throws InterruptedException {
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000263 assertTrue(graph.exists(key));
264 assertNotNull(graph.getValue(key));
265 if (expectTransitiveException) {
266 assertNotNull(graph.getException(key));
267 } else {
268 assertNull(graph.getException(key));
269 }
270 }
271
Janak Ramakrishnan3c0adb22016-08-15 21:54:55 +0000272 private static Exception assertException(WalkableGraph graph, SkyKey key)
273 throws InterruptedException {
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000274 assertTrue(graph.exists(key));
275 assertNull(graph.getValue(key));
276 Exception exception = graph.getException(key);
277 assertNotNull(exception);
278 return exception;
279 }
280}