blob: 3bf92ec39d72271f45f88d1f1e14c15363374fae [file] [log] [blame]
Dmitry Lomov021a3652015-11-23 14:55: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.analysis;
16
17import static com.google.common.truth.Truth.assertThat;
Michael Staiba5aa9162017-03-17 23:15:16 +000018import static com.google.common.truth.Truth.assertWithMessage;
Dmitry Lomov021a3652015-11-23 14:55:13 +000019import static com.google.devtools.build.lib.testutil.MoreAsserts.assertEventCount;
Janak Ramakrishnan2655e6d2016-08-18 18:20:53 +000020import static com.google.devtools.build.lib.testutil.MoreAsserts.assertEventCountAtLeast;
Florian Weikert79bd2372015-11-26 15:42:24 +000021import static org.junit.Assert.assertEquals;
22import static org.junit.Assert.assertFalse;
23import static org.junit.Assert.assertNotNull;
24import static org.junit.Assert.assertNull;
25import static org.junit.Assert.assertSame;
26import static org.junit.Assert.assertTrue;
27import static org.junit.Assert.fail;
Dmitry Lomov021a3652015-11-23 14:55:13 +000028
29import com.google.common.base.Function;
30import com.google.common.collect.ImmutableList;
Dmitry Lomov021a3652015-11-23 14:55:13 +000031import com.google.common.collect.Iterables;
32import com.google.common.collect.Lists;
33import com.google.common.collect.Sets;
34import com.google.common.eventbus.EventBus;
35import com.google.common.truth.Truth;
36import com.google.devtools.build.lib.actions.Action;
37import com.google.devtools.build.lib.actions.Actions;
38import com.google.devtools.build.lib.actions.Artifact;
39import com.google.devtools.build.lib.actions.FailAction;
Ulf Adams58581a32016-01-25 15:54:15 +000040import com.google.devtools.build.lib.analysis.BuildView.AnalysisResult;
Michael Staiba5aa9162017-03-17 23:15:16 +000041import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
Greg Estren373e3e22016-08-09 22:36:51 +000042import com.google.devtools.build.lib.analysis.config.ConfigurationFactory;
Dmitry Lomov021a3652015-11-23 14:55:13 +000043import com.google.devtools.build.lib.analysis.config.InvalidConfigurationException;
Ulf Adams3e34a112016-02-09 16:31:06 +000044import com.google.devtools.build.lib.analysis.util.AnalysisMock;
Dmitry Lomov021a3652015-11-23 14:55:13 +000045import com.google.devtools.build.lib.analysis.util.BuildViewTestBase;
Greg Estren42c49352016-06-08 20:12:40 +000046import com.google.devtools.build.lib.analysis.util.ExpectedDynamicConfigurationErrors;
Dmitry Lomov021a3652015-11-23 14:55:13 +000047import com.google.devtools.build.lib.cmdline.Label;
Dmitry Lomov021a3652015-11-23 14:55:13 +000048import com.google.devtools.build.lib.packages.Attribute;
49import com.google.devtools.build.lib.packages.Rule;
Dmitry Lomov021a3652015-11-23 14:55:13 +000050import com.google.devtools.build.lib.skyframe.SkyFunctions;
51import com.google.devtools.build.lib.skyframe.TargetPatternValue.TargetPatternKey;
Greg Estren247ac162016-08-10 20:50:09 +000052import com.google.devtools.build.lib.skyframe.util.SkyframeExecutorTestUtils;
Dmitry Lomov021a3652015-11-23 14:55:13 +000053import com.google.devtools.build.lib.testutil.Suite;
54import com.google.devtools.build.lib.testutil.TestSpec;
55import com.google.devtools.build.lib.testutil.TestUtils;
56import com.google.devtools.build.lib.util.Pair;
57import com.google.devtools.build.lib.vfs.Path;
58import com.google.devtools.build.lib.vfs.PathFragment;
Janak Ramakrishnancc7712f2016-07-08 17:38:27 +000059import com.google.devtools.build.skyframe.NotifyingHelper.EventType;
60import com.google.devtools.build.skyframe.NotifyingHelper.Listener;
61import com.google.devtools.build.skyframe.NotifyingHelper.Order;
Dmitry Lomov021a3652015-11-23 14:55:13 +000062import com.google.devtools.build.skyframe.SkyKey;
63import com.google.devtools.build.skyframe.TrackingAwaiter;
Michael Staiba5aa9162017-03-17 23:15:16 +000064import com.google.devtools.common.options.Options;
65import com.google.devtools.common.options.OptionsParsingException;
Carmi Grushkobabd4852016-11-18 17:58:09 +000066import java.util.ArrayList;
Dmitry Lomov021a3652015-11-23 14:55:13 +000067import java.util.Collection;
68import java.util.LinkedHashSet;
Carmi Grushkobabd4852016-11-18 17:58:09 +000069import java.util.List;
Dmitry Lomov021a3652015-11-23 14:55:13 +000070import java.util.concurrent.CountDownLatch;
71import java.util.concurrent.TimeUnit;
72import java.util.regex.Pattern;
Lukacs Berki120b8632016-07-28 10:18:21 +000073import org.junit.Test;
74import org.junit.runner.RunWith;
75import org.junit.runners.JUnit4;
Dmitry Lomov021a3652015-11-23 14:55:13 +000076
77/**
78 * Tests for the {@link BuildView}.
79 */
80@TestSpec(size = Suite.SMALL_TESTS)
Florian Weikert79bd2372015-11-26 15:42:24 +000081@RunWith(JUnit4.class)
Ulf Adams2ac20962016-02-01 13:04:54 +000082public class BuildViewTest extends BuildViewTestBase {
Ulf Adams47838c92016-02-02 18:12:44 +000083 private static final Function<AnalysisFailureEvent, Pair<String, String>>
84 ANALYSIS_EVENT_TO_STRING_PAIR = new Function<AnalysisFailureEvent, Pair<String, String>>() {
85 @Override
86 public Pair<String, String> apply(AnalysisFailureEvent event) {
87 return Pair.of(
88 event.getFailedTarget().getLabel().toString(), event.getFailureReason().toString());
89 }
90 };
Dmitry Lomov021a3652015-11-23 14:55:13 +000091
Florian Weikert79bd2372015-11-26 15:42:24 +000092 @Test
Dmitry Lomov021a3652015-11-23 14:55:13 +000093 public void testRuleConfiguredTarget() throws Exception {
94 scratch.file("pkg/BUILD",
95 "genrule(name='foo', ",
96 " cmd = '',",
97 " srcs=['a.src'],",
98 " outs=['a.out'])");
99 update("//pkg:foo");
100 Rule ruleTarget = (Rule) getTarget("//pkg:foo");
101 assertEquals("genrule", ruleTarget.getRuleClass());
102
103 ConfiguredTarget ruleCT = getConfiguredTarget("//pkg:foo");
104
105 assertSame(ruleTarget, ruleCT.getTarget());
106 }
107
Florian Weikert79bd2372015-11-26 15:42:24 +0000108 @Test
Dmitry Lomov021a3652015-11-23 14:55:13 +0000109 public void testFilterByTargets() throws Exception {
110 scratch.file("tests/BUILD",
111 "sh_test(name = 'small_test_1',",
112 " srcs = ['small_test_1.sh'],",
113 " data = [':xUnit'],",
114 " size = 'small',",
115 " tags = ['tag1'])",
116 "",
117 "sh_test(name = 'small_test_2',",
118 " srcs = ['small_test_2.sh'],",
119 " size = 'small',",
120 " tags = ['tag2'])",
121 "",
122 "",
123 "test_suite( name = 'smallTests', tags=['small'])");
124 //scratch.file("tests/small_test_1.py");
125
126 update("//tests:smallTests");
127
128 ConfiguredTarget test1 = getConfiguredTarget("//tests:small_test_1");
129 ConfiguredTarget test2 = getConfiguredTarget("//tests:small_test_2");
130 ConfiguredTarget suite = getConfiguredTarget("//tests:smallTests");
131 assertNoEvents(); // start from a clean slate
132
133
134 Collection<ConfiguredTarget> targets =
135 new LinkedHashSet<>(ImmutableList.of(test1, test2, suite));
Lukacs Berki3d486832016-10-26 12:51:38 +0000136 targets = Lists.<ConfiguredTarget>newArrayList(
Dmitry Lomov021a3652015-11-23 14:55:13 +0000137 BuildView.filterTestsByTargets(targets,
138 Sets.newHashSet(test1.getTarget(), suite.getTarget())));
139 assertThat(targets).containsExactlyElementsIn(Sets.newHashSet(test1, suite));
140 }
141
Florian Weikert79bd2372015-11-26 15:42:24 +0000142 @Test
Dmitry Lomov021a3652015-11-23 14:55:13 +0000143 public void testSourceArtifact() throws Exception {
144 setupDummyRule();
145 update("//pkg:a.src");
146 InputFileConfiguredTarget inputCT = getInputFileConfiguredTarget("//pkg:a.src");
147 Artifact inputArtifact = inputCT.getArtifact();
148 assertNull(getGeneratingAction(inputArtifact));
149 assertEquals("pkg/a.src", inputArtifact.getExecPathString());
150 }
151
Florian Weikert79bd2372015-11-26 15:42:24 +0000152 @Test
Dmitry Lomov021a3652015-11-23 14:55:13 +0000153 public void testGeneratedArtifact() throws Exception {
154 setupDummyRule();
155 update("//pkg:a.out");
156 OutputFileConfiguredTarget outputCT = (OutputFileConfiguredTarget)
157 getConfiguredTarget("//pkg:a.out");
158 Artifact outputArtifact = outputCT.getArtifact();
Kristina Chodorowf8a1ae62016-08-11 14:44:40 +0000159 assertEquals(
160 outputCT.getConfiguration().getBinDirectory(
161 outputCT.getTarget().getLabel().getPackageIdentifier().getRepository()),
162 outputArtifact.getRoot());
Greg Estren7971e672016-06-01 23:22:48 +0000163 assertEquals(outputCT.getConfiguration().getBinFragment().getRelative("pkg/a.out"),
Dmitry Lomov021a3652015-11-23 14:55:13 +0000164 outputArtifact.getExecPath());
165 assertEquals(new PathFragment("pkg/a.out"), outputArtifact.getRootRelativePath());
166
167 Action action = getGeneratingAction(outputArtifact);
168 assertSame(FailAction.class, action.getClass());
169 }
170
Florian Weikertfd735f32015-11-27 17:32:23 +0000171 @Test
Ulf Adamsaf0b6702017-01-18 10:58:10 +0000172 public void testSyntaxErrorInDepPackage() throws Exception {
173 // Check that a loading error in a dependency is properly reported.
174 scratch.file("a/BUILD",
175 "genrule(name='x',",
176 " srcs = ['file.txt'],",
177 " outs = ['foo'],",
178 " cmd = 'echo')",
179 "@"); // syntax error
180
181 scratch.file("b/BUILD",
182 "genrule(name= 'cc',",
183 " tools = ['//a:x'],",
184 " outs = ['bar'],",
185 " cmd = 'echo')");
186
187 reporter.removeHandler(failFastHandler);
188 EventBus eventBus = new EventBus();
189 AnalysisResult result = update(eventBus, defaultFlags().with(Flag.KEEP_GOING), "//b:cc");
190
191 assertContainsEvent("invalid character: '@'");
192 assertThat(result.hasError()).isTrue();
193 }
194
195 @Test
Ulf Adamsf8ff07a2016-01-22 14:56:19 +0000196 public void testReportsAnalysisRootCauses() throws Exception {
197 scratch.file("private/BUILD",
198 "genrule(",
199 " name='private',",
200 " outs=['private.out'],",
201 " cmd='',",
202 " visibility=['//visibility:private'])");
203 scratch.file("foo/BUILD",
204 "genrule(",
205 " name='foo',",
206 " tools=[':bar'],",
207 " outs=['foo.out'],",
208 " cmd='')",
209 "genrule(",
210 " name='bar',",
211 " tools=['//private'],",
212 " outs=['bar.out'],",
213 " cmd='')");
Dmitry Lomov021a3652015-11-23 14:55:13 +0000214
215 reporter.removeHandler(failFastHandler);
216 EventBus eventBus = new EventBus();
217 AnalysisFailureRecorder recorder = new AnalysisFailureRecorder();
218 eventBus.register(recorder);
Ulf Adams58581a32016-01-25 15:54:15 +0000219 AnalysisResult result = update(eventBus, defaultFlags().with(Flag.KEEP_GOING), "//foo");
220 assertThat(result.hasError()).isTrue();
Dmitry Lomov021a3652015-11-23 14:55:13 +0000221 assertThat(recorder.events).hasSize(1);
222 AnalysisFailureEvent event = recorder.events.get(0);
Ulf Adamsf8ff07a2016-01-22 14:56:19 +0000223 assertEquals("//foo:bar", event.getFailureReason().toString());
224 assertEquals("//foo:foo", event.getFailedTarget().getLabel().toString());
Dmitry Lomov021a3652015-11-23 14:55:13 +0000225 }
226
Florian Weikert79bd2372015-11-26 15:42:24 +0000227 @Test
Dmitry Lomov021a3652015-11-23 14:55:13 +0000228 public void testReportsLoadingRootCauses() throws Exception {
Ulf Adams47838c92016-02-02 18:12:44 +0000229 // This test checks that two simultaneous errors are both reported:
230 // - missing outs attribute,
231 // - package referenced in tools does not exist
Dmitry Lomov021a3652015-11-23 14:55:13 +0000232 scratch.file("pkg/BUILD",
233 "genrule(name='foo',",
234 " tools=['//nopackage:missing'],",
235 " cmd='')");
236
237 reporter.removeHandler(failFastHandler);
238 EventBus eventBus = new EventBus();
239 LoadingFailureRecorder recorder = new LoadingFailureRecorder();
240 eventBus.register(recorder);
241 // Note: no need to run analysis for a loading failure.
Ulf Adams58581a32016-01-25 15:54:15 +0000242 AnalysisResult result = update(eventBus, defaultFlags().with(Flag.KEEP_GOING), "//pkg:foo");
243 assertThat(result.hasError()).isTrue();
Dmitry Lomov021a3652015-11-23 14:55:13 +0000244 assertThat(recorder.events)
245 .contains(
246 Pair.of(Label.parseAbsolute("//pkg:foo"), Label.parseAbsolute("//nopackage:missing")));
247 assertContainsEvent("missing value for mandatory attribute 'outs'");
248 assertContainsEvent("no such package 'nopackage'");
249 // Skyframe correctly reports the other root cause as the genrule itself (since it is
250 // missing attributes).
251 assertThat(recorder.events).hasSize(2);
252 assertThat(recorder.events)
253 .contains(Pair.of(Label.parseAbsolute("//pkg:foo"), Label.parseAbsolute("//pkg:foo")));
254 }
255
Florian Weikert79bd2372015-11-26 15:42:24 +0000256 @Test
Dmitry Lomov021a3652015-11-23 14:55:13 +0000257 public void testConvolutedLoadRootCauseAnalysis() throws Exception {
258 // You need license declarations in third_party. We use this constraint to
259 // create targets that are loadable, but are in error.
260 scratch.file("third_party/first/BUILD",
261 "sh_library(name='first', deps=['//third_party/second'], licenses=['notice'])");
262 scratch.file("third_party/second/BUILD",
263 "sh_library(name='second', deps=['//third_party/third'], licenses=['notice'])");
264 scratch.file("third_party/third/BUILD",
265 "sh_library(name='third', deps=['//third_party/fourth'], licenses=['notice'])");
266 scratch.file("third_party/fourth/BUILD",
267 "sh_library(name='fourth', deps=['//third_party/fifth'])");
268 scratch.file("third_party/fifth/BUILD",
269 "sh_library(name='fifth', licenses=['notice'])");
270 reporter.removeHandler(failFastHandler);
271 EventBus eventBus = new EventBus();
272 LoadingFailureRecorder recorder = new LoadingFailureRecorder();
273 eventBus.register(recorder);
274 // Note: no need to run analysis for a loading failure.
Ulf Adams58581a32016-01-25 15:54:15 +0000275 AnalysisResult result = update(eventBus, defaultFlags().with(Flag.KEEP_GOING),
Dmitry Lomov021a3652015-11-23 14:55:13 +0000276 "//third_party/first", "//third_party/third");
Ulf Adams58581a32016-01-25 15:54:15 +0000277 assertThat(result.hasError()).isTrue();
Dmitry Lomov021a3652015-11-23 14:55:13 +0000278 assertThat(recorder.events).hasSize(2);
279 assertTrue(recorder.events.toString(), recorder.events.contains(
280 Pair.of(Label.parseAbsolute("//third_party/first"),
281 Label.parseAbsolute("//third_party/fourth"))));
282 assertThat(recorder.events)
283 .contains(Pair.of(
284 Label.parseAbsolute("//third_party/third"),
285 Label.parseAbsolute("//third_party/fourth")));
286 }
287
Florian Weikert79bd2372015-11-26 15:42:24 +0000288 @Test
Dmitry Lomov021a3652015-11-23 14:55:13 +0000289 public void testMultipleRootCauseReporting() throws Exception {
290 scratch.file("gp/BUILD",
291 "sh_library(name = 'gp', deps = ['//p:p'])");
292 scratch.file("p/BUILD",
293 "sh_library(name = 'p', deps = ['//c1:not', '//c2:not'])");
294 scratch.file("c1/BUILD");
295 scratch.file("c2/BUILD");
296 reporter.removeHandler(failFastHandler);
297 EventBus eventBus = new EventBus();
298 LoadingFailureRecorder recorder = new LoadingFailureRecorder();
299 eventBus.register(recorder);
Ulf Adams58581a32016-01-25 15:54:15 +0000300 AnalysisResult result = update(eventBus, defaultFlags().with(Flag.KEEP_GOING), "//gp");
301 assertThat(result.hasError()).isTrue();
Dmitry Lomov021a3652015-11-23 14:55:13 +0000302 assertThat(recorder.events).hasSize(2);
303 assertTrue(recorder.events.toString(), recorder.events.contains(
304 Pair.of(Label.parseAbsolute("//gp"),
305 Label.parseAbsolute("//c1:not"))));
306 assertThat(recorder.events)
307 .contains(Pair.of(Label.parseAbsolute("//gp"), Label.parseAbsolute("//c2:not")));
308 }
309
310 /**
311 * Regression test for: "Package group includes are broken"
312 */
Florian Weikert79bd2372015-11-26 15:42:24 +0000313 @Test
Dmitry Lomov021a3652015-11-23 14:55:13 +0000314 public void testTopLevelPackageGroup() throws Exception {
315 scratch.file("tropical/BUILD",
316 "package_group(name='guava', includes=[':mango'])",
317 "package_group(name='mango')");
318
319 // If the analysis phase results in an error, this will throw an exception
320 update("//tropical:guava");
321
322 // Check if the included package group also got analyzed
323 assertNotNull(getConfiguredTarget("//tropical:mango", null));
324 }
325
Florian Weikert79bd2372015-11-26 15:42:24 +0000326 @Test
Dmitry Lomov021a3652015-11-23 14:55:13 +0000327 public void testTopLevelInputFile() throws Exception {
328 scratch.file("tropical/BUILD",
329 "exports_files(['file.txt'])");
330 update("//tropical:file.txt");
331 assertNotNull(getConfiguredTarget("//tropical:file.txt", null));
332 }
333
Florian Weikert79bd2372015-11-26 15:42:24 +0000334 @Test
Dmitry Lomov021a3652015-11-23 14:55:13 +0000335 public void testGetDirectPrerequisites() throws Exception {
336 scratch.file(
337 "package/BUILD",
338 "filegroup(name='top', srcs=[':inner', 'file'])",
339 "sh_binary(name='inner', srcs=['script.sh'])");
340 update("//package:top");
341 ConfiguredTarget top = getConfiguredTarget("//package:top", getTargetConfiguration());
342 Iterable<ConfiguredTarget> targets = getView().getDirectPrerequisitesForTesting(
343 reporter, top, getBuildConfigurationCollection());
344 Iterable<Label> labels =
345 Iterables.transform(
346 targets,
347 new Function<ConfiguredTarget, Label>() {
348 @Override
349 public Label apply(ConfiguredTarget target) {
350 return target.getLabel();
351 }
352 });
353 assertThat(labels)
354 .containsExactly(
355 Label.parseAbsolute("//package:inner"), Label.parseAbsolute("//package:file"));
356 }
357
Florian Weikert79bd2372015-11-26 15:42:24 +0000358 @Test
Dmitry Lomov021a3652015-11-23 14:55:13 +0000359 public void testGetDirectPrerequisiteDependencies() throws Exception {
360 scratch.file(
361 "package/BUILD",
362 "filegroup(name='top', srcs=[':inner', 'file'])",
363 "sh_binary(name='inner', srcs=['script.sh'])");
364 update("//package:top");
365 ConfiguredTarget top = getConfiguredTarget("//package:top", getTargetConfiguration());
366 Iterable<Dependency> targets = getView().getDirectPrerequisiteDependenciesForTesting(
Ulf Adamsa4ca6372016-01-11 14:20:28 +0000367 reporter, top, getBuildConfigurationCollection()).values();
Dmitry Lomov021a3652015-11-23 14:55:13 +0000368
369 Dependency innerDependency;
370 Dependency fileDependency;
371 if (top.getConfiguration().useDynamicConfigurations()) {
372 innerDependency =
Michael Staib5e573fd2016-01-27 00:33:29 +0000373 Dependency.withTransitionAndAspects(
Dmitry Lomov021a3652015-11-23 14:55:13 +0000374 Label.parseAbsolute("//package:inner"),
375 Attribute.ConfigurationTransition.NONE,
Dmitry Lomove851fe22017-02-14 23:11:23 +0000376 AspectCollection.EMPTY);
Dmitry Lomov021a3652015-11-23 14:55:13 +0000377 } else {
378 innerDependency =
Michael Staib5e573fd2016-01-27 00:33:29 +0000379 Dependency.withConfiguration(
Dmitry Lomov021a3652015-11-23 14:55:13 +0000380 Label.parseAbsolute("//package:inner"),
Michael Staib5e573fd2016-01-27 00:33:29 +0000381 getTargetConfiguration());
Dmitry Lomov021a3652015-11-23 14:55:13 +0000382 }
Greg Estren9e26f0f2016-09-29 01:01:57 +0000383 fileDependency =
384 Dependency.withNullConfiguration(
385 Label.parseAbsolute("//package:file"));
Dmitry Lomov021a3652015-11-23 14:55:13 +0000386
387 assertThat(targets).containsExactly(innerDependency, fileDependency);
388 }
389
390 /**
Michael Staiba5aa9162017-03-17 23:15:16 +0000391 * Tests that the {@code --output directory name} option cannot be used on
Dmitry Lomov021a3652015-11-23 14:55:13 +0000392 * the command line.
393 */
Florian Weikert79bd2372015-11-26 15:42:24 +0000394 @Test
Dmitry Lomov021a3652015-11-23 14:55:13 +0000395 public void testConfigurationShortName() throws Exception {
Michael Staiba5aa9162017-03-17 23:15:16 +0000396 // Check that output directory name is still the name, otherwise this test is not testing what
397 // we expect.
398 BuildConfiguration.Options options = Options.getDefaults(BuildConfiguration.Options.class);
399 options.outputDirectoryName = "/home/wonkaw/wonka_chocolate/factory/out";
400 assertWithMessage("The flag's name may have been changed; this test may need to be updated.")
401 .that(options.asMap().get("output directory name"))
402 .isEqualTo("/home/wonkaw/wonka_chocolate/factory/out");
403
Dmitry Lomov021a3652015-11-23 14:55:13 +0000404 try {
Michael Staiba5aa9162017-03-17 23:15:16 +0000405 useConfiguration("--output directory name=foo");
Dmitry Lomov021a3652015-11-23 14:55:13 +0000406 fail();
Michael Staiba5aa9162017-03-17 23:15:16 +0000407 } catch (OptionsParsingException e) {
408 assertThat(e).hasMessage("Unrecognized option: --output directory name=foo");
Dmitry Lomov021a3652015-11-23 14:55:13 +0000409 }
410 }
411
Florian Weikert79bd2372015-11-26 15:42:24 +0000412 @Test
Dmitry Lomov021a3652015-11-23 14:55:13 +0000413 public void testFileTranslations() throws Exception {
414 scratch.file("foo/file");
415 scratch.file("foo/BUILD",
416 "exports_files(['file'])");
417 useConfiguration("--message_translations=//foo:file");
418 scratch.file("bar/BUILD",
419 "sh_library(name = 'bar')");
420 update("//bar");
421 }
422
423 // Regression test: "output_filter broken (but in a different way)"
Florian Weikert79bd2372015-11-26 15:42:24 +0000424 @Test
Dmitry Lomov021a3652015-11-23 14:55:13 +0000425 public void testOutputFilterSeeWarning() throws Exception {
426 runAnalysisWithOutputFilter(Pattern.compile(".*"));
427 assertContainsEvent("please do not import '//java/a:A.java'");
428 }
429
430 // Regression test: "output_filter broken (but in a different way)"
Florian Weikert79bd2372015-11-26 15:42:24 +0000431 @Test
Dmitry Lomov021a3652015-11-23 14:55:13 +0000432 public void testOutputFilter() throws Exception {
433 runAnalysisWithOutputFilter(Pattern.compile("^//java/c"));
434 assertNoEvents();
435 }
436
Florian Weikert79bd2372015-11-26 15:42:24 +0000437 @Test
Dmitry Lomov021a3652015-11-23 14:55:13 +0000438 public void testAnalysisErrorMessageWithKeepGoing() throws Exception {
439 scratch.file("a/BUILD", "sh_binary(name='a', srcs=['a1.sh', 'a2.sh'])");
440 reporter.removeHandler(failFastHandler);
Ulf Adams58581a32016-01-25 15:54:15 +0000441 AnalysisResult result = update(defaultFlags().with(Flag.KEEP_GOING), "//a");
442 assertThat(result.hasError()).isTrue();
Dmitry Lomov021a3652015-11-23 14:55:13 +0000443 assertContainsEvent("errors encountered while analyzing target '//a:a'");
444 }
445
446 /**
447 * Regression test: Exception in ConfiguredTargetGraph.checkForCycles()
448 * when multiple top-level targets depend on the same cycle.
449 */
Florian Weikert79bd2372015-11-26 15:42:24 +0000450 @Test
Dmitry Lomov021a3652015-11-23 14:55:13 +0000451 public void testCircularDependencyBelowTwoTargets() throws Exception {
452 scratch.file("foo/BUILD",
453 "sh_library(name = 'top1', srcs = ['top1.sh'], deps = [':rec1'])",
454 "sh_library(name = 'top2', srcs = ['top2.sh'], deps = [':rec1'])",
455 "sh_library(name = 'rec1', srcs = ['rec1.sh'], deps = [':rec2'])",
456 "sh_library(name = 'rec2', srcs = ['rec2.sh'], deps = [':rec1'])"
457 );
458 reporter.removeHandler(failFastHandler);
Ulf Adams58581a32016-01-25 15:54:15 +0000459 AnalysisResult result =
460 update(defaultFlags().with(Flag.KEEP_GOING), "//foo:top1", "//foo:top2");
461 assertThat(result.hasError()).isTrue();
Dmitry Lomov021a3652015-11-23 14:55:13 +0000462 assertContainsEvent("in sh_library rule //foo:rec1: cycle in dependency graph:\n");
463 assertContainsEvent("in sh_library rule //foo:top");
464 }
465
466 // Regression test: cycle node depends on error.
Florian Weikert79bd2372015-11-26 15:42:24 +0000467 @Test
Dmitry Lomov021a3652015-11-23 14:55:13 +0000468 public void testErrorBelowCycle() throws Exception {
469 scratch.file("foo/BUILD",
470 "sh_library(name = 'top', deps = ['mid'])",
471 "sh_library(name = 'mid', deps = ['bad', 'cycle1'])",
472 "sh_library(name = 'bad', srcs = ['//badbuild:isweird'])",
473 "sh_library(name = 'cycle1', deps = ['cycle2', 'mid'])",
474 "sh_library(name = 'cycle2', deps = ['cycle1'])");
475 scratch.file("badbuild/BUILD", "");
476 reporter.removeHandler(failFastHandler);
Janak Ramakrishnan2655e6d2016-08-18 18:20:53 +0000477 injectGraphListenerForTesting(
478 new Listener() {
479 @Override
480 public void accept(SkyKey key, EventType type, Order order, Object context) {}
481 },
482 /*deterministic=*/ true);
Dmitry Lomov021a3652015-11-23 14:55:13 +0000483 try {
484 update("//foo:top");
485 fail();
Ulf Adamsab64e592016-09-05 09:40:13 +0000486 } catch (ViewCreationFailedException e) {
Dmitry Lomov021a3652015-11-23 14:55:13 +0000487 // Expected.
488 }
489 assertContainsEvent("no such target '//badbuild:isweird': target 'isweird' not declared in "
490 + "package 'badbuild'");
491 assertContainsEvent("and referenced by '//foo:bad'");
Janak Ramakrishnan2655e6d2016-08-18 18:20:53 +0000492 assertContainsEvent("in sh_library rule //foo");
493 assertContainsEvent("cycle in dependency graph");
494 assertEventCountAtLeast(2, eventCollector);
Dmitry Lomov021a3652015-11-23 14:55:13 +0000495 }
496
Florian Weikert79bd2372015-11-26 15:42:24 +0000497 @Test
Ulf Adams47838c92016-02-02 18:12:44 +0000498 public void testErrorBelowCycleKeepGoing() throws Exception {
499 scratch.file("foo/BUILD",
500 "sh_library(name = 'top', deps = ['mid'])",
501 "sh_library(name = 'mid', deps = ['bad', 'cycle1'])",
502 "sh_library(name = 'bad', srcs = ['//badbuild:isweird'])",
503 "sh_library(name = 'cycle1', deps = ['cycle2', 'mid'])",
504 "sh_library(name = 'cycle2', deps = ['cycle1'])");
505 scratch.file("badbuild/BUILD", "");
506 reporter.removeHandler(failFastHandler);
507 update(defaultFlags().with(Flag.KEEP_GOING), "//foo:top");
508 assertContainsEvent("no such target '//badbuild:isweird': target 'isweird' not declared in "
509 + "package 'badbuild'");
510 assertContainsEvent("and referenced by '//foo:bad'");
511 assertContainsEvent("in sh_library rule //foo");
512 assertContainsEvent("cycle in dependency graph");
Greg Estren2f5ca772016-06-17 00:02:06 +0000513 // Dynamic configurations trigger this error both in configuration trimming (which visits
514 // the transitive target closure) and in the normal configured target cycle detection path.
515 // So we get an additional instance of this check (which varies depending on whether Skyframe
516 // loading phase is enabled).
517 // TODO(gregce): refactor away this variation. Note that the duplicate doesn't make it into
518 // real user output (it only affects tests).
519 if (!getTargetConfiguration().useDynamicConfigurations()) {
520 assertEventCount(3, eventCollector);
521 }
Ulf Adams47838c92016-02-02 18:12:44 +0000522 }
523
524 @Test
Dmitry Lomov021a3652015-11-23 14:55:13 +0000525 public void testAnalysisEntryHasActionsEvenWithError() throws Exception {
526 scratch.file("foo/BUILD",
527 "cc_binary(name = 'foo', linkshared = 1, srcs = ['foo.cc'])");
528 reporter.removeHandler(failFastHandler);
529 try {
530 update("//foo:foo");
531 fail(); // Expected ViewCreationFailedException.
532 } catch (ViewCreationFailedException e) {
533 // ok.
534 }
535 }
536
Florian Weikert79bd2372015-11-26 15:42:24 +0000537 @Test
Dmitry Lomov021a3652015-11-23 14:55:13 +0000538 public void testHelpfulErrorForWrongPackageLabels() throws Exception {
539 reporter.removeHandler(failFastHandler);
540
541 scratch.file("x/BUILD",
542 "cc_library(name='x', srcs=['x.cc'])");
543 scratch.file("y/BUILD",
544 "cc_library(name='y', srcs=['y.cc'], deps=['//x:z'])");
545
Ulf Adams58581a32016-01-25 15:54:15 +0000546 AnalysisResult result = update(defaultFlags().with(Flag.KEEP_GOING), "//y:y");
547 assertThat(result.hasError()).isTrue();
Dmitry Lomov021a3652015-11-23 14:55:13 +0000548 assertContainsEvent("no such target '//x:z': "
549 + "target 'z' not declared in package 'x' "
550 + "defined by /workspace/x/BUILD and referenced by '//y:y'");
551 }
552
Florian Weikert79bd2372015-11-26 15:42:24 +0000553 @Test
Dmitry Lomov021a3652015-11-23 14:55:13 +0000554 public void testNewActionsAreDifferentAndDontConflict() throws Exception {
555 scratch.file("pkg/BUILD",
556 "genrule(name='a', ",
557 " cmd='',",
558 " outs=['a.out'])");
559 update("//pkg:a.out");
560 OutputFileConfiguredTarget outputCT = (OutputFileConfiguredTarget)
561 getConfiguredTarget("//pkg:a.out");
562 Artifact outputArtifact = outputCT.getArtifact();
563 Action action = getGeneratingAction(outputArtifact);
564 assertNotNull(action);
565 scratch.overwriteFile("pkg/BUILD",
566 "genrule(name='a', ",
567 " cmd='false',",
568 " outs=['a.out'])");
569 update("//pkg:a.out");
570 assertFalse("Actions should not be compatible",
571 Actions.canBeShared(action, getGeneratingAction(outputArtifact)));
572 }
573
574 /**
575 * This test exercises the case where we invalidate (mark dirty) a node in one build command
576 * invocation and the revalidation (because it did not change) happens in a subsequent build
577 * command call.
578 *
579 * - In the first update call we construct A.
580 *
581 * - Then we construct B and we make the glob get invalidated. We do that by deleting a file
582 * because it depends on the directory listing. Because of that A gets invalidated.
583 *
584 * - Then we construct A again. The glob gets revalidated because it is still matching just A.java
585 * and A configured target gets revalidated too. At the end of the analysis A java action should
586 * be in the action graph.
587 */
Florian Weikert79bd2372015-11-26 15:42:24 +0000588 @Test
Dmitry Lomov021a3652015-11-23 14:55:13 +0000589 public void testMultiBuildInvalidationRevalidation() throws Exception {
590 scratch.file("java/a/A.java", "bla1");
591 scratch.file("java/a/C.java", "bla2");
592 scratch.file("java/a/BUILD",
593 "java_test(name = 'A',",
594 " srcs = glob(['A*.java']))",
595 "java_test(name = 'B',",
596 " srcs = ['B.java'])");
597 update("//java/a:A");
598 ConfiguredTarget ct = getConfiguredTarget("//java/a:A");
599 scratch.deleteFile("java/a/C.java");
600 update("//java/a:B");
601 update("//java/a:A");
602 assertNotNull(getGeneratingAction(
603 getBinArtifact("A_deploy.jar", ct)));
604 }
605
606 /**
607 * Regression test: ClassCastException in SkyframeLabelVisitor.updateRootCauses.
608 */
Florian Weikert79bd2372015-11-26 15:42:24 +0000609 @Test
Dmitry Lomov021a3652015-11-23 14:55:13 +0000610 public void testDepOnGoodTargetInBadPkgAndTransitivelyBadTarget() throws Exception {
611 reporter.removeHandler(failFastHandler);
612 scratch.file("parent/BUILD",
613 "sh_library(name = 'foo',",
614 " srcs = ['//badpkg1:okay-target', '//okaypkg:transitively-bad-target'])");
615 Path badpkg1BuildFile = scratch.file("badpkg1/BUILD",
616 "exports_files(['okay-target'])",
617 "invalidbuildsyntax");
618 scratch.file("okaypkg/BUILD",
619 "sh_library(name = 'transitively-bad-target',",
620 " srcs = ['//badpkg2:bad-target'])");
621 Path badpkg2BuildFile = scratch.file("badpkg2/BUILD",
622 "sh_library(name = 'bad-target')",
623 "invalidbuildsyntax");
624 update(defaultFlags().with(Flag.KEEP_GOING), "//parent:foo");
625 assertEquals(1, getFrequencyOfErrorsWithLocation(
626 badpkg1BuildFile.asFragment(), eventCollector));
627 assertEquals(1, getFrequencyOfErrorsWithLocation(
628 badpkg2BuildFile.asFragment(), eventCollector));
629 }
630
Florian Weikert79bd2372015-11-26 15:42:24 +0000631 @Test
Dmitry Lomov021a3652015-11-23 14:55:13 +0000632 public void testDepOnGoodTargetInBadPkgAndTransitiveCycle_NotIncremental() throws Exception {
633 runTestDepOnGoodTargetInBadPkgAndTransitiveCycle(/*incremental=*/false);
634 }
635
Florian Weikert79bd2372015-11-26 15:42:24 +0000636 @Test
Dmitry Lomov021a3652015-11-23 14:55:13 +0000637 public void testDepOnGoodTargetInBadPkgAndTransitiveCycle_Incremental() throws Exception {
638 runTestDepOnGoodTargetInBadPkgAndTransitiveCycle(/*incremental=*/true);
639 }
640
641 /**
642 * Regression test: in keep_going mode, cycles in target graph aren't reported
643 * if package is in error.
644 */
Florian Weikert79bd2372015-11-26 15:42:24 +0000645 @Test
Dmitry Lomov021a3652015-11-23 14:55:13 +0000646 public void testCycleReporting_TargetCycleWhenPackageInError() throws Exception {
647 reporter.removeHandler(failFastHandler);
648 scratch.file("cycles/BUILD",
649 "sh_library(name = 'a', deps = [':b'])",
650 "sh_library(name = 'b', deps = [':a'])",
651 "notvalidbuildsyntax");
652 update(defaultFlags().with(Flag.KEEP_GOING), "//cycles:a");
653 assertContainsEvent("'notvalidbuildsyntax'");
654 assertContainsEvent("cycle in dependency graph");
655 }
656
Florian Weikert79bd2372015-11-26 15:42:24 +0000657 @Test
Dmitry Lomov021a3652015-11-23 14:55:13 +0000658 public void testTransitiveLoadingDoesntShortCircuitInKeepGoing() throws Exception {
659 reporter.removeHandler(failFastHandler);
660 scratch.file("parent/BUILD",
661 "sh_library(name = 'a', deps = ['//child:b'])",
662 "parentisbad");
663 scratch.file("child/BUILD",
664 "sh_library(name = 'b')",
665 "childisbad");
666 update(defaultFlags().with(Flag.KEEP_GOING), "//parent:a");
667 assertContainsEventWithFrequency("parentisbad", 1);
668 assertContainsEventWithFrequency("childisbad", 1);
669 assertContainsEventWithFrequency("and referenced by '//parent:a'", 1);
670 }
671
672 /**
673 * Smoke test for the Skyframe code path.
674 */
Florian Weikert79bd2372015-11-26 15:42:24 +0000675 @Test
Dmitry Lomov021a3652015-11-23 14:55:13 +0000676 public void testSkyframe() throws Exception {
677 setupDummyRule();
678 String aoutLabel = "//pkg:a.out";
679
680 update(aoutLabel);
681
682 // However, a ConfiguredTarget was actually produced.
683 ConfiguredTarget target = Iterables.getOnlyElement(getAnalysisResult().getTargetsToBuild());
684 assertEquals(aoutLabel, target.getLabel().toString());
685
686 Artifact aout = Iterables.getOnlyElement(
687 target.getProvider(FileProvider.class).getFilesToBuild());
688 Action action = getGeneratingAction(aout);
689 assertSame(FailAction.class, action.getClass());
690 }
691
692 /**
693 * ConfiguredTargetFunction should not register actions in legacy Blaze ActionGraph unless
694 * the creation of the node is successful.
695 */
Florian Weikert79bd2372015-11-26 15:42:24 +0000696 @Test
Dmitry Lomov021a3652015-11-23 14:55:13 +0000697 public void testActionsNotRegisteredInLegacyWhenError() throws Exception {
698 // First find the artifact we want to make sure is not generated by an action with an error.
699 // Then update the BUILD file and re-analyze.
700 scratch.file("actions_not_registered/BUILD",
701 "cc_binary(name = 'foo', srcs = ['foo.cc'])");
702 update("//actions_not_registered:foo");
703 Artifact fooOut = Iterables.getOnlyElement(
704 getConfiguredTarget("//actions_not_registered:foo")
705 .getProvider(FileProvider.class).getFilesToBuild());
706 assertNotNull(getActionGraph().getGeneratingAction(fooOut));
707 clearAnalysisResult();
708
709 scratch.overwriteFile("actions_not_registered/BUILD",
710 "cc_binary(name = 'foo', linkshared = 1, srcs = ['foo.cc'])");
711
712 reporter.removeHandler(failFastHandler);
713
714 try {
715 update("//actions_not_registered:foo");
716 fail("This build should fail because: 'linkshared' used in non-shared library");
717 } catch (ViewCreationFailedException e) {
718 assertNull(getActionGraph().getGeneratingAction(fooOut));
719 }
720 }
721
722 /**
723 * Regression test:
724 * "skyframe: ArtifactFactory and ConfiguredTargets out of sync".
725 */
Florian Weikert79bd2372015-11-26 15:42:24 +0000726 @Test
Dmitry Lomov021a3652015-11-23 14:55:13 +0000727 public void testSkyframeAnalyzeRuleThenItsOutputFile() throws Exception {
728 scratch.file("pkg/BUILD",
729 "testing_dummy_rule(name='foo', ",
730 " srcs=['a.src'],",
731 " outs=['a.out'])");
732
733 scratch.file("pkg2/BUILD",
734 "testing_dummy_rule(name='foo', ",
735 " srcs=['a.src'],",
736 " outs=['a.out'])");
737 String aoutLabel = "//pkg:a.out";
738
739 update("//pkg2:foo");
740 update("//pkg:foo");
741 scratch.overwriteFile("pkg2/BUILD",
742 "testing_dummy_rule(name='foo', ",
743 " srcs=['a.src'],",
744 " outs=['a.out'])",
745 "# Comment");
746
747 update("//pkg:a.out");
748
749 // However, a ConfiguredTarget was actually produced.
750 ConfiguredTarget target = Iterables.getOnlyElement(getAnalysisResult().getTargetsToBuild());
751 assertEquals(aoutLabel, target.getLabel().toString());
752
753 Artifact aout = Iterables.getOnlyElement(
754 target.getProvider(FileProvider.class).getFilesToBuild());
755 Action action = getGeneratingAction(aout);
756 assertSame(FailAction.class, action.getClass());
757 }
758
759 /**
760 * Tests that skyframe reports the root cause as being the target that depended on the symlink
761 * cycle.
762 */
Florian Weikert79bd2372015-11-26 15:42:24 +0000763 @Test
Dmitry Lomov021a3652015-11-23 14:55:13 +0000764 public void testRootCauseReportingFileSymlinks() throws Exception {
765 scratch.file("gp/BUILD",
766 "sh_library(name = 'gp', deps = ['//p'])");
767 scratch.file("p/BUILD",
768 "sh_library(name = 'p', deps = ['//c'])");
769 scratch.file("c/BUILD",
770 "sh_library(name = 'c', deps = [':c1', ':c2'])",
771 "sh_library(name = 'c1', deps = ['//cycles1'])",
772 "sh_library(name = 'c2', deps = ['//cycles2'])");
773 Path cycles1BuildFilePath = scratch.file("cycles1/BUILD",
774 "sh_library(name = 'cycles1', srcs = glob(['*.sh']))");
775 Path cycles2BuildFilePath = scratch.file("cycles2/BUILD",
776 "sh_library(name = 'cycles2', srcs = glob(['*.sh']))");
777 cycles1BuildFilePath.getParentDirectory().getRelative("cycles1.sh").createSymbolicLink(
778 new PathFragment("cycles1.sh"));
779 cycles2BuildFilePath.getParentDirectory().getRelative("cycles2.sh").createSymbolicLink(
780 new PathFragment("cycles2.sh"));
781 reporter.removeHandler(failFastHandler);
782 EventBus eventBus = new EventBus();
783 LoadingFailureRecorder recorder = new LoadingFailureRecorder();
784 eventBus.register(recorder);
Ulf Adams58581a32016-01-25 15:54:15 +0000785 AnalysisResult result = update(eventBus, defaultFlags().with(Flag.KEEP_GOING), "//gp");
786 assertThat(result.hasError()).isTrue();
Dmitry Lomov021a3652015-11-23 14:55:13 +0000787 assertThat(recorder.events).hasSize(2);
788 assertTrue(recorder.events.toString(), recorder.events.contains(
789 Pair.of(Label.parseAbsolute("//gp"), Label.parseAbsolute("//cycles1"))));
790 assertTrue(recorder.events.toString(), recorder.events.contains(
791 Pair.of(Label.parseAbsolute("//gp"), Label.parseAbsolute("//cycles2"))));
792 }
793
794 /**
795 * Regression test for bug when a configured target has missing deps, but also depends
796 * transitively on an error. We build //foo:query, which depends on a valid and an invalid target
797 * pattern. We ensure that by the time it requests its dependent target patterns, the invalid one
798 * is ready, and throws (though not before the request is registered). Then, when bubbling the
799 * invalid target pattern error up, we ensure that it bubbles into //foo:query, which must cope
800 * with the combination of an error and a missing dep.
801 */
Florian Weikert79bd2372015-11-26 15:42:24 +0000802 @Test
Dmitry Lomov021a3652015-11-23 14:55:13 +0000803 public void testGenQueryWithBadTargetAndUnfinishedTarget() throws Exception {
804 // The target //foo:zquery is used to force evaluation of //foo:nosuchtarget before the target
805 // patterns in //foo:query are enqueued for evaluation. That way, //foo:query will depend on one
806 // invalid target pattern and two target patterns that haven't been evaluated yet.
807 // It is important that 'query' come before 'zquery' alphabetically, so that when the error is
808 // bubbling up, it goes to the //foo:query node -- we use a graph implementation in which the
809 // reverse deps of each entry are ordered alphabetically. It is also important that a missing
810 // target pattern is requested before the exception is thrown, so we have both //foo:b and
811 // //foo:z missing from the deps, in the hopes that at least one of them will come before
812 // //foo:nosuchtarget.
813 scratch.file("foo/BUILD",
814 "genquery(name = 'query',",
815 " expression = 'deps(//foo:b) except //foo:nosuchtarget except //foo:z',",
816 " scope = ['//foo:a'])",
817 "genquery(name = 'zquery',",
818 " expression = 'deps(//foo:nosuchtarget)',",
819 " scope = ['//foo:a'])",
820 "sh_library(name = 'a')",
821 "sh_library(name = 'b')",
822 "sh_library(name = 'z')"
823 );
824 Listener listener =
825 new Listener() {
826 private final CountDownLatch errorDone = new CountDownLatch(1);
827 private final CountDownLatch realQueryStarted = new CountDownLatch(1);
828
829 @Override
830 public void accept(SkyKey key, EventType type, Order order, Object context) {
831 if (!key.functionName().equals(SkyFunctions.TARGET_PATTERN)) {
832 return;
833 }
834 String label = ((TargetPatternKey) key.argument()).getPattern();
835 if (label.equals("//foo:nosuchtarget")) {
836 if (type == EventType.SET_VALUE) {
837 // Inform //foo:query-dep-registering thread that it may proceed.
838 errorDone.countDown();
839 // Wait to make sure //foo:query-dep-registering process has started.
840 TrackingAwaiter.INSTANCE.awaitLatchAndTrackExceptions(
841 realQueryStarted, "//foo:query did not request dep in time");
842 } else if (type == EventType.ADD_REVERSE_DEP
843 && context.toString().contains("foo:query")) {
844 // Make sure that when foo:query requests foo:nosuchtarget, it's already done.
845 TrackingAwaiter.INSTANCE.awaitLatchAndTrackExceptions(
846 errorDone, "//foo:nosuchtarget did not evaluate in time");
847 }
848 } else if ((label.equals("//foo:b") || label.equals("//foo:z"))
849 && type == EventType.CREATE_IF_ABSENT) {
850 // Inform error-evaluating thread that it may throw an exception.
851 realQueryStarted.countDown();
852 TrackingAwaiter.INSTANCE.awaitLatchAndTrackExceptions(
853 errorDone, "//foo:nosuchtarget did not evaluate in time");
854 // Don't let the target pattern //foo:{b,z} get enqueued for evaluation until we
855 // receive an interrupt signal from the threadpool. The interrupt means that
856 // evaluation is shutting down, and so //foo:{b,z} definitely won't get evaluated.
857 CountDownLatch waitForInterrupt = new CountDownLatch(1);
858 try {
859 waitForInterrupt.await(TestUtils.WAIT_TIMEOUT_SECONDS, TimeUnit.SECONDS);
860 throw new IllegalStateException("node was not interrupted in time");
861 } catch (InterruptedException e) {
862 // Expected.
863 Thread.currentThread().interrupt();
864 }
865 }
866 }
867 };
Janak Ramakrishnan8be7fd02016-05-10 20:01:40 +0000868 injectGraphListenerForTesting(listener, /*deterministic=*/ true);
Dmitry Lomov021a3652015-11-23 14:55:13 +0000869 reporter.removeHandler(failFastHandler);
870 try {
871 update("//foo:query", "//foo:zquery");
872 fail();
873 } catch (ViewCreationFailedException e) {
874 Truth.assertThat(e.getMessage())
875 .contains("Analysis of target '//foo:query' failed; build aborted");
876 }
877 TrackingAwaiter.INSTANCE.assertNoErrors();
Dmitry Lomov021a3652015-11-23 14:55:13 +0000878 }
879
880 /**
881 * Tests that rules with configurable attributes can be accessed through {@link
882 * com.google.devtools.build.lib.skyframe.PostConfiguredTargetFunction}.
883 * This is a regression test for a Bazel crash.
884 */
Florian Weikert79bd2372015-11-26 15:42:24 +0000885 @Test
Dmitry Lomov021a3652015-11-23 14:55:13 +0000886 public void testPostProcessedConfigurableAttributes() throws Exception {
Ulf Adamsf32a8452016-09-08 09:38:31 +0000887 useConfiguration("--cpu=k8");
Dmitry Lomov021a3652015-11-23 14:55:13 +0000888 reporter.removeHandler(failFastHandler); // Expect errors from action conflicts.
889 scratch.file("conflict/BUILD",
890 "config_setting(name = 'a', values = {'test_arg': 'a'})",
891 "cc_library(name='x', srcs=select({':a': ['a.cc'], '//conditions:default': ['foo.cc']}))",
892 "cc_binary(name='_objs/x/conflict/foo.pic.o', srcs=['bar.cc'])");
Ulf Adams58581a32016-01-25 15:54:15 +0000893 AnalysisResult result = update(
894 defaultFlags().with(Flag.KEEP_GOING),
895 "//conflict:_objs/x/conflict/foo.pic.o",
Dmitry Lomov021a3652015-11-23 14:55:13 +0000896 "//conflict:x");
Ulf Adams2dc95082016-01-27 12:56:15 +0000897 assertThat(result.hasError()).isTrue();
Dmitry Lomov021a3652015-11-23 14:55:13 +0000898 // Expect to reach this line without a Precondition-triggered NullPointerException.
899 assertContainsEvent(
900 "file 'conflict/_objs/x/conflict/foo.pic.o' is generated by these conflicting actions");
901 }
902
Florian Weikert79bd2372015-11-26 15:42:24 +0000903 @Test
Dmitry Lomov021a3652015-11-23 14:55:13 +0000904 public void testCycleDueToJavaLauncherConfiguration() throws Exception {
Greg Estrenb5692bd2016-06-08 21:09:11 +0000905 if (defaultFlags().contains(Flag.DYNAMIC_CONFIGURATIONS)) {
906 // Dynamic configurations don't yet support late-bound attributes. Development testing already
907 // runs all tests with dynamic configurations enabled, so this will still fail for developers
908 // and won't get lost in the fog.
909 return;
910 }
Dmitry Lomov021a3652015-11-23 14:55:13 +0000911 scratch.file("foo/BUILD",
912 "java_binary(name = 'java', srcs = ['DoesntMatter.java'])",
913 "cc_binary(name = 'cpp', data = [':java'])");
914 // Everything is fine - the dependency graph is acyclic.
Ulf Adams2ac20962016-02-01 13:04:54 +0000915 update("//foo:java", "//foo:cpp");
Greg Estren76c237a2016-11-16 22:09:21 +0000916 if (getTargetConfiguration().trimConfigurations()) {
Greg Estren42c49352016-06-08 20:12:40 +0000917 fail(ExpectedDynamicConfigurationErrors.LATE_BOUND_ATTRIBUTES_UNSUPPORTED);
918 }
Dmitry Lomov021a3652015-11-23 14:55:13 +0000919 // Now there will be an analysis-phase cycle because the java_binary now has an implicit dep on
920 // the cc_binary launcher.
921 useConfiguration("--java_launcher=//foo:cpp");
922 reporter.removeHandler(failFastHandler);
923 try {
Ulf Adams2ac20962016-02-01 13:04:54 +0000924 update("//foo:java", "//foo:cpp");
Dmitry Lomov021a3652015-11-23 14:55:13 +0000925 fail();
926 } catch (ViewCreationFailedException expected) {
927 Truth.assertThat(expected.getMessage())
928 .matches("Analysis of target '//foo:(java|cpp)' failed; build aborted.*");
929 }
930 assertContainsEvent("cycle in dependency graph");
Dmitry Lomov021a3652015-11-23 14:55:13 +0000931 }
Ulf Adams2ac20962016-02-01 13:04:54 +0000932
933 @Test
934 public void testDependsOnBrokenTarget() throws Exception {
935 scratch.file("foo/BUILD",
936 "sh_test(name = 'test', srcs = ['test.sh'], data = ['//bar:data'])");
937 scratch.file("bar/BUILD",
938 "BROKEN BROKEN BROKEN!!!");
939 reporter.removeHandler(failFastHandler);
940 try {
941 update("//foo:test");
942 fail();
Ulf Adams2ac20962016-02-01 13:04:54 +0000943 } catch (ViewCreationFailedException expected) {
944 Truth.assertThat(expected.getMessage())
945 .matches("Analysis of target '//foo:test' failed; build aborted.*");
946 }
947 }
948
Ulf Adams47838c92016-02-02 18:12:44 +0000949 /**
950 * Regression test: IllegalStateException in BuildView.update() on circular dependency instead of
951 * graceful failure.
952 */
953 @Test
954 public void testCircularDependency() throws Exception {
955 scratch.file("cycle/BUILD",
956 "cc_library(name = 'foo', srcs = ['foo.cc'], deps = [':bar'])",
957 "cc_library(name = 'bar', srcs = ['bar.cc'], deps = [':foo'])");
958 reporter.removeHandler(failFastHandler);
959 try {
960 update("//cycle:foo");
961 fail();
Ulf Adamsab64e592016-09-05 09:40:13 +0000962 } catch (ViewCreationFailedException expected) {
Ulf Adams47838c92016-02-02 18:12:44 +0000963 assertContainsEvent("in cc_library rule //cycle:foo: cycle in dependency graph:");
Ulf Adamsab64e592016-09-05 09:40:13 +0000964 assertThat(expected.getMessage())
965 .contains("Analysis of target '//cycle:foo' failed; build aborted");
Ulf Adams47838c92016-02-02 18:12:44 +0000966 }
967 }
968
969 /**
970 * Regression test: IllegalStateException in BuildView.update() on circular dependency instead of
971 * graceful failure.
972 */
973 @Test
974 public void testCircularDependencyWithKeepGoing() throws Exception {
975 scratch.file("cycle/BUILD",
976 "cc_library(name = 'foo', srcs = ['foo.cc'], deps = [':bar'])",
977 "cc_library(name = 'bar', srcs = ['bar.cc'], deps = [':foo'])",
978 "cc_library(name = 'bat', srcs = ['bat.cc'], deps = [':bas'])",
979 "cc_library(name = 'bas', srcs = ['bas.cc'], deps = [':bau'])",
980 "cc_library(name = 'bau', srcs = ['bas.cc'], deps = [':bas'])",
981 "cc_library(name = 'baz', srcs = ['baz.cc'])");
982 reporter.removeHandler(failFastHandler);
983 EventBus eventBus = new EventBus();
984 LoadingFailureRecorder loadingFailureRecorder = new LoadingFailureRecorder();
985 AnalysisFailureRecorder analysisFailureRecorder = new AnalysisFailureRecorder();
986 eventBus.register(loadingFailureRecorder);
987 eventBus.register(analysisFailureRecorder);
988 update(eventBus, defaultFlags().with(Flag.KEEP_GOING),
989 "//cycle:foo", "//cycle:bat", "//cycle:baz");
990 assertContainsEvent("in cc_library rule //cycle:foo: cycle in dependency graph:");
Ulf Adams47838c92016-02-02 18:12:44 +0000991 assertContainsEvent("in cc_library rule //cycle:bas: cycle in dependency graph:");
Ulf Adamsab64e592016-09-05 09:40:13 +0000992 assertContainsEvent(
993 "errors encountered while analyzing target '//cycle:foo': it will not be built");
994 assertContainsEvent(
995 "errors encountered while analyzing target '//cycle:bat': it will not be built");
996 // With interleaved loading and analysis, we can no longer distinguish loading-phase cycles
997 // and analysis-phase cycles. This was previously reported as a loading-phase cycle, as it
998 // happens with any configuration (cycle is hard-coded in the BUILD files). Also see the
999 // test below.
1000 assertThat(Iterables.transform(analysisFailureRecorder.events, ANALYSIS_EVENT_TO_STRING_PAIR))
1001 .containsExactly(
1002 Pair.of("//cycle:foo", "//cycle:foo"), Pair.of("//cycle:bat", "//cycle:bas"));
Ulf Adams47838c92016-02-02 18:12:44 +00001003 }
1004
1005 @Test
1006 public void testCircularDependencyWithLateBoundLabel() throws Exception {
1007 scratch.file("cycle/BUILD",
1008 "cc_library(name = 'foo', deps = [':bar'])",
1009 "cc_library(name = 'bar')");
1010 useConfiguration("--experimental_stl=//cycle:foo");
1011 reporter.removeHandler(failFastHandler);
1012 EventBus eventBus = new EventBus();
1013 LoadingFailureRecorder loadingFailureRecorder = new LoadingFailureRecorder();
1014 AnalysisFailureRecorder analysisFailureRecorder = new AnalysisFailureRecorder();
1015 eventBus.register(loadingFailureRecorder);
1016 eventBus.register(analysisFailureRecorder);
1017 AnalysisResult result = update(eventBus, defaultFlags().with(Flag.KEEP_GOING), "//cycle:foo");
1018 assertThat(result.hasError()).isTrue();
1019 assertContainsEvent("in cc_library rule //cycle:foo: cycle in dependency graph:");
1020 // This needs to be reported as an anlysis-phase cycle; the cycle only occurs due to the stl
1021 // command-line option, which is part of the configuration, and which is used due to the
1022 // late-bound label.
1023 assertThat(Iterables.transform(analysisFailureRecorder.events, ANALYSIS_EVENT_TO_STRING_PAIR))
1024 .containsExactly(Pair.of("//cycle:foo", "//cycle:foo"));
1025 assertThat(loadingFailureRecorder.events).isEmpty();
1026 }
1027
Ulf Adams53abece2016-02-03 08:30:07 +00001028 @Test
1029 public void testLoadingErrorReportedCorrectly() throws Exception {
1030 scratch.file("a/BUILD", "cc_library(name='a')");
1031 scratch.file("b/BUILD", "cc_library(name='b', deps = ['//missing:lib'])");
1032
1033 reporter.removeHandler(failFastHandler);
1034 AnalysisResult result = update(defaultFlags().with(Flag.KEEP_GOING), "//a", "//b");
1035 assertThat(result.hasError()).isTrue();
1036 assertThat(result.getError())
Janak Ramakrishnan6f9d7d12016-08-09 08:45:34 +00001037 .contains("command succeeded, but there were loading phase errors");
Ulf Adams53abece2016-02-03 08:30:07 +00001038 }
1039
Ulf Adams5e8e5fe2016-02-04 09:37:35 +00001040 @Test
Ulf Adams3e34a112016-02-09 16:31:06 +00001041 public void testBadLabelInConfiguration() throws Exception {
1042 useConfiguration("--crosstool_top=//third_party/crosstool/v2");
1043 reporter.removeHandler(failFastHandler);
1044 try {
1045 update(defaultFlags().with(Flag.KEEP_GOING));
1046 fail();
Ulf Adamsab64e592016-09-05 09:40:13 +00001047 } catch (InvalidConfigurationException e) {
Lukacs Berki120b8632016-07-28 10:18:21 +00001048 assertThat(e.getMessage()).contains("third_party/crosstool/v2");
Ulf Adams3e34a112016-02-09 16:31:06 +00001049 }
1050 }
1051
1052 @Test
1053 public void testMissingFdoOptimize() throws Exception {
1054 // The fdo_optimize flag uses a different code path, because it also accepts paths.
1055 useConfiguration("--fdo_optimize=//does/not/exist");
1056 reporter.removeHandler(failFastHandler);
1057 try {
1058 update(defaultFlags().with(Flag.KEEP_GOING));
1059 fail();
Ulf Adamsab64e592016-09-05 09:40:13 +00001060 } catch (InvalidConfigurationException e) {
Ulf Adams3e34a112016-02-09 16:31:06 +00001061 assertContainsEvent(
1062 "no such package 'does/not/exist': BUILD file not found on package path");
1063 }
1064 }
1065
1066 @Test
1067 public void testMissingJavabase() throws Exception {
1068 // The javabase flag uses yet another code path with its own redirection logic on top of the
1069 // redirect chaser.
1070 scratch.file("jdk/BUILD",
1071 "filegroup(name = 'jdk', srcs = [",
1072 " '//does/not/exist:a-piii', '//does/not/exist:b-k8', '//does/not/exist:c-default'])");
1073 scratch.file("does/not/exist/BUILD");
Ulf Adams5b1be3a2016-07-07 12:58:00 +00001074 useConfigurationFactory(AnalysisMock.get().createConfigurationFactory());
Ulf Adams3e34a112016-02-09 16:31:06 +00001075 useConfiguration("--javabase=//jdk");
1076 reporter.removeHandler(failFastHandler);
1077 try {
1078 update(defaultFlags().with(Flag.KEEP_GOING));
1079 fail();
Ulf Adamsab64e592016-09-05 09:40:13 +00001080 } catch (InvalidConfigurationException e) {
Lukacs Berki120b8632016-07-28 10:18:21 +00001081 // Expected
Ulf Adams3e34a112016-02-09 16:31:06 +00001082 }
1083 }
1084
1085 @Test
1086 public void testMissingXcodeVersion() throws Exception {
1087 // The xcode_version flag uses yet another code path on top of the redirect chaser.
1088 // Note that the redirect chaser throws if it can't find a package, but doesn't throw if it
1089 // can't find a label in a package - that's why we use an empty package here.
1090 scratch.file("xcode/BUILD");
1091 useConfiguration("--xcode_version=1.2", "--xcode_version_config=//xcode:does_not_exist");
1092 reporter.removeHandler(failFastHandler);
1093 try {
1094 update(defaultFlags().with(Flag.KEEP_GOING));
1095 fail();
Ulf Adamsab64e592016-09-05 09:40:13 +00001096 } catch (InvalidConfigurationException e) {
Lukacs Berki120b8632016-07-28 10:18:21 +00001097 assertThat(e.getMessage()).contains("//xcode:does_not_exist");
Ulf Adams3e34a112016-02-09 16:31:06 +00001098 }
1099 }
1100
Ulf Adamscaf14772016-02-10 09:50:01 +00001101
1102 @Test
1103 public void testVisibilityReferencesNonexistentPackage() throws Exception {
1104 scratch.file("z/a/BUILD",
1105 "py_library(name='a', visibility=['//nonexistent:nothing'])");
1106 scratch.file("z/b/BUILD",
1107 "py_library(name='b', deps=['//z/a:a'])");
1108 reporter.removeHandler(failFastHandler);
1109 try {
1110 update("//z/b:b");
1111 fail();
Ulf Adamsab64e592016-09-05 09:40:13 +00001112 } catch (ViewCreationFailedException expected) {
Ulf Adamscaf14772016-02-10 09:50:01 +00001113 assertContainsEvent("no such package 'nonexistent'");
1114 }
1115 }
1116
1117 // regression test ("java.lang.IllegalStateException: cannot happen")
1118 @Test
1119 public void testDefaultVisibilityInNonexistentPackage() throws Exception {
1120 scratch.file("z/a/BUILD",
1121 "package(default_visibility=['//b'])",
1122 "py_library(name='alib')");
1123 scratch.file("z/b/BUILD",
1124 "py_library(name='b', deps=['//z/a:alib'])");
1125 reporter.removeHandler(failFastHandler);
1126 try {
1127 update("//z/b:b");
1128 fail();
Ulf Adamsab64e592016-09-05 09:40:13 +00001129 } catch (ViewCreationFailedException expected) {
Ulf Adamscaf14772016-02-10 09:50:01 +00001130 assertContainsEvent("no such package 'b'");
1131 }
1132 }
1133
Ulf Adams76f0ec62016-05-25 12:25:53 +00001134 @Test
1135 public void testNonTopLevelErrorsPrintedExactlyOnce() throws Exception {
1136 scratch.file("parent/BUILD",
1137 "sh_library(name = 'a', deps = ['//child:b'])");
1138 scratch.file("child/BUILD",
1139 "sh_library(name = 'b')",
1140 "undefined_symbol");
1141 reporter.removeHandler(failFastHandler);
1142 try {
1143 update("//parent:a");
1144 fail();
Ulf Adamsab64e592016-09-05 09:40:13 +00001145 } catch (ViewCreationFailedException expected) {
Ulf Adams76f0ec62016-05-25 12:25:53 +00001146 }
1147 assertContainsEventWithFrequency("name 'undefined_symbol' is not defined", 1);
1148 assertContainsEventWithFrequency(
1149 "Target '//child:b' contains an error and its package is in error and referenced "
1150 + "by '//parent:a'", 1);
1151 }
1152
1153 @Test
1154 public void testNonTopLevelErrorsPrintedExactlyOnce_KeepGoing() throws Exception {
1155 scratch.file("parent/BUILD",
1156 "sh_library(name = 'a', deps = ['//child:b'])");
1157 scratch.file("child/BUILD",
1158 "sh_library(name = 'b')",
1159 "undefined_symbol");
1160 reporter.removeHandler(failFastHandler);
1161 update(defaultFlags().with(Flag.KEEP_GOING), "//parent:a");
1162 assertContainsEventWithFrequency("name 'undefined_symbol' is not defined", 1);
1163 assertContainsEventWithFrequency(
1164 "Target '//child:b' contains an error and its package is in error and referenced "
1165 + "by '//parent:a'", 1);
1166 }
1167
1168 @Test
1169 public void testNonTopLevelErrorsPrintedExactlyOnce_ActionListener() throws Exception {
1170 scratch.file("parent/BUILD",
1171 "sh_library(name = 'a', deps = ['//child:b'])");
1172 scratch.file("child/BUILD",
1173 "sh_library(name = 'b')",
1174 "undefined_symbol");
1175 scratch.file("okay/BUILD",
1176 "sh_binary(name = 'okay', srcs = ['okay.sh'])");
1177 useConfiguration("--experimental_action_listener=//parent:a");
1178 reporter.removeHandler(failFastHandler);
1179 try {
1180 update("//okay");
1181 fail();
Ulf Adamsab64e592016-09-05 09:40:13 +00001182 } catch (ViewCreationFailedException e) {
Ulf Adams76f0ec62016-05-25 12:25:53 +00001183 }
1184 assertContainsEventWithFrequency("name 'undefined_symbol' is not defined", 1);
1185 assertContainsEventWithFrequency(
1186 "Target '//child:b' contains an error and its package is in error and referenced "
1187 + "by '//parent:a'", 1);
1188 }
1189
1190 @Test
1191 public void testNonTopLevelErrorsPrintedExactlyOnce_ActionListener_KeepGoing() throws Exception {
1192 scratch.file("parent/BUILD",
1193 "sh_library(name = 'a', deps = ['//child:b'])");
1194 scratch.file("child/BUILD",
1195 "sh_library(name = 'b')",
1196 "undefined_symbol");
1197 scratch.file("okay/BUILD",
1198 "sh_binary(name = 'okay', srcs = ['okay.sh'])");
1199 useConfiguration("--experimental_action_listener=//parent:a");
1200 reporter.removeHandler(failFastHandler);
Ulf Adamsab64e592016-09-05 09:40:13 +00001201 update(defaultFlags().with(Flag.KEEP_GOING), "//okay");
Ulf Adams76f0ec62016-05-25 12:25:53 +00001202 assertContainsEventWithFrequency("name 'undefined_symbol' is not defined", 1);
1203 assertContainsEventWithFrequency(
1204 "Target '//child:b' contains an error and its package is in error and referenced "
1205 + "by '//parent:a'", 1);
1206 }
1207
Greg Estren7971e672016-06-01 23:22:48 +00001208 @Test
1209 public void testTopLevelTargetsAreTrimmedWithDynamicConfigurations() throws Exception {
1210 scratch.file("foo/BUILD",
1211 "sh_library(name='x', ",
1212 " srcs=['x.sh'])");
Greg Estren1d8ba902016-09-21 21:18:19 +00001213 useConfiguration("--experimental_dynamic_configs=on");
Greg Estren7971e672016-06-01 23:22:48 +00001214 AnalysisResult res = update("//foo:x");
1215 ConfiguredTarget topLevelTarget = Iterables.getOnlyElement(res.getTargetsToBuild());
1216 assertThat(topLevelTarget.getConfiguration().getAllFragments().keySet()).containsExactly(
1217 ruleClassProvider.getUniversalFragment());
1218 }
1219
Greg Estren2bc88382016-08-02 21:45:35 +00001220 @Test
1221 public void errorOnMissingDepFragments() throws Exception {
1222 scratch.file("foo/BUILD",
1223 "cc_library(",
1224 " name = 'ccbin', ",
1225 " srcs = ['c.cc'],",
1226 " data = [':javalib'])",
1227 "java_library(",
1228 " name = 'javalib',",
1229 " srcs = ['javalib.java'])");
Greg Estren1d8ba902016-09-21 21:18:19 +00001230 useConfiguration("--experimental_dynamic_configs=on", "--experimental_disable_jvm");
Greg Estren2bc88382016-08-02 21:45:35 +00001231 reporter.removeHandler(failFastHandler);
1232 try {
1233 update("//foo:ccbin");
1234 fail();
1235 } catch (ViewCreationFailedException e) {
1236 // Expected.
1237 }
1238 assertContainsEvent("//foo:ccbin: dependency //foo:javalib from attribute \"data\" is missing "
1239 + "required config fragments: Jvm");
1240 }
1241
Greg Estren373e3e22016-08-09 22:36:51 +00001242 @Test
1243 public void lateBoundSplitAttributeConfigs() throws Exception {
1244 useRuleClassProvider(LateBoundSplitUtil.getRuleClassProvider());
1245 // Register the latebound split fragment with the config creation environment.
1246 useConfigurationFactory(new ConfigurationFactory(
1247 ruleClassProvider.getConfigurationCollectionFactory(),
1248 ruleClassProvider.getConfigurationFragments()));
1249
1250 scratch.file("foo/BUILD",
1251 "rule_with_latebound_split(",
1252 " name = 'foo')",
Greg Estren247ac162016-08-10 20:50:09 +00001253 "rule_with_test_fragment(",
1254 " name = 'latebound_dep')");
Greg Estren373e3e22016-08-09 22:36:51 +00001255 update("//foo:foo");
1256 assertNotNull(getConfiguredTarget("//foo:foo"));
Greg Estren247ac162016-08-10 20:50:09 +00001257 Iterable<ConfiguredTarget> deps = SkyframeExecutorTestUtils.getExistingConfiguredTargets(
1258 skyframeExecutor, Label.parseAbsolute("//foo:latebound_dep"));
1259 assertThat(deps).hasSize(2);
1260 assertThat(
1261 ImmutableList.of(
1262 LateBoundSplitUtil.getOptions(Iterables.get(deps, 0).getConfiguration()).fooFlag,
1263 LateBoundSplitUtil.getOptions(Iterables.get(deps, 1).getConfiguration()).fooFlag))
1264 .containsExactly("one", "two");
Greg Estren373e3e22016-08-09 22:36:51 +00001265 }
1266
Carmi Grushkobabd4852016-11-18 17:58:09 +00001267 /**
1268 * Here, injecting_rule injects an aspect which acts on a action_rule() and registers an action.
1269 * The action_rule() registers another action of its own.
1270 *
1271 * <p>This test asserts that both actions are reported.
1272 */
1273 @Test
1274 public void ruleExtraActionsDontHideAspectExtraActions() throws Exception {
1275 useConfiguration("--experimental_action_listener=//pkg:listener");
1276
1277 scratch.file(
1278 "x/BUILD",
1279 "load(':extension.bzl', 'injecting_rule', 'action_rule')",
1280 "injecting_rule(name='a', deps=[':b'])",
1281 "action_rule(name='b')");
1282
1283 scratch.file(
1284 "x/extension.bzl",
1285 "def _aspect1_impl(target, ctx):",
1286 " ctx.empty_action(mnemonic='Mnemonic')",
1287 " return struct()",
1288 "aspect1 = aspect(_aspect1_impl, attr_aspects=['deps'])",
1289 "",
1290 "def _injecting_rule_impl(ctx):",
1291 " return struct()",
1292 "injecting_rule = rule(_injecting_rule_impl, ",
1293 " attrs = { 'deps' : attr.label_list(aspects = [aspect1]) })",
1294 "",
1295 "def _action_rule_impl(ctx):",
1296 " out = ctx.new_file(ctx.label.name)",
1297 " ctx.action(outputs = [out], command = 'dontcare', mnemonic='Mnemonic')",
1298 " return struct()",
1299 "action_rule = rule(_action_rule_impl, attrs = { 'deps' : attr.label_list() })");
1300
1301 scratch.file(
1302 "pkg/BUILD",
1303 "extra_action(name='xa', cmd='echo dont-care')",
1304 "action_listener(name='listener', mnemonics=['Mnemonic'], extra_actions=[':xa'])");
1305
1306 BuildView.AnalysisResult analysisResult = update("//x:a");
1307
1308 List<String> owners = new ArrayList<>();
1309 for (Artifact artifact : analysisResult.getAdditionalArtifactsToBuild()) {
1310 if ("xa".equals(artifact.getExtension())) {
1311 owners.add(artifact.getOwnerLabel().toString());
1312 }
1313 }
1314 assertThat(owners).containsExactly("//x:b", "//x:b");
1315 }
1316
Ulf Adamsaf0b6702017-01-18 10:58:10 +00001317 @Test
1318 public void testErrorMessageForMissingPackageGroup() throws Exception {
1319 scratch.file(
1320 "apple/BUILD",
1321 "py_library(name='apple', visibility=['//non:existent'])");
1322 reporter.removeHandler(failFastHandler);
1323 try {
1324 update("//apple");
1325 fail();
1326 } catch (ViewCreationFailedException e) {
1327 // Expected.
1328 }
1329 assertDoesNotContainEvent("implicitly depends upon");
1330 }
1331
Ulf Adams2ac20962016-02-01 13:04:54 +00001332 /** Runs the same test with the reduced loading phase. */
1333 @TestSpec(size = Suite.SMALL_TESTS)
1334 @RunWith(JUnit4.class)
1335 public static class WithSkyframeLoadingPhase extends BuildViewTest {
1336 @Override
1337 protected FlagBuilder defaultFlags() {
1338 return super.defaultFlags().with(Flag.SKYFRAME_LOADING_PHASE);
1339 }
1340 }
Greg Estrenb5692bd2016-06-08 21:09:11 +00001341
1342 /** Runs the same test with dynamic configurations. */
1343 @TestSpec(size = Suite.SMALL_TESTS)
1344 @RunWith(JUnit4.class)
1345 public static class WithDynamicConfigurations extends BuildViewTest {
1346 @Override
1347 protected FlagBuilder defaultFlags() {
1348 return super.defaultFlags().with(Flag.DYNAMIC_CONFIGURATIONS);
1349 }
1350 }
Dmitry Lomov021a3652015-11-23 14:55:13 +00001351}