From 021a3657b5dfed6961ec18586b1bdcfebd693f95 Mon Sep 17 00:00:00 2001 From: Dmitry Lomov Date: Mon, 23 Nov 2015 14:55:13 +0000 Subject: Open-source BuildViewTest. -- MOS_MIGRATED_REVID=108501464 --- src/test/java/com/google/devtools/build/lib/BUILD | 8 + .../devtools/build/lib/analysis/BuildViewTest.java | 795 +++++++++++++++++++++ .../build/lib/analysis/util/BuildViewTestBase.java | 172 +++++ 3 files changed, 975 insertions(+) create mode 100644 src/test/java/com/google/devtools/build/lib/analysis/BuildViewTest.java create mode 100644 src/test/java/com/google/devtools/build/lib/analysis/util/BuildViewTestBase.java (limited to 'src/test') diff --git a/src/test/java/com/google/devtools/build/lib/BUILD b/src/test/java/com/google/devtools/build/lib/BUILD index 0ce1d00fb1..b8f4cfacbe 100644 --- a/src/test/java/com/google/devtools/build/lib/BUILD +++ b/src/test/java/com/google/devtools/build/lib/BUILD @@ -296,6 +296,9 @@ java_library( "MOCK_CROSSTOOL", ], tags = ["analysis"], + exports = [ + "//src/test/java/com/google/devtools/build/skyframe:testutil", + ], deps = [ ":actions_testutil", ":foundations_testutil", @@ -314,9 +317,12 @@ java_library( "//src/main/java/com/google/devtools/build/lib:util", "//src/main/java/com/google/devtools/build/lib:vfs", "//src/main/java/com/google/devtools/build/lib/actions", + "//src/main/java/com/google/devtools/build/lib/query2", + "//src/main/java/com/google/devtools/build/lib/rules/genquery", "//src/main/java/com/google/devtools/build/skyframe", "//src/main/java/com/google/devtools/common/options", "//src/main/protobuf:extra_actions_base_proto", + "//src/test/java/com/google/devtools/build/skyframe:testutil", "//third_party:guava", "//third_party:guava-testlib", "//third_party:jsr305", @@ -450,8 +456,10 @@ java_test( "//src/main/java/com/google/devtools/build/lib:collect", "//src/main/java/com/google/devtools/build/lib:events", "//src/main/java/com/google/devtools/build/lib:packages", + "//src/main/java/com/google/devtools/build/lib:util", "//src/main/java/com/google/devtools/build/lib:vfs", "//src/main/java/com/google/devtools/build/lib/actions", + "//src/main/java/com/google/devtools/build/skyframe", "//third_party:guava", "//third_party:guava-testlib", "//third_party:jsr305", diff --git a/src/test/java/com/google/devtools/build/lib/analysis/BuildViewTest.java b/src/test/java/com/google/devtools/build/lib/analysis/BuildViewTest.java new file mode 100644 index 0000000000..c725c12731 --- /dev/null +++ b/src/test/java/com/google/devtools/build/lib/analysis/BuildViewTest.java @@ -0,0 +1,795 @@ +// Copyright 2015 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.devtools.build.lib.analysis; + +import static com.google.common.truth.Truth.assertThat; +import static com.google.devtools.build.lib.testutil.MoreAsserts.assertEventCount; + +import com.google.common.base.Function; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +import com.google.common.eventbus.EventBus; +import com.google.common.truth.Truth; +import com.google.devtools.build.lib.actions.Action; +import com.google.devtools.build.lib.actions.Actions; +import com.google.devtools.build.lib.actions.Artifact; +import com.google.devtools.build.lib.actions.FailAction; +import com.google.devtools.build.lib.analysis.DependencyResolver.Dependency; +import com.google.devtools.build.lib.analysis.config.BuildConfiguration; +import com.google.devtools.build.lib.analysis.config.InvalidConfigurationException; +import com.google.devtools.build.lib.analysis.util.BuildViewTestBase; +import com.google.devtools.build.lib.cmdline.Label; +import com.google.devtools.build.lib.packages.Aspect; +import com.google.devtools.build.lib.packages.Attribute; +import com.google.devtools.build.lib.packages.Rule; +import com.google.devtools.build.lib.pkgcache.LoadingFailedException; +import com.google.devtools.build.lib.skyframe.SkyFunctions; +import com.google.devtools.build.lib.skyframe.TargetPatternValue.TargetPatternKey; +import com.google.devtools.build.lib.testutil.Suite; +import com.google.devtools.build.lib.testutil.TestSpec; +import com.google.devtools.build.lib.testutil.TestUtils; +import com.google.devtools.build.lib.util.Pair; +import com.google.devtools.build.lib.vfs.Path; +import com.google.devtools.build.lib.vfs.PathFragment; +import com.google.devtools.build.skyframe.DeterministicInMemoryGraph; +import com.google.devtools.build.skyframe.NotifyingInMemoryGraph; +import com.google.devtools.build.skyframe.NotifyingInMemoryGraph.EventType; +import com.google.devtools.build.skyframe.NotifyingInMemoryGraph.Listener; +import com.google.devtools.build.skyframe.NotifyingInMemoryGraph.Order; +import com.google.devtools.build.skyframe.SkyKey; +import com.google.devtools.build.skyframe.TrackingAwaiter; + +import java.util.Collection; +import java.util.LinkedHashSet; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.regex.Pattern; + +/** + * Tests for the {@link BuildView}. + */ +@TestSpec(size = Suite.SMALL_TESTS) +public final class BuildViewTest extends BuildViewTestBase { + + public void testRuleConfiguredTarget() throws Exception { + scratch.file("pkg/BUILD", + "genrule(name='foo', ", + " cmd = '',", + " srcs=['a.src'],", + " outs=['a.out'])"); + update("//pkg:foo"); + Rule ruleTarget = (Rule) getTarget("//pkg:foo"); + assertEquals("genrule", ruleTarget.getRuleClass()); + + ConfiguredTarget ruleCT = getConfiguredTarget("//pkg:foo"); + + assertSame(ruleTarget, ruleCT.getTarget()); + } + + public void testFilterByTargets() throws Exception { + scratch.file("tests/BUILD", + "sh_test(name = 'small_test_1',", + " srcs = ['small_test_1.sh'],", + " data = [':xUnit'],", + " size = 'small',", + " tags = ['tag1'])", + "", + "sh_test(name = 'small_test_2',", + " srcs = ['small_test_2.sh'],", + " size = 'small',", + " tags = ['tag2'])", + "", + "", + "test_suite( name = 'smallTests', tags=['small'])"); + //scratch.file("tests/small_test_1.py"); + + update("//tests:smallTests"); + + ConfiguredTarget test1 = getConfiguredTarget("//tests:small_test_1"); + ConfiguredTarget test2 = getConfiguredTarget("//tests:small_test_2"); + ConfiguredTarget suite = getConfiguredTarget("//tests:smallTests"); + assertNoEvents(); // start from a clean slate + + + Collection targets = + new LinkedHashSet<>(ImmutableList.of(test1, test2, suite)); + targets = Lists.newArrayList( + BuildView.filterTestsByTargets(targets, + Sets.newHashSet(test1.getTarget(), suite.getTarget()))); + assertThat(targets).containsExactlyElementsIn(Sets.newHashSet(test1, suite)); + } + + public void testSourceArtifact() throws Exception { + setupDummyRule(); + update("//pkg:a.src"); + InputFileConfiguredTarget inputCT = getInputFileConfiguredTarget("//pkg:a.src"); + Artifact inputArtifact = inputCT.getArtifact(); + assertNull(getGeneratingAction(inputArtifact)); + assertEquals("pkg/a.src", inputArtifact.getExecPathString()); + } + + public void testGeneratedArtifact() throws Exception { + setupDummyRule(); + update("//pkg:a.out"); + OutputFileConfiguredTarget outputCT = (OutputFileConfiguredTarget) + getConfiguredTarget("//pkg:a.out"); + Artifact outputArtifact = outputCT.getArtifact(); + assertEquals(getTargetConfiguration().getBinDirectory(), outputArtifact.getRoot()); + assertEquals(getTargetConfiguration().getBinFragment().getRelative("pkg/a.out"), + outputArtifact.getExecPath()); + assertEquals(new PathFragment("pkg/a.out"), outputArtifact.getRootRelativePath()); + + Action action = getGeneratingAction(outputArtifact); + assertSame(FailAction.class, action.getClass()); + } + + // TODO(bazel-team): this test is bad, it seems to rely on genrule emitting a warning to make the + // analysis fail, this needs a proper way to inject errors/warnings + public void disabled_testReportsAnalysisRootCauses() throws Exception { + scratch.file("pkg/BUILD", + "genrule(name='foo',", + " tools=[:missing],", + " outs=['foofile'],", + " cmd='')", + "genrule(name='bar',", + " srcs=['foofile'],", + " outs=['barfile'],", + " cmd='')"); + + reporter.removeHandler(failFastHandler); + EventBus eventBus = new EventBus(); + AnalysisFailureRecorder recorder = new AnalysisFailureRecorder(); + eventBus.register(recorder); + update(eventBus, defaultFlags().with(Flag.KEEP_GOING), "//pkg:bar"); + assertThat(recorder.events).hasSize(1); + AnalysisFailureEvent event = recorder.events.get(0); + assertEquals("//pkg:foo", event.getFailureReason().toString()); + assertEquals("//pkg:bar", event.getFailedTarget().getLabel().toString()); + } + + public void testReportsLoadingRootCauses() throws Exception { + scratch.file("pkg/BUILD", + "genrule(name='foo',", + " tools=['//nopackage:missing'],", + " cmd='')"); + + reporter.removeHandler(failFastHandler); + EventBus eventBus = new EventBus(); + LoadingFailureRecorder recorder = new LoadingFailureRecorder(); + eventBus.register(recorder); + // Note: no need to run analysis for a loading failure. + update(eventBus, defaultFlags().with(Flag.KEEP_GOING), "//pkg:foo"); + assertThat(recorder.events) + .contains( + Pair.of(Label.parseAbsolute("//pkg:foo"), Label.parseAbsolute("//nopackage:missing"))); + assertContainsEvent("missing value for mandatory attribute 'outs'"); + assertContainsEvent("no such package 'nopackage'"); + // Skyframe correctly reports the other root cause as the genrule itself (since it is + // missing attributes). + assertThat(recorder.events).hasSize(2); + assertThat(recorder.events) + .contains(Pair.of(Label.parseAbsolute("//pkg:foo"), Label.parseAbsolute("//pkg:foo"))); + } + + public void testConvolutedLoadRootCauseAnalysis() throws Exception { + // You need license declarations in third_party. We use this constraint to + // create targets that are loadable, but are in error. + scratch.file("third_party/first/BUILD", + "sh_library(name='first', deps=['//third_party/second'], licenses=['notice'])"); + scratch.file("third_party/second/BUILD", + "sh_library(name='second', deps=['//third_party/third'], licenses=['notice'])"); + scratch.file("third_party/third/BUILD", + "sh_library(name='third', deps=['//third_party/fourth'], licenses=['notice'])"); + scratch.file("third_party/fourth/BUILD", + "sh_library(name='fourth', deps=['//third_party/fifth'])"); + scratch.file("third_party/fifth/BUILD", + "sh_library(name='fifth', licenses=['notice'])"); + reporter.removeHandler(failFastHandler); + EventBus eventBus = new EventBus(); + LoadingFailureRecorder recorder = new LoadingFailureRecorder(); + eventBus.register(recorder); + // Note: no need to run analysis for a loading failure. + update(eventBus, defaultFlags().with(Flag.KEEP_GOING), + "//third_party/first", "//third_party/third"); + assertThat(recorder.events).hasSize(2); + assertTrue(recorder.events.toString(), recorder.events.contains( + Pair.of(Label.parseAbsolute("//third_party/first"), + Label.parseAbsolute("//third_party/fourth")))); + assertThat(recorder.events) + .contains(Pair.of( + Label.parseAbsolute("//third_party/third"), + Label.parseAbsolute("//third_party/fourth"))); + } + + public void testMultipleRootCauseReporting() throws Exception { + scratch.file("gp/BUILD", + "sh_library(name = 'gp', deps = ['//p:p'])"); + scratch.file("p/BUILD", + "sh_library(name = 'p', deps = ['//c1:not', '//c2:not'])"); + scratch.file("c1/BUILD"); + scratch.file("c2/BUILD"); + reporter.removeHandler(failFastHandler); + EventBus eventBus = new EventBus(); + LoadingFailureRecorder recorder = new LoadingFailureRecorder(); + eventBus.register(recorder); + update(eventBus, defaultFlags().with(Flag.KEEP_GOING), "//gp"); + assertThat(recorder.events).hasSize(2); + assertTrue(recorder.events.toString(), recorder.events.contains( + Pair.of(Label.parseAbsolute("//gp"), + Label.parseAbsolute("//c1:not")))); + assertThat(recorder.events) + .contains(Pair.of(Label.parseAbsolute("//gp"), Label.parseAbsolute("//c2:not"))); + } + + /** + * Regression test for: "Package group includes are broken" + */ + public void testTopLevelPackageGroup() throws Exception { + scratch.file("tropical/BUILD", + "package_group(name='guava', includes=[':mango'])", + "package_group(name='mango')"); + + // If the analysis phase results in an error, this will throw an exception + update("//tropical:guava"); + + // Check if the included package group also got analyzed + assertNotNull(getConfiguredTarget("//tropical:mango", null)); + } + + public void testTopLevelInputFile() throws Exception { + scratch.file("tropical/BUILD", + "exports_files(['file.txt'])"); + update("//tropical:file.txt"); + assertNotNull(getConfiguredTarget("//tropical:file.txt", null)); + } + + public void testGetDirectPrerequisites() throws Exception { + scratch.file( + "package/BUILD", + "filegroup(name='top', srcs=[':inner', 'file'])", + "sh_binary(name='inner', srcs=['script.sh'])"); + update("//package:top"); + ConfiguredTarget top = getConfiguredTarget("//package:top", getTargetConfiguration()); + Iterable targets = getView().getDirectPrerequisitesForTesting( + reporter, top, getBuildConfigurationCollection()); + Iterable