blob: 3093d8de4c85a42ed63e7b8dc03fd27ae3c3f108 [file] [log] [blame]
Dmitry Lomov1b2e3e32015-11-23 13:19:02 +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;
Dmitry Lomov1b2e3e32015-11-23 13:19:02 +000016import static com.google.common.truth.Truth.assertThat;
Florian Weikertf7bd7682015-11-26 15:42:17 +000017import static org.junit.Assert.assertEquals;
18import static org.junit.Assert.assertNotNull;
19import static org.junit.Assert.assertNotSame;
20import static org.junit.Assert.assertSame;
21import static org.junit.Assert.assertTrue;
22import static org.junit.Assert.fail;
Dmitry Lomov1b2e3e32015-11-23 13:19:02 +000023
24import com.google.common.collect.ImmutableList;
25import com.google.devtools.build.lib.actions.Action;
26import com.google.devtools.build.lib.analysis.util.AnalysisCachingTestBase;
Googler1d4c9d22016-03-17 15:56:41 +000027import com.google.devtools.build.lib.events.Event;
Dmitry Lomov1b2e3e32015-11-23 13:19:02 +000028import com.google.devtools.build.lib.rules.java.JavaSourceJarsProvider;
29import com.google.devtools.build.lib.testutil.Suite;
30import com.google.devtools.build.lib.testutil.TestSpec;
Dmitry Lomov1b2e3e32015-11-23 13:19:02 +000031import java.util.Set;
Googler1d4c9d22016-03-17 15:56:41 +000032import java.util.regex.Matcher;
33import java.util.regex.Pattern;
Ulf Adamsab64e592016-09-05 09:40:13 +000034import org.junit.Test;
35import org.junit.runner.RunWith;
36import org.junit.runners.JUnit4;
Dmitry Lomov1b2e3e32015-11-23 13:19:02 +000037
38/**
39 * Analysis caching tests.
40 */
41@TestSpec(size = Suite.SMALL_TESTS)
Florian Weikertf7bd7682015-11-26 15:42:17 +000042@RunWith(JUnit4.class)
Dmitry Lomov1b2e3e32015-11-23 13:19:02 +000043public class AnalysisCachingTest extends AnalysisCachingTestBase {
44
Florian Weikertf7bd7682015-11-26 15:42:17 +000045 @Test
Dmitry Lomov1b2e3e32015-11-23 13:19:02 +000046 public void testSimpleCleanAnalysis() throws Exception {
47 scratch.file("java/a/BUILD",
48 "java_test(name = 'A',",
49 " srcs = ['A.java'])");
50 update("//java/a:A");
51 ConfiguredTarget javaTest = getConfiguredTarget("//java/a:A");
52 assertNotNull(javaTest);
53 assertNotNull(javaTest.getProvider(JavaSourceJarsProvider.class));
54 }
55
Florian Weikertf7bd7682015-11-26 15:42:17 +000056 @Test
Dmitry Lomov1b2e3e32015-11-23 13:19:02 +000057 public void testTickTock() throws Exception {
58 scratch.file("java/a/BUILD",
59 "java_test(name = 'A',",
60 " srcs = ['A.java'])",
61 "java_test(name = 'B',",
62 " srcs = ['B.java'])");
63 update("//java/a:A");
64 update("//java/a:B");
65 update("//java/a:A");
66 }
67
Florian Weikertf7bd7682015-11-26 15:42:17 +000068 @Test
Dmitry Lomov1b2e3e32015-11-23 13:19:02 +000069 public void testFullyCached() throws Exception {
70 scratch.file("java/a/BUILD",
71 "java_test(name = 'A',",
72 " srcs = ['A.java'])");
73 update("//java/a:A");
74 ConfiguredTarget old = getConfiguredTarget("//java/a:A");
75 update("//java/a:A");
76 ConfiguredTarget current = getConfiguredTarget("//java/a:A");
77 assertSame(old, current);
78 }
79
Florian Weikertf7bd7682015-11-26 15:42:17 +000080 @Test
Dmitry Lomov1b2e3e32015-11-23 13:19:02 +000081 public void testSubsetCached() throws Exception {
82 scratch.file("java/a/BUILD",
83 "java_test(name = 'A',",
84 " srcs = ['A.java'])",
85 "java_test(name = 'B',",
86 " srcs = ['B.java'])");
87 update("//java/a:A", "//java/a:B");
88 ConfiguredTarget old = getConfiguredTarget("//java/a:A");
89 update("//java/a:A");
90 ConfiguredTarget current = getConfiguredTarget("//java/a:A");
91 assertSame(old, current);
92 }
93
Florian Weikertf7bd7682015-11-26 15:42:17 +000094 @Test
Dmitry Lomov1b2e3e32015-11-23 13:19:02 +000095 public void testDependencyChanged() throws Exception {
96 scratch.file("java/a/BUILD",
97 "java_test(name = 'A',",
98 " srcs = ['A.java'],",
99 " deps = ['//java/b'])");
100 scratch.file("java/b/BUILD",
101 "java_library(name = 'b',",
102 " srcs = ['B.java'])");
103 update("//java/a:A");
104 ConfiguredTarget old = getConfiguredTarget("//java/a:A");
105 scratch.overwriteFile("java/b/BUILD",
106 "java_library(name = 'b',",
107 " srcs = ['C.java'])");
108 update("//java/a:A");
109 ConfiguredTarget current = getConfiguredTarget("//java/a:A");
110 assertNotSame(old, current);
111 }
112
Florian Weikertf7bd7682015-11-26 15:42:17 +0000113 @Test
Dmitry Lomov1b2e3e32015-11-23 13:19:02 +0000114 public void testTopLevelChanged() throws Exception {
115 scratch.file("java/a/BUILD",
116 "java_test(name = 'A',",
117 " srcs = ['A.java'],",
118 " deps = ['//java/b'])");
119 scratch.file("java/b/BUILD",
120 "java_library(name = 'b',",
121 " srcs = ['B.java'])");
122 update("//java/a:A");
123 ConfiguredTarget old = getConfiguredTarget("//java/a:A");
124 scratch.overwriteFile("java/a/BUILD",
125 "java_test(name = 'A',",
126 " srcs = ['A.java'])");
127 update("//java/a:A");
128 ConfiguredTarget current = getConfiguredTarget("//java/a:A");
129 assertNotSame(old, current);
130 }
131
132 // Regression test for:
133 // "action conflict detection is incorrect if conflict is in non-top-level configured targets".
Florian Weikertf7bd7682015-11-26 15:42:17 +0000134 @Test
Dmitry Lomov1b2e3e32015-11-23 13:19:02 +0000135 public void testActionConflictInDependencyImpliesTopLevelTargetFailure() throws Exception {
Ulf Adamsf32a8452016-09-08 09:38:31 +0000136 useConfiguration("--cpu=k8");
Dmitry Lomov1b2e3e32015-11-23 13:19:02 +0000137 scratch.file("conflict/BUILD",
138 "cc_library(name='x', srcs=['foo.cc'])",
139 "cc_binary(name='_objs/x/conflict/foo.pic.o', srcs=['bar.cc'])",
140 "cc_binary(name='foo', deps=['x'], data=['_objs/x/conflict/foo.pic.o'])");
141 reporter.removeHandler(failFastHandler); // expect errors
142 update(defaultFlags().with(Flag.KEEP_GOING), "//conflict:foo");
143 assertContainsEvent("file 'conflict/_objs/x/conflict/foo.pic.o' " + CONFLICT_MSG);
144 assertThat(getAnalysisResult().getTargetsToBuild()).isEmpty();
145 }
146
147 /**
148 * Generating the same output from two targets is ok if we build them on successive builds
149 * and invalidate the first target before we build the second target. This is a strictly weaker
150 * test than if we didn't invalidate the first target, but since Skyframe can't pass then, this
151 * test could be useful for it. Actually, since Skyframe makes multiple update calls, it manages
152 * to unregister actions even when it shouldn't, and so this test can incorrectly pass. However,
153 * {@code SkyframeExecutorTest#testNoActionConflictWithInvalidatedTarget} tests it more
154 * rigorously.
155 */
Florian Weikertf7bd7682015-11-26 15:42:17 +0000156 @Test
Dmitry Lomov1b2e3e32015-11-23 13:19:02 +0000157 public void testNoActionConflictWithInvalidatedTarget() throws Exception {
Ulf Adamsf32a8452016-09-08 09:38:31 +0000158 useConfiguration("--cpu=k8");
Dmitry Lomov1b2e3e32015-11-23 13:19:02 +0000159 scratch.file("conflict/BUILD",
160 "cc_library(name='x', srcs=['foo.cc'])",
Ulf Adamsf32a8452016-09-08 09:38:31 +0000161 "cc_binary(name='_objs/x/conflict/foo.o', srcs=['bar.cc'])");
Dmitry Lomov1b2e3e32015-11-23 13:19:02 +0000162 update("//conflict:x");
163 ConfiguredTarget conflict = getConfiguredTarget("//conflict:x");
164 Action oldAction = getGeneratingAction(getBinArtifact("_objs/x/conflict/foo.pic.o", conflict));
165 assertEquals("//conflict:x", oldAction.getOwner().getLabel().toString());
166 scratch.overwriteFile("conflict/BUILD",
167 "cc_library(name='newx', srcs=['foo.cc'])", // Rename target.
168 "cc_binary(name='_objs/x/conflict/foo.pic.o', srcs=['bar.cc'])");
169 update(defaultFlags(), "//conflict:_objs/x/conflict/foo.pic.o");
170 ConfiguredTarget objsConflict = getConfiguredTarget("//conflict:_objs/x/conflict/foo.pic.o");
171 Action newAction =
172 getGeneratingAction(getBinArtifact("_objs/x/conflict/foo.pic.o", objsConflict));
173 assertEquals("//conflict:_objs/x/conflict/foo.pic.o",
174 newAction.getOwner().getLabel().toString());
175 }
176
177 /**
178 * Generating the same output from multiple actions is causing an error.
179 */
Florian Weikertf7bd7682015-11-26 15:42:17 +0000180 @Test
Dmitry Lomov1b2e3e32015-11-23 13:19:02 +0000181 public void testActionConflictCausesError() throws Exception {
Ulf Adamsf32a8452016-09-08 09:38:31 +0000182 useConfiguration("--cpu=k8");
Dmitry Lomov1b2e3e32015-11-23 13:19:02 +0000183 scratch.file("conflict/BUILD",
184 "cc_library(name='x', srcs=['foo.cc'])",
185 "cc_binary(name='_objs/x/conflict/foo.pic.o', srcs=['bar.cc'])");
186 reporter.removeHandler(failFastHandler); // expect errors
187 update(defaultFlags().with(Flag.KEEP_GOING),
188 "//conflict:x", "//conflict:_objs/x/conflict/foo.pic.o");
189 assertContainsEvent("file 'conflict/_objs/x/conflict/foo.pic.o' " + CONFLICT_MSG);
190 }
191
Florian Weikertf7bd7682015-11-26 15:42:17 +0000192 @Test
Dmitry Lomov1b2e3e32015-11-23 13:19:02 +0000193 public void testNoActionConflictErrorAfterClearedAnalysis() throws Exception {
Ulf Adamsf32a8452016-09-08 09:38:31 +0000194 useConfiguration("--cpu=k8");
Dmitry Lomov1b2e3e32015-11-23 13:19:02 +0000195 scratch.file("conflict/BUILD",
196 "cc_library(name='x', srcs=['foo.cc'])",
197 "cc_binary(name='_objs/x/conflict/foo.pic.o', srcs=['bar.cc'])");
198 reporter.removeHandler(failFastHandler); // expect errors
199 update(defaultFlags().with(Flag.KEEP_GOING),
200 "//conflict:x", "//conflict:_objs/x/conflict/foo.pic.o");
201 // We want to force a "dropConfiguredTargetsNow" operation, which won't inform the
202 // invalidation receiver about the dropped configured targets.
203 getView().clearAnalysisCache(ImmutableList.<ConfiguredTarget>of());
204 assertContainsEvent("file 'conflict/_objs/x/conflict/foo.pic.o' " + CONFLICT_MSG);
205 eventCollector.clear();
206 scratch.overwriteFile("conflict/BUILD",
207 "cc_library(name='x', srcs=['baz.cc'])",
208 "cc_binary(name='_objs/x/conflict/foo.pic.o', srcs=['bar.cc'])");
209 update(defaultFlags().with(Flag.KEEP_GOING),
210 "//conflict:x", "//conflict:_objs/x/conflict/foo.pic.o");
211 assertNoEvents();
212 }
Googler1d4c9d22016-03-17 15:56:41 +0000213
214 /**
215 * For two conflicting actions whose primary inputs are different, no list diff detail should be
216 * part of the output.
217 */
218 @Test
219 public void testConflictingArtifactsErrorWithNoListDetail() throws Exception {
Ulf Adamsf32a8452016-09-08 09:38:31 +0000220 useConfiguration("--cpu=k8");
Googler1d4c9d22016-03-17 15:56:41 +0000221 scratch.file(
222 "conflict/BUILD",
223 "cc_library(name='x', srcs=['foo.cc'])",
224 "cc_binary(name='_objs/x/conflict/foo.pic.o', srcs=['bar.cc'])");
225 reporter.removeHandler(failFastHandler); // expect errors
226 update(
227 defaultFlags().with(Flag.KEEP_GOING),
228 "//conflict:x",
229 "//conflict:_objs/x/conflict/foo.pic.o");
230
231 assertContainsEvent("file 'conflict/_objs/x/conflict/foo.pic.o' " + CONFLICT_MSG);
232 assertDoesNotContainEvent("MandatoryInputs");
233 assertDoesNotContainEvent("Outputs");
234 }
235
236 /**
237 * For two conflicted actions whose primary inputs are the same, list diff (max 5) should be part
238 * of the output.
239 */
240 @Test
241 public void testConflictingArtifactsWithListDetail() throws Exception {
Ulf Adamsf32a8452016-09-08 09:38:31 +0000242 useConfiguration("--cpu=k8");
Googler1d4c9d22016-03-17 15:56:41 +0000243 scratch.file(
244 "conflict/BUILD",
245 "cc_library(name='x', srcs=['foo1.cc', 'foo2.cc', 'foo3.cc', 'foo4.cc', 'foo5.cc'"
246 + ", 'foo6.cc'])",
247 "genrule(name = 'foo', outs=['_objs/x/conflict/foo1.pic.o'], srcs=['foo1.cc', 'foo2.cc', "
248 + "'foo3.cc', 'foo4.cc', 'foo5.cc', 'foo6.cc'], cmd='', output_to_bindir=1)");
249 reporter.removeHandler(failFastHandler); // expect errors
250 update(defaultFlags().with(Flag.KEEP_GOING), "//conflict:x", "//conflict:foo");
251
252 Event event =
253 assertContainsEvent("file 'conflict/_objs/x/conflict/foo1.pic.o' " + CONFLICT_MSG);
254 assertContainsEvent("MandatoryInputs");
255 assertContainsEvent("Outputs");
256
257 // Validate that maximum of 5 artifacts in MandatoryInputs are part of output.
258 Pattern pattern = Pattern.compile("\tconflict\\/foo[1-6].cc");
259 Matcher matcher = pattern.matcher(event.getMessage());
260 int matchCount = 0;
261 while (matcher.find()) {
262 matchCount++;
263 }
264
265 assertEquals(5, matchCount);
266 }
Dmitry Lomov1b2e3e32015-11-23 13:19:02 +0000267
268 /**
269 * The current action conflict detection code will only mark one of the targets as having an
270 * error, and with multi-threaded analysis it is not deterministic which one that will be.
271 */
Florian Weikertf7bd7682015-11-26 15:42:17 +0000272 @Test
Dmitry Lomov1b2e3e32015-11-23 13:19:02 +0000273 public void testActionConflictMarksTargetInvalid() throws Exception {
Ulf Adamsf32a8452016-09-08 09:38:31 +0000274 useConfiguration("--cpu=k8");
Dmitry Lomov1b2e3e32015-11-23 13:19:02 +0000275 scratch.file("conflict/BUILD",
276 "cc_library(name='x', srcs=['foo.cc'])",
Ulf Adamsf32a8452016-09-08 09:38:31 +0000277 "cc_binary(name='_objs/x/conflict/foo.o', srcs=['bar.cc'])");
Dmitry Lomov1b2e3e32015-11-23 13:19:02 +0000278 reporter.removeHandler(failFastHandler); // expect errors
279 update(defaultFlags().with(Flag.KEEP_GOING),
280 "//conflict:x", "//conflict:_objs/x/conflict/foo.pic.o");
281 ConfiguredTarget a = getConfiguredTarget("//conflict:x");
282 ConfiguredTarget b = getConfiguredTarget("//conflict:_objs/x/conflict/foo.pic.o");
283 assertTrue(hasTopLevelAnalysisError(a) ^ hasTopLevelAnalysisError(b));
284 }
285
286 /**
287 * BUILD file involved in BUILD-file cycle is changed
288 */
Florian Weikertf7bd7682015-11-26 15:42:17 +0000289 @Test
Dmitry Lomov1b2e3e32015-11-23 13:19:02 +0000290 public void testBuildFileInCycleChanged() throws Exception {
291 scratch.file("java/a/BUILD",
292 "java_test(name = 'A',",
293 " srcs = ['A.java'],",
294 " deps = ['//java/b'])");
295 scratch.file("java/b/BUILD",
296 "java_library(name = 'b',",
297 " srcs = ['B.java'],",
298 " deps = ['//java/c'])");
299 scratch.file("java/c/BUILD",
300 "java_library(name = 'c',",
301 " srcs = ['C.java'],",
302 " deps = ['//java/b'])");
303 // expect error
304 reporter.removeHandler(failFastHandler);
305 update(defaultFlags().with(Flag.KEEP_GOING), "//java/a:A");
306 ConfiguredTarget old = getConfiguredTarget("//java/a:A");
307 // drop dependency on from b to c
308 scratch.overwriteFile("java/b/BUILD",
309 "java_library(name = 'b',",
310 " srcs = ['B.java'])");
311 eventCollector.clear();
312 reporter.addHandler(failFastHandler);
313 update("//java/a:A");
314 ConfiguredTarget current = getConfiguredTarget("//java/a:A");
315 assertNotSame(old, current);
316 }
317
318 private void assertNoTargetsVisited() {
319 Set<?> analyzedTargets = getSkyframeEvaluatedTargetKeys();
320 assertEquals(analyzedTargets.toString(), 0, analyzedTargets.size());
321 }
322
Florian Weikertf7bd7682015-11-26 15:42:17 +0000323 @Test
Dmitry Lomov1b2e3e32015-11-23 13:19:02 +0000324 public void testSecondRunAllCacheHits() throws Exception {
325 scratch.file("java/a/BUILD",
326 "java_test(name = 'A',",
327 " srcs = ['A.java'])");
328 update("//java/a:A");
329 update("//java/a:A");
330 assertNoTargetsVisited();
331 }
332
Florian Weikertf7bd7682015-11-26 15:42:17 +0000333 @Test
Dmitry Lomov1b2e3e32015-11-23 13:19:02 +0000334 public void testDependencyAllCacheHits() throws Exception {
335 scratch.file("java/a/BUILD",
336 "java_library(name = 'x', srcs = ['A.java'], deps = ['y'])",
337 "java_library(name = 'y', srcs = ['B.java'])");
338 update("//java/a:x");
339 Set<?> oldAnalyzedTargets = getSkyframeEvaluatedTargetKeys();
340 assertTrue(oldAnalyzedTargets.size() >= 2); // could be greater due to implicit deps
341 assertEquals(1, countObjectsPartiallyMatchingRegex(oldAnalyzedTargets, "//java/a:x"));
342 assertEquals(1, countObjectsPartiallyMatchingRegex(oldAnalyzedTargets, "//java/a:y"));
343 update("//java/a:y");
344 assertNoTargetsVisited();
345 }
346
Florian Weikertf7bd7682015-11-26 15:42:17 +0000347 @Test
Dmitry Lomov1b2e3e32015-11-23 13:19:02 +0000348 public void testSupersetNotAllCacheHits() throws Exception {
349 scratch.file("java/a/BUILD",
350 // It's important that all targets are of the same rule class, otherwise the second update
351 // call might analyze more than one extra target because of potential implicit dependencies.
352 "java_library(name = 'x', srcs = ['A.java'], deps = ['y'])",
353 "java_library(name = 'y', srcs = ['B.java'], deps = ['z'])",
354 "java_library(name = 'z', srcs = ['C.java'])");
355 update("//java/a:y");
356 Set<?> oldAnalyzedTargets = getSkyframeEvaluatedTargetKeys();
357 assertTrue(oldAnalyzedTargets.size() >= 3); // could be greater due to implicit deps
358 assertEquals(0, countObjectsPartiallyMatchingRegex(oldAnalyzedTargets, "//java/a:x"));
359 assertEquals(1, countObjectsPartiallyMatchingRegex(oldAnalyzedTargets, "//java/a:y"));
360 update("//java/a:x");
361 Set<?> newAnalyzedTargets = getSkyframeEvaluatedTargetKeys();
362 assertTrue(newAnalyzedTargets.size() >= 1); // could be greater due to implicit deps
363 assertEquals(1, countObjectsPartiallyMatchingRegex(newAnalyzedTargets, "//java/a:x"));
364 assertEquals(0, countObjectsPartiallyMatchingRegex(newAnalyzedTargets, "//java/a:y"));
365 }
366
Florian Weikertf7bd7682015-11-26 15:42:17 +0000367 @Test
Dmitry Lomov1b2e3e32015-11-23 13:19:02 +0000368 public void testExtraActions() throws Exception {
369 scratch.file("java/com/google/a/BUILD", "java_library(name='a', srcs=['A.java'])");
370 scratch.file("java/com/google/b/BUILD", "java_library(name='b', srcs=['B.java'])");
371 scratch.file("extra/BUILD",
372 "extra_action(name = 'extra',",
373 " out_templates = ['$(OWNER_LABEL_DIGEST)_$(ACTION_ID).tst'],",
374 " cmd = '')",
375 "action_listener(name = 'listener',",
376 " mnemonics = ['Javac'],",
377 " extra_actions = [':extra'])");
378
379 useConfiguration("--experimental_action_listener=//extra:listener");
380 update("//java/com/google/a:a");
381 update("//java/com/google/b:b");
382 }
383
Florian Weikertf7bd7682015-11-26 15:42:17 +0000384 @Test
Dmitry Lomov1b2e3e32015-11-23 13:19:02 +0000385 public void testExtraActionsCaching() throws Exception {
386 scratch.file("java/a/BUILD", "java_library(name='a', srcs=['A.java'])");
387 scratch.file("extra/BUILD",
388 "extra_action(name = 'extra',",
389 " out_templates = ['$(OWNER_LABEL_DIGEST)_$(ACTION_ID).tst'],",
390 " cmd = 'echo $(EXTRA_ACTION_FILE)')",
391 "action_listener(name = 'listener',",
392 " mnemonics = ['Javac'],",
393 " extra_actions = [':extra'])");
394 useConfiguration("--experimental_action_listener=//extra:listener");
395
396 update("//java/a:a");
397 getConfiguredTarget("//java/a:a");
398
399 scratch.overwriteFile("extra/BUILD",
400 "extra_action(name = 'extra',",
401 " out_templates = ['$(OWNER_LABEL_DIGEST)_$(ACTION_ID).tst'],",
402 " cmd = 'echo $(BUG)')", // <-- change here
403 "action_listener(name = 'listener',",
404 " mnemonics = ['Javac'],",
405 " extra_actions = [':extra'])");
406 reporter.removeHandler(failFastHandler);
407 try {
408 update("//java/a:a");
409 fail();
410 } catch (ViewCreationFailedException e) {
411 assertThat(e.getMessage()).contains("Analysis of target '//java/a:a' failed");
412 assertContainsEvent("Unable to expand make variables: $(BUG)");
413 }
414 }
415
Florian Weikertf7bd7682015-11-26 15:42:17 +0000416 @Test
Dmitry Lomov1b2e3e32015-11-23 13:19:02 +0000417 public void testConfigurationCachingWithWarningReplay() throws Exception {
418 useConfiguration("--test_sharding_strategy=experimental_heuristic");
419 update();
420 assertContainsEvent("Heuristic sharding is intended as a one-off experimentation tool");
421 eventCollector.clear();
422 update();
423 assertContainsEvent("Heuristic sharding is intended as a one-off experimentation tool");
424 }
425
Florian Weikertf7bd7682015-11-26 15:42:17 +0000426 @Test
Dmitry Lomov1b2e3e32015-11-23 13:19:02 +0000427 public void testWorkspaceStatusCommandIsNotCachedForNullBuild() throws Exception {
428 update();
429 WorkspaceStatusAction actionA = getView().getLastWorkspaceBuildInfoActionForTesting();
430 assertEquals("DummyBuildInfoAction", actionA.getMnemonic());
431
432 workspaceStatusActionFactory.setKey("Second");
433 update();
434 WorkspaceStatusAction actionB = getView().getLastWorkspaceBuildInfoActionForTesting();
435 assertEquals("DummyBuildInfoActionSecond", actionB.getMnemonic());
436 }
437
Florian Weikertf7bd7682015-11-26 15:42:17 +0000438 @Test
Dmitry Lomov1b2e3e32015-11-23 13:19:02 +0000439 public void testSkyframeCacheInvalidationBuildFileChange() throws Exception {
440 scratch.file("java/a/BUILD",
441 "java_test(name = 'A',",
442 " srcs = ['A.java'])");
443 String aTarget = "//java/a:A";
444 update(aTarget);
445 ConfiguredTarget firstCT = getConfiguredTarget(aTarget);
446
447 scratch.overwriteFile("java/a/BUILD",
448 "java_test(name = 'A',",
449 " srcs = ['B.java'])");
450
451 update(aTarget);
452 ConfiguredTarget updatedCT = getConfiguredTarget(aTarget);
453 assertNotSame(firstCT, updatedCT);
454
455 update(aTarget);
456 ConfiguredTarget updated2CT = getConfiguredTarget(aTarget);
457 assertSame(updatedCT, updated2CT);
458 }
459
Florian Weikertf7bd7682015-11-26 15:42:17 +0000460 @Test
Dmitry Lomov1b2e3e32015-11-23 13:19:02 +0000461 public void testSkyframeDifferentPackagesInvalidation() throws Exception {
462 scratch.file("java/a/BUILD",
463 "java_test(name = 'A',",
464 " srcs = ['A.java'])");
465
466 scratch.file("java/b/BUILD",
467 "java_test(name = 'B',",
468 " srcs = ['B.java'])");
469
470 String aTarget = "//java/a:A";
471 update(aTarget);
472 ConfiguredTarget oldAConfTarget = getConfiguredTarget(aTarget);
473 String bTarget = "//java/b:B";
474 update(bTarget);
475 ConfiguredTarget oldBConfTarget = getConfiguredTarget(bTarget);
476
477 scratch.overwriteFile("java/b/BUILD",
478 "java_test(name = 'B',",
479 " srcs = ['C.java'])");
480
481 update(aTarget);
482 // Check that 'A' was not invalidated because 'B' was modified and invalidated.
483 ConfiguredTarget newAConfTarget = getConfiguredTarget(aTarget);
484 ConfiguredTarget newBConfTarget = getConfiguredTarget(bTarget);
485
486 assertSame(oldAConfTarget, newAConfTarget);
487 assertNotSame(oldBConfTarget, newBConfTarget);
488 }
489
490 private int countObjectsPartiallyMatchingRegex(Iterable<? extends Object> elements,
491 String toStringMatching) {
492 toStringMatching = ".*" + toStringMatching + ".*";
493 int result = 0;
494 for (Object o : elements) {
495 if (o.toString().matches(toStringMatching)) {
496 ++result;
497 }
498 }
499 return result;
500 }
501
Florian Weikertf7bd7682015-11-26 15:42:17 +0000502 @Test
Dmitry Lomov1b2e3e32015-11-23 13:19:02 +0000503 public void testGetSkyframeEvaluatedTargetKeysOmitsCachedTargets() throws Exception {
504 scratch.file("java/a/BUILD",
505 "java_library(name = 'x', srcs = ['A.java'], deps = ['z', 'w'])",
506 "java_library(name = 'y', srcs = ['B.java'], deps = ['z', 'w'])",
507 "java_library(name = 'z', srcs = ['C.java'])",
508 "java_library(name = 'w', srcs = ['D.java'])");
509
510 update("//java/a:x");
511 Set<?> oldAnalyzedTargets = getSkyframeEvaluatedTargetKeys();
512 assertTrue(oldAnalyzedTargets.size() >= 2); // could be greater due to implicit deps
513 assertEquals(1, countObjectsPartiallyMatchingRegex(oldAnalyzedTargets, "//java/a:x"));
514 assertEquals(0, countObjectsPartiallyMatchingRegex(oldAnalyzedTargets, "//java/a:y"));
515 assertEquals(1, countObjectsPartiallyMatchingRegex(oldAnalyzedTargets, "//java/a:z"));
516 assertEquals(1, countObjectsPartiallyMatchingRegex(oldAnalyzedTargets, "//java/a:w"));
517
518 // Unless the build is not fully cached, we get notified about newly evaluated targets, as well
519 // as cached top-level targets. For the two tests above to work correctly, we need to ensure
520 // that getSkyframeEvaluatedTargetKeys() doesn't return these.
521 update("//java/a:x", "//java/a:y", "//java/a:z");
522 Set<?> newAnalyzedTargets = getSkyframeEvaluatedTargetKeys();
523 assertThat(newAnalyzedTargets).hasSize(2);
524 assertEquals(1, countObjectsPartiallyMatchingRegex(newAnalyzedTargets, "//java/a:B.java"));
525 assertEquals(1, countObjectsPartiallyMatchingRegex(newAnalyzedTargets, "//java/a:y"));
526 }
Dmitry Lomov1b2e3e32015-11-23 13:19:02 +0000527}