From d70d329ee6d52b3d9dc7340e99f2b27736c45785 Mon Sep 17 00:00:00 2001 From: leba Date: Thu, 3 Mar 2022 08:29:27 -0800 Subject: [PATCH] Replace the existing skymeld bash tests with Java integration tests. We'll continue adding more tests here as we go along. PiperOrigin-RevId: 432200357 --- .../google/devtools/build/lib/buildtool/BUILD | 18 +++ .../SkymeldBuildIntegrationTest.java | 152 ++++++++++++++++++ .../merged_skyframe_phases_test.sh | 147 ----------------- 3 files changed, 170 insertions(+), 147 deletions(-) create mode 100644 src/test/java/com/google/devtools/build/lib/buildtool/SkymeldBuildIntegrationTest.java delete mode 100755 src/test/shell/integration/merged_skyframe_phases_test.sh diff --git a/src/test/java/com/google/devtools/build/lib/buildtool/BUILD b/src/test/java/com/google/devtools/build/lib/buildtool/BUILD index 7a41888aff5d55..0cf35e9e77d439 100644 --- a/src/test/java/com/google/devtools/build/lib/buildtool/BUILD +++ b/src/test/java/com/google/devtools/build/lib/buildtool/BUILD @@ -629,3 +629,21 @@ java_test( "//third_party:truth", ], ) + +java_test( + name = "SkymeldBuildIntegrationTest", + srcs = ["SkymeldBuildIntegrationTest.java"], + tags = [ + "no_windows", + ], + deps = [ + "//src/main/java/com/google/devtools/build/lib:runtime", + "//src/main/java/com/google/devtools/build/lib/actions", + "//src/main/java/com/google/devtools/build/lib/analysis:view_creation_failed_exception", + "//src/test/java/com/google/devtools/build/lib/buildtool/util", + "//third_party:guava", + "//third_party:junit4", + "//third_party:truth", + "@com_google_testparameterinjector//:testparameterinjector", + ], +) diff --git a/src/test/java/com/google/devtools/build/lib/buildtool/SkymeldBuildIntegrationTest.java b/src/test/java/com/google/devtools/build/lib/buildtool/SkymeldBuildIntegrationTest.java new file mode 100644 index 00000000000000..101ecdb0aa7a3d --- /dev/null +++ b/src/test/java/com/google/devtools/build/lib/buildtool/SkymeldBuildIntegrationTest.java @@ -0,0 +1,152 @@ +// 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.common.collect.Iterables; +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 tests for project Skymeld: interleaving Skyframe's analysis and execution phases. */ +@RunWith(TestParameterInjector.class) +public class SkymeldBuildIntegrationTest extends BuildIntegrationTestCase { + + @Before + public void setUp() { + addOptions("--experimental_merged_skyframe_analysis_execution"); + } + + /** 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 assertSingleOutputBuilt(String target) throws Exception { + assertThat(Iterables.getOnlyElement(getArtifacts(target)).getPath().isFile()).isTrue(); + } + + @Test + public void multiTargetBuild_success() throws Exception { + writeMyRuleBzl(); + 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"); + + BuildResult result = buildTarget("//foo:foo", "//foo:bar"); + + assertThat(result.getSuccess()).isTrue(); + assertSingleOutputBuilt("//foo:foo"); + assertSingleOutputBuilt("//foo:bar"); + } + + @Test + public void onlyExecutionFailure(@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")); + if (keepGoing) { + assertSingleOutputBuilt("//foo:foo"); + } + events.assertContainsError( + "Action foo/execution_failure.out failed: missing input file '//foo:missing'"); + } + + @Test + public void onlyAnalysisFailure(@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")); + assertSingleOutputBuilt("//foo:foo"); + } else { + assertThrows( + ViewCreationFailedException.class, + () -> buildTarget("//foo:foo", "//foo:analysis_failure")); + } + events.assertContainsError("rule '//foo:missing' does not exist"); + } + + @Test + public void analysisAndExecutionFailure_keepGoing_bothReported() throws Exception { + addOptions("--keep_going"); + writeMyRuleBzl(); + write( + "foo/BUILD", + "load('//foo:my_rule.bzl', 'my_rule')", + "my_rule(name = 'execution_failure', srcs = ['missing'])", + "my_rule(name = 'analysis_failure', srcs = ['foo.in'], deps = [':missing'])"); + write("foo/foo.in"); + + assertThrows( + BuildFailedException.class, + () -> buildTarget("//foo:analysis_failure", "//foo:execution_failure")); + events.assertContainsError( + "Action foo/execution_failure.out failed: missing input file '//foo:missing'"); + events.assertContainsError("rule '//foo:missing' does not exist"); + } +} diff --git a/src/test/shell/integration/merged_skyframe_phases_test.sh b/src/test/shell/integration/merged_skyframe_phases_test.sh deleted file mode 100755 index 8ac19f6e4db93a..00000000000000 --- a/src/test/shell/integration/merged_skyframe_phases_test.sh +++ /dev/null @@ -1,147 +0,0 @@ -#!/bin/bash -# -# Copyright 2021 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. -# -# execution_phase_tests.sh: miscellaneous integration tests of Bazel for -# behaviors that affect the execution phase. -# - -# --- begin runfiles.bash initialization --- -set -euo pipefail -if [[ ! -d "${RUNFILES_DIR:-/dev/null}" && ! -f "${RUNFILES_MANIFEST_FILE:-/dev/null}" ]]; then - if [[ -f "$0.runfiles_manifest" ]]; then - export RUNFILES_MANIFEST_FILE="$0.runfiles_manifest" - elif [[ -f "$0.runfiles/MANIFEST" ]]; then - export RUNFILES_MANIFEST_FILE="$0.runfiles/MANIFEST" - elif [[ -f "$0.runfiles/bazel_tools/tools/bash/runfiles/runfiles.bash" ]]; then - export RUNFILES_DIR="$0.runfiles" - fi -fi -if [[ -f "${RUNFILES_DIR:-/dev/null}/bazel_tools/tools/bash/runfiles/runfiles.bash" ]]; then - source "${RUNFILES_DIR}/bazel_tools/tools/bash/runfiles/runfiles.bash" -elif [[ -f "${RUNFILES_MANIFEST_FILE:-/dev/null}" ]]; then - source "$(grep -m1 "^bazel_tools/tools/bash/runfiles/runfiles.bash " \ - "$RUNFILES_MANIFEST_FILE" | cut -d ' ' -f 2-)" -else - echo >&2 "ERROR: cannot find @bazel_tools//tools/bash/runfiles:runfiles.bash" - exit 1 -fi -# --- end runfiles.bash initialization --- - -source "$(rlocation "io_bazel/src/test/shell/integration_test_setup.sh")" \ - || { echo "integration_test_setup.sh not found!" >&2; exit 1; } - -case "$(uname -s | tr [:upper:] [:lower:])" in -msys*|mingw*|cygwin*) - declare -r is_windows=true - ;; -*) - declare -r is_windows=false - ;; -esac - -if "$is_windows"; then - export MSYS_NO_PATHCONV=1 - export MSYS2_ARG_CONV_EXCL="*" -fi - -function set_up() { - cd ${WORKSPACE_DIR} - mkdir -p "foo" -} - -#### TESTS ############################################################# -function test_flag_enabled() { - cat > foo/BUILD < foo/foo.cc < "$TEST_log" || fail "Expected success" -} - -function test_failed_builds() { - cat > foo/BUILD < "$TEST_log" && fail "Expected failure" - exit_code="$?" - [[ "$exit_code" -eq 1 ]] || fail "Unexpected exit code: $exit_code" - expect_log "missing input file '//foo:missing.a'" - - bazel build --experimental_merged_skyframe_analysis_execution //foo:analysis_failure &> "$TEST_log" && fail "Expected failure" - exit_code="$?" - [[ "$exit_code" -eq 1 ]] || fail "Unexpected exit code: $exit_code" - expect_log "Analysis of target '//foo:analysis_failure' failed" - - bazel build --nokeep_going --experimental_merged_skyframe_analysis_execution //foo:analysis_failure //foo:execution_failure &> "$TEST_log" && fail "Expected failure" - exit_code="$?" - [[ "$exit_code" -eq 1 ]] || fail "Unexpected exit code: $exit_code" - # With --nokeep_going, technically nothing can be said about the message: whichever target fails first would abort the build. - - - bazel build --keep_going --experimental_merged_skyframe_analysis_execution //foo:analysis_failure //foo:execution_failure &> "$TEST_log" && fail "Expected failure" - exit_code="$?" - [[ "$exit_code" -eq 1 ]] || fail "Unexpected exit code: $exit_code" - expect_log "missing input file '//foo:missing.a'" - expect_log "Analysis of target '//foo:analysis_failure' failed" -} - -run_suite "Integration tests of ${PRODUCT_NAME} with merged Analysis & Execution phases of Skyframe."