| // Copyright 2022 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.buildtool; |
| |
| import static com.google.common.truth.Truth.assertThat; |
| import static org.junit.Assert.assertThrows; |
| |
| import com.google.devtools.build.lib.actions.BuildFailedException; |
| import com.google.devtools.build.lib.analysis.ViewCreationFailedException; |
| import com.google.devtools.build.lib.buildtool.util.BuildIntegrationTestCase; |
| import com.google.testing.junit.testparameterinjector.TestParameter; |
| import com.google.testing.junit.testparameterinjector.TestParameterInjector; |
| import java.io.IOException; |
| import org.junit.Before; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| |
| /** Integration test for {@link com.google.devtools.build.lib.skyframe.BuildResultListener}. */ |
| @RunWith(TestParameterInjector.class) |
| public class BuildResultListenerIntegrationTest extends BuildIntegrationTestCase { |
| @TestParameter boolean mergedAnalysisExecution; |
| |
| @Before |
| public final void setUp() { |
| addOptions("--experimental_merged_skyframe_analysis_execution=" + mergedAnalysisExecution); |
| } |
| |
| /** A simple rule that has srcs, deps and writes these attributes to its output. */ |
| private void writeMyRuleBzl() throws IOException { |
| write( |
| "foo/my_rule.bzl", |
| """ |
| def _path(file): |
| return file.path |
| |
| def _impl(ctx): |
| inputs = depset( |
| ctx.files.srcs, |
| transitive = [dep[DefaultInfo].files for dep in ctx.attr.deps], |
| ) |
| output = ctx.actions.declare_file(ctx.attr.name + ".out") |
| command = "echo $@ > %s" % (output.path) |
| args = ctx.actions.args() |
| args.add_all(inputs, map_each = _path) |
| ctx.actions.run_shell( |
| inputs = inputs, |
| outputs = [output], |
| command = command, |
| arguments = [args], |
| ) |
| return DefaultInfo(files = depset([output])) |
| |
| my_rule = rule( |
| implementation = _impl, |
| attrs = { |
| "srcs": attr.label_list(allow_files = True), |
| "deps": attr.label_list(providers = ["DefaultInfo"]), |
| }, |
| ) |
| """); |
| } |
| |
| private void writeAnalysisFailureAspectBzl() throws IOException { |
| write( |
| "foo/aspect.bzl", |
| """ |
| def _aspect_impl(target, ctx): |
| malformed |
| |
| analysis_err_aspect = aspect(implementation = _aspect_impl) |
| """); |
| } |
| |
| private void writeExecutionFailureAspectBzl() throws IOException { |
| write( |
| "foo/aspect.bzl", |
| """ |
| def _aspect_impl(target, ctx): |
| output = ctx.actions.declare_file("aspect_output") |
| ctx.actions.run_shell( |
| outputs = [output], |
| command = "false", |
| ) |
| return [OutputGroupInfo( |
| files = depset([output]), |
| )] |
| |
| execution_err_aspect = aspect(implementation = _aspect_impl) |
| """); |
| } |
| |
| private void writeSuccessfulAspectBzl() throws IOException { |
| write( |
| "foo/aspect.bzl", |
| """ |
| def _aspect_impl(target, ctx): |
| print("hello") |
| return [] |
| |
| successful_aspect = aspect(implementation = _aspect_impl) |
| """); |
| } |
| |
| @Test |
| public void multiTargetBuild_success() throws Exception { |
| writeMyRuleBzl(); |
| writeSuccessfulAspectBzl(); |
| write( |
| "foo/BUILD", |
| """ |
| load("//foo:my_rule.bzl", "my_rule") |
| |
| my_rule( |
| name = "bar", |
| srcs = ["bar.in"], |
| ) |
| |
| my_rule( |
| name = "foo", |
| srcs = ["foo.in"], |
| ) |
| """); |
| write("foo/foo.in"); |
| write("foo/bar.in"); |
| addOptions("--aspects=//foo:aspect.bzl%successful_aspect"); |
| |
| BuildResult result = buildTarget("//foo:foo", "//foo:bar"); |
| |
| assertThat(result.getSuccess()).isTrue(); |
| assertThat(getLabelsOfAnalyzedTargets()).containsExactly("//foo:foo", "//foo:bar"); |
| assertThat(getLabelsOfBuiltTargets()).containsExactly("//foo:foo", "//foo:bar"); |
| assertThat(getLabelsOfAnalyzedAspects()).containsExactly("//foo:foo", "//foo:bar"); |
| assertThat(getLabelsOfBuiltAspects()).containsExactly("//foo:foo", "//foo:bar"); |
| } |
| |
| @Test |
| public void aspectAnalysisFailure_consistentWithNonSkymeld() throws Exception { |
| writeMyRuleBzl(); |
| writeAnalysisFailureAspectBzl(); |
| write( |
| "foo/BUILD", |
| """ |
| load("//foo:my_rule.bzl", "my_rule") |
| |
| my_rule( |
| name = "foo", |
| srcs = ["foo.in"], |
| ) |
| """); |
| write("foo/foo.in"); |
| |
| addOptions("--aspects=//foo:aspect.bzl%analysis_err_aspect", "--output_groups=files"); |
| |
| assertThrows(ViewCreationFailedException.class, () -> buildTarget("//foo:foo")); |
| |
| assertThat(getLabelsOfAnalyzedAspects()).isEmpty(); |
| } |
| |
| @Test |
| public void aspectExecutionFailure_consistentWithNonSkymeld(@TestParameter boolean keepGoing) |
| throws Exception { |
| addOptions("--keep_going=" + keepGoing); |
| writeMyRuleBzl(); |
| writeExecutionFailureAspectBzl(); |
| write( |
| "foo/BUILD", |
| """ |
| load("//foo:my_rule.bzl", "my_rule") |
| |
| my_rule( |
| name = "foo", |
| srcs = ["foo.in"], |
| ) |
| """); |
| write("foo/foo.in"); |
| |
| addOptions("--aspects=//foo:aspect.bzl%execution_err_aspect", "--output_groups=files"); |
| |
| assertThrows(BuildFailedException.class, () -> buildTarget("//foo:foo")); |
| |
| assertThat(getLabelsOfAnalyzedAspects()).contains("//foo:foo"); |
| assertThat(getLabelsOfBuiltAspects()).isEmpty(); |
| } |
| |
| @Test |
| public void targetExecutionFailure_consistentWithNonSkymeld(@TestParameter boolean keepGoing) |
| throws Exception { |
| addOptions("--keep_going=" + keepGoing); |
| writeMyRuleBzl(); |
| write( |
| "foo/BUILD", |
| """ |
| load("//foo:my_rule.bzl", "my_rule") |
| |
| my_rule( |
| name = "execution_failure", |
| srcs = ["missing"], |
| ) |
| |
| my_rule( |
| name = "foo", |
| srcs = ["foo.in"], |
| ) |
| """); |
| write("foo/foo.in"); |
| |
| assertThrows( |
| BuildFailedException.class, () -> buildTarget("//foo:foo", "//foo:execution_failure")); |
| |
| assertThat(getLabelsOfAnalyzedTargets()).contains("//foo:execution_failure"); |
| if (keepGoing) { |
| assertThat(getLabelsOfAnalyzedTargets()) |
| .containsExactly("//foo:foo", "//foo:execution_failure"); |
| assertThat(getLabelsOfBuiltTargets()).containsExactly("//foo:foo"); |
| } |
| } |
| |
| @Test |
| public void targetAnalysisFailure_consistentWithNonSkymeld(@TestParameter boolean keepGoing) |
| throws Exception { |
| addOptions("--keep_going=" + keepGoing); |
| writeMyRuleBzl(); |
| write( |
| "foo/BUILD", |
| """ |
| load("//foo:my_rule.bzl", "my_rule") |
| |
| my_rule( |
| name = "analysis_failure", |
| srcs = ["foo.in"], |
| deps = [":missing"], |
| ) |
| |
| my_rule( |
| name = "foo", |
| srcs = ["foo.in"], |
| ) |
| """); |
| write("foo/foo.in"); |
| |
| if (keepGoing) { |
| assertThrows( |
| BuildFailedException.class, () -> buildTarget("//foo:foo", "//foo:analysis_failure")); |
| assertThat(getLabelsOfAnalyzedTargets()).contains("//foo:foo"); |
| assertThat(getLabelsOfBuiltTargets()).containsExactly("//foo:foo"); |
| } else { |
| assertThrows( |
| ViewCreationFailedException.class, |
| () -> buildTarget("//foo:foo", "//foo:analysis_failure")); |
| assertThat(getBuildResultListener().getBuiltTargets()).isEmpty(); |
| } |
| } |
| |
| @Test |
| public void nullIncrementalBuild_correctAnalyzedAndBuiltTargets() throws Exception { |
| writeMyRuleBzl(); |
| write( |
| "foo/BUILD", |
| """ |
| load("//foo:my_rule.bzl", "my_rule") |
| |
| my_rule( |
| name = "foo", |
| srcs = ["foo.in"], |
| ) |
| """); |
| write("foo/foo.in"); |
| |
| BuildResult result = buildTarget("//foo:foo"); |
| |
| assertThat(result.getSuccess()).isTrue(); |
| assertThat(getLabelsOfAnalyzedTargets()).containsExactly("//foo:foo"); |
| assertThat(getLabelsOfBuiltTargets()).containsExactly("//foo:foo"); |
| |
| result = buildTarget("//foo:foo"); |
| |
| assertThat(result.getSuccess()).isTrue(); |
| assertThat(getLabelsOfAnalyzedTargets()).containsExactly("//foo:foo"); |
| assertThat(getLabelsOfBuiltTargets()).containsExactly("//foo:foo"); |
| } |
| } |