| #!/bin/bash |
| # |
| # Copyright 2020 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. |
| # |
| # Test building targets that are declared as compatible only with certain |
| # platforms (see the "target_compatible_with" common build rule attribute). |
| |
| # --- 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; } |
| |
| # `uname` returns the current platform, e.g "MSYS_NT-10.0" or "Linux". |
| # `tr` converts all upper case letters to lower case. |
| # `case` matches the result if the `uname | tr` expression to string prefixes |
| # that use the same wildcards as names do in Bash, i.e. "msys*" matches strings |
| # starting with "msys", and "*" matches everything (it's the default case). |
| case "$(uname -s | tr [:upper:] [:lower:])" in |
| msys*) |
| # As of 2019-01-15, Bazel on Windows only supports MSYS Bash. |
| 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() { |
| mkdir -p target_skipping || fail "couldn't create directory" |
| cat > target_skipping/pass.sh <<'EOF' |
| #!/bin/bash |
| exit 0 |
| EOF |
| chmod +x target_skipping/pass.sh |
| |
| cat > target_skipping/fail.sh <<'EOF' |
| #!/bin/bash |
| exit 1 |
| EOF |
| chmod +x target_skipping/fail.sh |
| # Not using 'EOF' because injecting default_host_platform |
| cat > target_skipping/BUILD <<EOF |
| # We're not validating visibility here. Let everything access these targets. |
| package(default_visibility = ["//visibility:public"]) |
| |
| constraint_setting(name = "foo_version") |
| |
| constraint_value( |
| name = "foo1", |
| constraint_setting = ":foo_version", |
| ) |
| |
| constraint_value( |
| name = "foo2", |
| constraint_setting = ":foo_version", |
| ) |
| |
| constraint_value( |
| name = "foo3", |
| constraint_setting = ":foo_version", |
| ) |
| |
| constraint_setting(name = "bar_version") |
| |
| constraint_value( |
| name = "bar1", |
| constraint_setting = "bar_version", |
| ) |
| |
| constraint_value( |
| name = "bar2", |
| constraint_setting = "bar_version", |
| ) |
| |
| platform( |
| name = "foo1_bar1_platform", |
| parents = ["${default_host_platform}"], |
| constraint_values = [ |
| ":foo1", |
| ":bar1", |
| ], |
| ) |
| |
| platform( |
| name = "foo2_bar1_platform", |
| parents = ["${default_host_platform}"], |
| constraint_values = [ |
| ":foo2", |
| ":bar1", |
| ], |
| ) |
| |
| platform( |
| name = "foo1_bar2_platform", |
| parents = ["${default_host_platform}"], |
| constraint_values = [ |
| ":foo1", |
| ":bar2", |
| ], |
| ) |
| |
| platform( |
| name = "foo3_platform", |
| parents = ["${default_host_platform}"], |
| constraint_values = [ |
| ":foo3", |
| ], |
| ) |
| |
| platform( |
| name = "foo3_bar2_platform", |
| parents = ["${default_host_platform}"], |
| constraint_values = [ |
| ":foo3", |
| ":bar2", |
| ], |
| ) |
| |
| sh_test( |
| name = "pass_on_foo1", |
| srcs = ["pass.sh"], |
| target_compatible_with = [":foo1"], |
| ) |
| |
| sh_test( |
| name = "fail_on_foo2", |
| srcs = ["fail.sh"], |
| target_compatible_with = [":foo2"], |
| ) |
| |
| sh_test( |
| name = "pass_on_foo1_bar2", |
| srcs = ["pass.sh"], |
| target_compatible_with = [ |
| ":foo1", |
| ":bar2", |
| ], |
| ) |
| |
| sh_binary( |
| name = "some_foo3_target", |
| srcs = ["pass.sh"], |
| target_compatible_with = [ |
| ":foo3", |
| ], |
| ) |
| |
| # Use this to let us change select() statements from the command line. |
| config_setting( |
| name = "setting1", |
| define_values = { |
| "foo": "1", |
| }, |
| ) |
| EOF |
| } |
| |
| add_to_bazelrc "test --nocache_test_results" |
| add_to_bazelrc "build --incompatible_merge_genfiles_directory=true" |
| |
| function tear_down() { |
| bazel shutdown |
| } |
| |
| function set_up_custom_toolchain() { |
| mkdir -p target_skipping/custom_tools/ |
| cat > target_skipping/custom_tools/BUILD <<'EOF' |
| load(":toolchain.bzl", "custom_toolchain") |
| |
| package(default_visibility = ["//visibility:public"]) |
| |
| toolchain_type(name = "toolchain_type") |
| |
| custom_toolchain( |
| name = "toolchain", |
| compiler_path = "customc", |
| ) |
| |
| toolchain( |
| name = "custom_foo3_toolchain", |
| exec_compatible_with = [ |
| "//target_skipping:foo3", |
| ], |
| target_compatible_with = [ |
| "//target_skipping:foo3", |
| ], |
| toolchain = ":toolchain", |
| toolchain_type = ":toolchain_type", |
| ) |
| EOF |
| |
| cat > target_skipping/custom_tools/toolchain.bzl <<'EOF' |
| def _custom_binary_impl(ctx): |
| info = ctx.toolchains["//target_skipping/custom_tools:toolchain_type"].custom_info |
| out = ctx.actions.declare_file(ctx.label.name) |
| ctx.actions.write(out, "%s %s" % (info.compiler_path, ctx.file.src.short_path)) |
| |
| custom_binary = rule( |
| implementation = _custom_binary_impl, |
| attrs = { |
| "src": attr.label(allow_single_file=True), |
| }, |
| toolchains = ["//target_skipping/custom_tools:toolchain_type"], |
| ) |
| |
| CustomInfo = provider( |
| fields = { |
| "compiler_path": "The path to the compiler binary", |
| }, |
| ) |
| |
| def _custom_toolchain_impl(ctx): |
| return [platform_common.ToolchainInfo( |
| custom_info = CustomInfo( |
| compiler_path = ctx.attr.compiler_path, |
| ), |
| )] |
| |
| custom_toolchain = rule( |
| implementation = _custom_toolchain_impl, |
| attrs = { |
| "compiler_path": attr.string(), |
| }, |
| ) |
| |
| def _compiler_flag_impl(ctx): |
| toolchain = ctx.toolchains["//target_skipping/custom_tools:toolchain_type"].custom_info |
| return [config_common.FeatureFlagInfo(value = toolchain.compiler_path)] |
| |
| compiler_flag = rule( |
| implementation = _compiler_flag_impl, |
| toolchains = ["//target_skipping/custom_tools:toolchain_type"], |
| incompatible_use_toolchain_transition = True, |
| ) |
| EOF |
| } |
| |
| # Validates that we get a good error message when passing a config_setting into |
| # the target_compatible_with attribute. This is a regression test for |
| # https://github.com/bazelbuild/bazel/issues/13250. |
| function test_config_setting_in_target_compatible_with() { |
| cat >> target_skipping/BUILD <<'EOF' |
| config_setting( |
| name = "foo3_config_setting", |
| constraint_values = [":foo3"], |
| ) |
| |
| sh_binary( |
| name = "problematic_foo3_target", |
| srcs = ["pass.sh"], |
| target_compatible_with = [ |
| ":foo3_config_setting", |
| ], |
| ) |
| EOF |
| |
| cd target_skipping || fail "couldn't cd into workspace" |
| |
| bazel build \ |
| --show_result=10 \ |
| --host_platform=@//target_skipping:foo3_platform \ |
| --platforms=@//target_skipping:foo3_platform \ |
| ... &> "${TEST_log}" && fail "Bazel succeeded unexpectedly." |
| |
| expect_log "'//target_skipping:foo3_config_setting' does not have mandatory providers: 'ConstraintValueInfo'" |
| } |
| |
| # Validates that the console log provides useful information to the user for |
| # builds. |
| function test_console_log_for_builds() { |
| cd target_skipping || fail "couldn't cd into workspace" |
| |
| bazel build \ |
| --show_result=10 \ |
| --host_platform=@//target_skipping:foo3_platform \ |
| --platforms=@//target_skipping:foo3_platform \ |
| ... &> "${TEST_log}" || fail "Bazel failed the test." |
| |
| cp "${TEST_log}" "${TEST_UNDECLARED_OUTPUTS_DIR}"/ |
| |
| expect_log 'Target //target_skipping:some_foo3_target up-to-date' |
| expect_log 'Target //target_skipping:fail_on_foo2 was skipped' |
| expect_log 'Target //target_skipping:pass_on_foo1 was skipped' |
| expect_log 'Target //target_skipping:pass_on_foo1_bar2 was skipped' |
| expect_not_log 'Target //target_skipping:fail_on_foo2 failed to build' |
| expect_not_log 'Target //target_skipping:pass_on_foo1 failed to build' |
| expect_not_log 'Target //target_skipping:pass_on_foo1_bar2 failed to build' |
| expect_not_log 'Target //target_skipping:fail_on_foo2 up-to-date' |
| expect_not_log 'Target //target_skipping:pass_on_foo1 up-to-date' |
| expect_not_log 'Target //target_skipping:pass_on_foo1_bar2 up-to-date' |
| } |
| |
| # Validates that the console log provides useful information to the user for |
| # tests. |
| function test_console_log_for_tests() { |
| cd target_skipping || fail "couldn't cd into workspace" |
| |
| # Get repeatable results from this test. |
| bazel clean --expunge |
| |
| bazel test \ |
| --host_platform=@//target_skipping:foo1_bar1_platform \ |
| --platforms=@//target_skipping:foo1_bar1_platform \ |
| ... &> "${TEST_log}" || fail "Bazel failed unexpectedly." |
| expect_log 'Executed 1 out of 3 tests: 1 test passes and 2 were skipped' |
| expect_log '^//target_skipping:pass_on_foo1 * PASSED in' |
| expect_log '^//target_skipping:fail_on_foo2 * SKIPPED$' |
| expect_log '^//target_skipping:pass_on_foo1_bar2 * SKIPPED$' |
| |
| bazel test \ |
| --host_platform=@//target_skipping:foo2_bar1_platform \ |
| --platforms=@//target_skipping:foo2_bar1_platform \ |
| ... &> "${TEST_log}" && fail "Bazel passed unexpectedly." |
| expect_log 'Executed 1 out of 3 tests: 1 fails .* and 2 were skipped.' |
| expect_log '^//target_skipping:pass_on_foo1 * SKIPPED$' |
| expect_log '^//target_skipping:fail_on_foo2 * FAILED in' |
| expect_log '^//target_skipping:pass_on_foo1_bar2 * SKIPPED$' |
| |
| # Use :all for this one to validate similar behaviour. |
| bazel test \ |
| --host_platform=@//target_skipping:foo1_bar2_platform \ |
| --platforms=@//target_skipping:foo1_bar2_platform \ |
| :all &> "${TEST_log}" || fail "Bazel failed unexpectedly." |
| expect_log 'Executed 2 out of 3 tests: 2 tests pass and 1 was skipped' |
| expect_log '^//target_skipping:pass_on_foo1 * PASSED in' |
| expect_log '^//target_skipping:fail_on_foo2 * SKIPPED$' |
| expect_log '^//target_skipping:pass_on_foo1_bar2 * PASSED in' |
| } |
| |
| # Validates that filegroups and other rules that don't inherit from |
| # `NativeActionCreatingRule` can be marked with target_compatible_with. This is |
| # a regression test for https://github.com/bazelbuild/bazel/issues/12745. |
| function test_skipping_for_rules_that_dont_create_actions() { |
| # Create a fake shared library for cc_import. |
| echo > target_skipping/some_precompiled_library.so |
| |
| cat >> target_skipping/BUILD <<'EOF' |
| cc_import( |
| name = "some_precompiled_library", |
| shared_library = "some_precompiled_library.so", |
| target_compatible_with = [ |
| ":foo3", |
| ], |
| ) |
| |
| cc_binary( |
| name = "some_binary", |
| deps = [ |
| ":some_precompiled_library", |
| ], |
| ) |
| |
| filegroup( |
| name = "filegroup", |
| srcs = [ |
| "some_precompiled_library.so", |
| ], |
| target_compatible_with = [ |
| ":foo3", |
| ], |
| ) |
| EOF |
| |
| cd target_skipping || fail "couldn't cd into workspace" |
| |
| bazel build \ |
| --show_result=10 \ |
| --host_platform=@//target_skipping:foo1_bar1_platform \ |
| --platforms=@//target_skipping:foo1_bar1_platform \ |
| :all &> "${TEST_log}" || fail "Bazel failed unexpectedly." |
| expect_log 'Target //target_skipping:some_precompiled_library was skipped' |
| expect_log 'Target //target_skipping:some_binary was skipped' |
| expect_log 'Target //target_skipping:filegroup was skipped' |
| |
| bazel build \ |
| --show_result=10 \ |
| --host_platform=@//target_skipping:foo1_bar1_platform \ |
| --platforms=@//target_skipping:foo1_bar1_platform \ |
| :filegroup &> "${TEST_log}" && fail "Bazel passed unexpectedly." |
| expect_log 'Target //target_skipping:filegroup is incompatible and cannot be built' |
| } |
| |
| # Validates that incompatible target skipping errors behave nicely with |
| # --keep_going. In other words, even if there's an error in the target skipping |
| # (e.g. because the user explicitly requested an incompatible target) we still |
| # want Bazel to finish the rest of the build when --keep_going is specified. |
| function test_failure_on_incompatible_top_level_target() { |
| cd target_skipping || fail "couldn't cd into workspace" |
| |
| # Validate a variety of ways to refer to the same target. |
| local -r -a incompatible_targets=( |
| :pass_on_foo1_bar2 |
| //target_skipping:pass_on_foo1_bar2 |
| @//target_skipping:pass_on_foo1_bar2 |
| ) |
| |
| for incompatible_target in "${incompatible_targets[@]}"; do |
| echo "Testing ${incompatible_target}" |
| |
| bazel test \ |
| --show_result=10 \ |
| --host_platform=@//target_skipping:foo1_bar1_platform \ |
| --platforms=@//target_skipping:foo1_bar1_platform \ |
| --build_event_text_file="${TEST_log}".build.json \ |
| "${incompatible_target}" &> "${TEST_log}" \ |
| && fail "Bazel passed unexpectedly." |
| |
| expect_log 'ERROR:.* Target //target_skipping:pass_on_foo1_bar2 is incompatible and cannot be built' |
| expect_log '^ERROR: Build did NOT complete successfully' |
| |
| # Now look at the build event log. |
| mv "${TEST_log}".build.json "${TEST_log}" |
| |
| expect_log '^ name: "PARSING_FAILURE"$' |
| expect_log 'Target //target_skipping:pass_on_foo1_bar2 is incompatible and cannot be built.' |
| done |
| |
| # Run an additional (passing) test and make sure we still fail the build. |
| # This is intended to validate that --keep_going works as expected. |
| bazel test \ |
| --show_result=10 \ |
| --host_platform=@//target_skipping:foo1_bar1_platform \ |
| --platforms=@//target_skipping:foo1_bar1_platform \ |
| --keep_going \ |
| //target_skipping:pass_on_foo1_bar2 \ |
| //target_skipping:pass_on_foo1 &> "${TEST_log}" && fail "Bazel passed unexpectedly." |
| |
| expect_log '^//target_skipping:pass_on_foo1 * PASSED in' |
| expect_log '^ERROR: command succeeded, but not all targets were analyzed' |
| expect_log '^ERROR: Build did NOT complete successfully' |
| } |
| |
| # https://github.com/bazelbuild/bazel/issues/17561 regression test: incompatible |
| # target skipping doesn't crash with --auto_cpu_environment_group. |
| function test_failure_on_incompatible_top_level_target_and_auto_cpu_environment_group() { |
| cat >> target_skipping/BUILD <<EOF |
| sh_test( |
| name = "always_incompatible", |
| srcs = [":pass.sh"], |
| target_compatible_with = ["@platforms//:incompatible"], |
| ) |
| EOF |
| |
| mkdir -p buildenv/cpus |
| cat > buildenv/cpus/BUILD <<EOF |
| package(default_visibility = ["//visibility:public"]) |
| |
| environment(name = "foo_cpu") |
| environment_group( |
| name = "cpus", |
| defaults = [":foo_cpu"], |
| environments = [":foo_cpu"], |
| ) |
| EOF |
| |
| bazel build \ |
| --nobuild \ |
| --cpu=foo_cpu \ |
| --auto_cpu_environment_group=//buildenv/cpus:cpus \ |
| --build_event_text_file=$TEST_log \ |
| //target_skipping:all &> "${TEST_log}" \ |
| || fail "Bazel failed unexpectedly." |
| |
| expect_log 'Target //target_skipping:always_incompatible build was skipped' |
| } |
| |
| # Validates that incompatible target skipping works with top level targets when |
| # --skip_incompatible_explicit_targets is enabled. |
| function test_success_on_incompatible_top_level_target_with_skipping() { |
| cd target_skipping || fail "couldn't cd into workspace" |
| |
| # Validate a variety of ways to refer to the same target. |
| local -r -a incompatible_targets=( |
| :pass_on_foo1_bar2 |
| //target_skipping:pass_on_foo1_bar2 |
| @//target_skipping:pass_on_foo1_bar2 |
| ) |
| |
| for incompatible_target in "${incompatible_targets[@]}"; do |
| echo "Testing ${incompatible_target}" |
| |
| bazel test \ |
| --show_result=10 \ |
| --host_platform=@//target_skipping:foo1_bar1_platform \ |
| --platforms=@//target_skipping:foo1_bar1_platform \ |
| --build_event_text_file="${TEST_log}".build.json \ |
| --skip_incompatible_explicit_targets \ |
| "${incompatible_target}" &> "${TEST_log}" \ |
| || fail "Bazel failed unexpectedly." |
| |
| expect_log '^//target_skipping:pass_on_foo1_bar2 * SKIPPED$' |
| done |
| } |
| |
| # Crudely validates that the build event protocol contains useful information |
| # when targets are skipped due to incompatibilities. |
| function test_build_event_protocol() { |
| cd target_skipping || fail "couldn't cd into workspace" |
| |
| bazel test \ |
| --show_result=10 \ |
| --host_platform=@//target_skipping:foo1_bar1_platform \ |
| --build_event_text_file=$TEST_log \ |
| --platforms=@//target_skipping:foo1_bar1_platform \ |
| ... || fail "Bazel failed unexpectedly." |
| expect_not_log 'Target //target_skipping:pass_on_foo1 build was skipped\.' |
| expect_log_n 'reason: SKIPPED\>' 3 |
| expect_log 'Target //target_skipping:fail_on_foo2 build was skipped\.' |
| expect_log 'Target //target_skipping:pass_on_foo1_bar2 build was skipped\.' |
| } |
| |
| # Validates that incompatibilities are transitive. I.e. targets that depend on |
| # incompatible targets are themselves deemed incompatible and should therefore |
| # not be built. |
| function test_non_top_level_skipping() { |
| touch target_skipping/foo_test.sh |
| chmod +x target_skipping/foo_test.sh |
| |
| cat >> target_skipping/BUILD <<'EOF' |
| genrule( |
| name = "genrule_foo1", |
| target_compatible_with = [":foo1"], |
| outs = ["foo1.sh"], |
| cmd = "echo 'Should not be executed' &>2; exit 1", |
| ) |
| |
| sh_binary( |
| name = "sh_foo2", |
| srcs = ["foo1.sh"], |
| target_compatible_with = [":foo2"], |
| ) |
| |
| # Make sure that using an incompatible target in Make variable substitution |
| # doesn't produce an unexpected error. |
| sh_test( |
| name = "foo_test", |
| srcs = ["foo_test.sh"], |
| data = [":some_foo3_target"], |
| args = ["$(location :some_foo3_target)"], |
| ) |
| EOF |
| |
| cd target_skipping || fail "couldn't cd into workspace" |
| |
| bazel build \ |
| --show_result=10 \ |
| --host_platform=@//target_skipping:foo2_bar1_platform \ |
| --platforms=@//target_skipping:foo2_bar1_platform \ |
| //target_skipping:sh_foo2 &> "${TEST_log}" && fail "Bazel passed unexpectedly." |
| expect_log 'ERROR:.* Target //target_skipping:sh_foo2 is incompatible and cannot be built, but was explicitly requested' |
| expect_log 'ERROR: Build did NOT complete successfully' |
| |
| bazel build \ |
| --show_result=10 \ |
| --host_platform=@//target_skipping:foo2_bar1_platform \ |
| --platforms=@//target_skipping:foo2_bar1_platform \ |
| //target_skipping:foo_test &> "${TEST_log}" && fail "Bazel passed unexpectedly." |
| expect_log 'ERROR:.* Target //target_skipping:foo_test is incompatible and cannot be built, but was explicitly requested' |
| expect_log 'ERROR: Build did NOT complete successfully' |
| } |
| |
| # Validate that targets are skipped when the implementation is in Starlark |
| # instead of in Java. |
| function test_starlark_skipping() { |
| cat > target_skipping/rules.bzl <<'EOF' |
| def _echo_rule_impl(ctx): |
| ctx.actions.write(ctx.outputs.out, ctx.attr.text) |
| return [] |
| |
| _echo_rule = rule( |
| implementation = _echo_rule_impl, |
| attrs = { |
| "text": attr.string(), |
| "out": attr.output(), |
| }, |
| ) |
| |
| def echo_rule(name, **kwargs): |
| _echo_rule( |
| name = name, |
| out = name, |
| **kwargs |
| ) |
| EOF |
| |
| cat >> target_skipping/BUILD <<'EOF' |
| load("//target_skipping:rules.bzl", "echo_rule") |
| |
| echo_rule( |
| name = "hello_world", |
| text = "Hello World", |
| target_compatible_with = [ |
| "//target_skipping:foo1", |
| ], |
| ) |
| |
| sh_binary( |
| name = "hello_world_bin", |
| srcs = ["pass.sh"], |
| data = [":hello_world"], |
| ) |
| EOF |
| |
| cd target_skipping || fail "couldn't cd into workspace" |
| |
| bazel build \ |
| --show_result=10 \ |
| --host_platform=@//target_skipping:foo3_platform \ |
| --platforms=@//target_skipping:foo3_platform \ |
| //target_skipping:hello_world_bin &> "${TEST_log}" && fail "Bazel passed unexpectedly." |
| expect_log 'ERROR:.* Target //target_skipping:hello_world_bin is incompatible and cannot be built, but was explicitly requested' |
| expect_log 'ERROR: Build did NOT complete successfully' |
| } |
| |
| # Validates that rules with custom providers are skipped when incompatible. |
| # This is valuable because we use providers to convey incompatibility. |
| function test_dependencies_with_providers() { |
| cat > target_skipping/rules.bzl <<'EOF' |
| DummyProvider = provider() |
| |
| def _dummy_rule_impl(ctx): |
| return [DummyProvider()] |
| |
| dummy_rule = rule( |
| implementation = _dummy_rule_impl, |
| attrs = { |
| "deps": attr.label_list(providers=[DummyProvider]), |
| }, |
| ) |
| EOF |
| |
| cat >> target_skipping/BUILD <<'EOF' |
| load("//target_skipping:rules.bzl", "dummy_rule") |
| |
| dummy_rule( |
| name = "dummy1", |
| target_compatible_with = [ |
| "//target_skipping:foo1", |
| ], |
| ) |
| |
| dummy_rule( |
| name = "dummy2", |
| deps = [ |
| ":dummy1", |
| ], |
| ) |
| EOF |
| |
| cd target_skipping || fail "couldn't cd into workspace" |
| |
| pwd >&2 |
| bazel build \ |
| --show_result=10 \ |
| --host_platform=@//target_skipping:foo3_platform \ |
| --platforms=@//target_skipping:foo3_platform \ |
| //target_skipping/... &> "${TEST_log}" || fail "Bazel failed unexpectedly." |
| expect_log '^Target //target_skipping:dummy2 was skipped' |
| } |
| |
| function test_dependencies_with_extensions() { |
| cat > target_skipping/rules.bzl <<'EOF' |
| def _dummy_rule_impl(ctx): |
| out = ctx.actions.declare_file(ctx.attr.name + ".cc") |
| ctx.actions.write(out, "Dummy content") |
| return DefaultInfo(files = depset([out])) |
| |
| dummy_rule = rule( |
| implementation = _dummy_rule_impl, |
| ) |
| EOF |
| |
| cat >> target_skipping/BUILD <<'EOF' |
| load("//target_skipping:rules.bzl", "dummy_rule") |
| |
| # Generates a dummy.cc file. |
| dummy_rule( |
| name = "dummy_file", |
| target_compatible_with = [":foo1"], |
| ) |
| |
| cc_library( |
| name = "dummy_cc_lib", |
| srcs = [ |
| "dummy_file", |
| ], |
| ) |
| EOF |
| |
| cd target_skipping || fail "couldn't cd into workspace" |
| |
| pwd >&2 |
| bazel build \ |
| --show_result=10 \ |
| --host_platform=@//target_skipping:foo3_platform \ |
| --platforms=@//target_skipping:foo3_platform \ |
| //target_skipping/... &> "${TEST_log}" || fail "Bazel failed unexpectedly." |
| expect_log '^Target //target_skipping:dummy_cc_lib was skipped' |
| } |
| |
| # Validates the same thing as test_non_top_level_skipping, but with a cc_test |
| # and adding one more level of dependencies. |
| function test_cc_test() { |
| cat > target_skipping/generator_tool.cc <<'EOF' |
| #include <cstdio> |
| int main() { |
| printf("int main() { return 1; }\\n"); |
| return 0; |
| } |
| EOF |
| |
| cat >> target_skipping/BUILD <<'EOF' |
| cc_binary( |
| name = "generator_tool", |
| srcs = ["generator_tool.cc"], |
| target_compatible_with = [":foo1"], |
| ) |
| |
| genrule( |
| name = "generate_with_tool", |
| outs = ["generated_test.cc"], |
| cmd = "$(location :generator_tool) > $(OUTS)", |
| tools = [":generator_tool"], |
| ) |
| |
| cc_test( |
| name = "generated_test", |
| srcs = ["generated_test.cc"], |
| ) |
| EOF |
| |
| cd target_skipping || fail "couldn't cd into workspace" |
| |
| # Validate the generated file that makes up the test. |
| bazel test \ |
| --show_result=10 \ |
| --host_platform=@//target_skipping:foo2_bar1_platform \ |
| --platforms=@//target_skipping:foo2_bar1_platform \ |
| //target_skipping:generated_test.cc &> "${TEST_log}" && fail "Bazel passed unexpectedly." |
| expect_log "ERROR:.* Target //target_skipping:generated_test.cc is incompatible and cannot be built, but was explicitly requested" |
| |
| # Validate that we get the dependency chain printed out. |
| expect_log '^Dependency chain:$' |
| expect_log '^ //target_skipping:generate_with_tool (.*)$' |
| expect_log "^ //target_skipping:generator_tool (.*) <-- target platform (//target_skipping:foo2_bar1_platform) didn't satisfy constraint //target_skipping:foo1" |
| expect_log 'ERROR: Build did NOT complete successfully' |
| |
| # Validate the test. |
| bazel test \ |
| --show_result=10 \ |
| --host_platform=@//target_skipping:foo2_bar1_platform \ |
| --platforms=@//target_skipping:foo2_bar1_platform \ |
| //target_skipping:generated_test &> "${TEST_log}" && fail "Bazel passed unexpectedly." |
| expect_log 'ERROR:.* Target //target_skipping:generated_test is incompatible and cannot be built, but was explicitly requested' |
| |
| # Validate that we get the dependency chain printed out. |
| expect_log '^Dependency chain:$' |
| expect_log '^ //target_skipping:generated_test (.*)$' |
| expect_log '^ //target_skipping:generate_with_tool (.*)$' |
| expect_log "^ //target_skipping:generator_tool (.*) <-- target platform (//target_skipping:foo2_bar1_platform) didn't satisfy constraint //target_skipping:foo1" |
| expect_log 'ERROR: Build did NOT complete successfully' |
| } |
| |
| # Validates the same thing as test_cc_test, but with multiple violated |
| # constraints. |
| function test_cc_test_multiple_constraints() { |
| cat > target_skipping/generator_tool.cc <<'EOF' |
| #include <cstdio> |
| int main() { |
| printf("int main() { return 1; }\\n"); |
| return 0; |
| } |
| EOF |
| |
| cat >> target_skipping/BUILD <<'EOF' |
| cc_binary( |
| name = "generator_tool", |
| srcs = ["generator_tool.cc"], |
| target_compatible_with = [":foo1", ":bar2"], |
| ) |
| |
| genrule( |
| name = "generate_with_tool", |
| outs = ["generated_test.cc"], |
| cmd = "$(location :generator_tool) > $(OUTS)", |
| tools = [":generator_tool"], |
| ) |
| |
| cc_test( |
| name = "generated_test", |
| srcs = ["generated_test.cc"], |
| ) |
| EOF |
| |
| cd target_skipping || fail "couldn't cd into workspace" |
| |
| bazel test \ |
| --show_result=10 \ |
| --host_platform=@//target_skipping:foo2_bar1_platform \ |
| --platforms=@//target_skipping:foo2_bar1_platform \ |
| //target_skipping:generated_test &> "${TEST_log}" && fail "Bazel passed unexpectedly." |
| expect_log 'ERROR:.* Target //target_skipping:generated_test is incompatible and cannot be built, but was explicitly requested' |
| |
| # Validate that we get the dependency chain and constraints printed out. |
| expect_log '^Dependency chain:$' |
| expect_log '^ //target_skipping:generated_test (.*)$' |
| expect_log '^ //target_skipping:generate_with_tool (.*)$' |
| expect_log "^ //target_skipping:generator_tool (.*) <-- target platform (//target_skipping:foo2_bar1_platform) didn't satisfy constraints \[//target_skipping:bar2, //target_skipping:foo1\]" |
| expect_log 'ERROR: Build did NOT complete successfully' |
| } |
| |
| # Validates that we can express targets being compatible with A _or_ B. |
| function test_or_logic() { |
| cat >> target_skipping/BUILD <<'EOF' |
| sh_test( |
| name = "pass_on_foo1_or_foo2_but_not_on_foo3", |
| srcs = [":pass.sh"], |
| target_compatible_with = select({ |
| ":foo1": [], |
| ":foo2": [], |
| "//conditions:default": ["@platforms//:incompatible"], |
| }), |
| ) |
| EOF |
| |
| cd target_skipping || fail "couldn't cd into workspace" |
| |
| bazel test \ |
| --show_result=10 \ |
| --host_platform=@//target_skipping:foo1_bar1_platform \ |
| --platforms=@//target_skipping:foo1_bar1_platform \ |
| --nocache_test_results \ |
| //target_skipping:pass_on_foo1_or_foo2_but_not_on_foo3 &> "${TEST_log}" \ |
| || fail "Bazel failed unexpectedly." |
| expect_log '^//target_skipping:pass_on_foo1_or_foo2_but_not_on_foo3 * PASSED in' |
| |
| bazel test \ |
| --show_result=10 \ |
| --host_platform=@//target_skipping:foo2_bar1_platform \ |
| --platforms=@//target_skipping:foo2_bar1_platform \ |
| --nocache_test_results \ |
| //target_skipping:pass_on_foo1_or_foo2_but_not_on_foo3 &> "${TEST_log}" \ |
| || fail "Bazel failed unexpectedly." |
| expect_log '^//target_skipping:pass_on_foo1_or_foo2_but_not_on_foo3 * PASSED in' |
| |
| bazel test \ |
| --show_result=10 \ |
| --host_platform=@//target_skipping:foo3_platform \ |
| --platforms=@//target_skipping:foo3_platform \ |
| //target_skipping:pass_on_foo1_or_foo2_but_not_on_foo3 &> "${TEST_log}" \ |
| && fail "Bazel passed unexpectedly." |
| |
| expect_log 'ERROR:.* Target //target_skipping:pass_on_foo1_or_foo2_but_not_on_foo3 is incompatible and cannot be built, but was explicitly requested' |
| expect_log 'ERROR: Build did NOT complete successfully' |
| } |
| |
| # Regression test for b/277371822. |
| function test_missing_default() { |
| cat >> target_skipping/BUILD <<'EOF' |
| sh_test( |
| name = "pass_on_foo1_or_foo2_but_not_on_foo3", |
| srcs = [":pass.sh"], |
| target_compatible_with = select({ |
| ":foo1": [], |
| # No default branch. |
| }), |
| ) |
| EOF |
| |
| cd target_skipping || fail "couldn't cd into workspace" |
| |
| bazel test \ |
| --show_result=10 \ |
| --host_platform=@//target_skipping:foo3_platform \ |
| --platforms=@//target_skipping:foo3_platform \ |
| //target_skipping:pass_on_foo1_or_foo2_but_not_on_foo3 &> "${TEST_log}" \ |
| && fail "Bazel passed unexpectedly." |
| |
| expect_log 'ERROR:.*configurable attribute "target_compatible_with" in //target_skipping:pass_on_foo1_or_foo2_but_not_on_foo3' |
| expect_log 'ERROR: Build did NOT complete successfully' |
| expect_not_log 'FATAL: bazel crashed' |
| } |
| |
| # Validates that we can express targets being compatible with everything _but_ |
| # A and B. |
| function test_inverse_logic() { |
| setup_skylib_support |
| |
| # Not using 'EOF' because injecting skylib_package |
| cat >> target_skipping/BUILD <<EOF |
| load("${skylib_package}lib:selects.bzl", "selects") |
| |
| sh_test( |
| name = "pass_on_everything_but_foo1_and_foo2", |
| srcs = [":pass.sh"], |
| target_compatible_with = selects.with_or({ |
| (":foo1", ":foo2"): ["@platforms//:incompatible"], |
| "//conditions:default": [], |
| }), |
| ) |
| EOF |
| |
| cd target_skipping || fail "couldn't cd into workspace" |
| |
| # Try with :foo1. This should fail. |
| bazel test \ |
| --show_result=10 \ |
| --host_platform=@//target_skipping:foo1_bar1_platform \ |
| --platforms=@//target_skipping:foo1_bar1_platform \ |
| //target_skipping:pass_on_everything_but_foo1_and_foo2 &> "${TEST_log}" \ |
| && fail "Bazel passed unexpectedly." |
| expect_log 'ERROR:.* Target //target_skipping:pass_on_everything_but_foo1_and_foo2 is incompatible and cannot be built, but was explicitly requested' |
| expect_log 'ERROR: Build did NOT complete successfully' |
| |
| # Try with :foo2. This should fail. |
| bazel test \ |
| --show_result=10 \ |
| --host_platform=@//target_skipping:foo2_bar1_platform \ |
| --platforms=@//target_skipping:foo2_bar1_platform \ |
| //target_skipping:pass_on_everything_but_foo1_and_foo2 &> "${TEST_log}" \ |
| && fail "Bazel passed unexpectedly." |
| expect_log 'ERROR:.* Target //target_skipping:pass_on_everything_but_foo1_and_foo2 is incompatible and cannot be built, but was explicitly requested' |
| expect_log 'ERROR: Build did NOT complete successfully' |
| |
| # Now with :foo3. This should pass. |
| bazel test \ |
| --show_result=10 \ |
| --host_platform=@//target_skipping:foo3_platform \ |
| --platforms=@//target_skipping:foo3_platform \ |
| --nocache_test_results \ |
| //target_skipping:pass_on_everything_but_foo1_and_foo2 &> "${TEST_log}" \ |
| || fail "Bazel failed unexpectedly." |
| expect_log '^//target_skipping:pass_on_everything_but_foo1_and_foo2 * PASSED in' |
| } |
| |
| # Validates that we can reference the same incompatible constraint in several, |
| # composed select() statements. This is useful for expressing compatibility for |
| # orthogonal constraints. It's also useful when a macro author wants to express |
| # incompatibility while also honouring the user-defined incompatibility. |
| function test_composition() { |
| # The first select() statement might come from a macro. The second might come |
| # from the user who's calling that macro. |
| cat >> target_skipping/BUILD <<EOF |
| sh_test( |
| name = "pass_on_foo3_and_bar2", |
| srcs = [":pass.sh"], |
| target_compatible_with = select({ |
| ":foo3": [], |
| "//conditions:default": ["@platforms//:incompatible"], |
| }) + select({ |
| ":bar2": [], |
| "//conditions:default": ["@platforms//:incompatible"], |
| }), |
| ) |
| EOF |
| |
| cd target_skipping || fail "couldn't cd into workspace" |
| |
| bazel test \ |
| --show_result=10 \ |
| --host_platform=@//target_skipping:foo3_bar2_platform \ |
| --platforms=@//target_skipping:foo3_bar2_platform \ |
| --nocache_test_results \ |
| //target_skipping:pass_on_foo3_and_bar2 &> "${TEST_log}" \ |
| || fail "Bazel failed unexpectedly." |
| expect_log '^//target_skipping:pass_on_foo3_and_bar2 * PASSED in' |
| |
| # Validate that we get an error about the target being incompatible. Make |
| # sure that the ":incompatible" constraint is only listed once even though |
| # it appears twice in the configured "target_compatible_with" attribute. |
| bazel test \ |
| --show_result=10 \ |
| --host_platform=@//target_skipping:foo1_bar1_platform \ |
| --platforms=@//target_skipping:foo1_bar1_platform \ |
| //target_skipping:pass_on_foo3_and_bar2 &> "${TEST_log}" \ |
| && fail "Bazel passed unexpectedly." |
| |
| expect_log 'ERROR:.* Target //target_skipping:pass_on_foo3_and_bar2 is incompatible and cannot be built, but was explicitly requested' |
| expect_log "^ //target_skipping:pass_on_foo3_and_bar2 (.*) <-- target platform (//target_skipping:foo1_bar1_platform) didn't satisfy constraint @platforms//:incompatible$" |
| expect_log 'ERROR: Build did NOT complete successfully' |
| } |
| |
| function test_incompatible_with_aliased_constraint() { |
| cat >> target_skipping/BUILD <<'EOF' |
| alias( |
| name = "also_foo3", |
| actual = ":foo3", |
| ) |
| |
| alias( |
| name = "again_foo3", |
| actual = ":foo3", |
| ) |
| |
| cc_library( |
| name = "some_library", |
| target_compatible_with = select({ |
| ":also_foo3": [":again_foo3"], |
| "//conditions:default": ["@platforms//:incompatible"], |
| }), |
| ) |
| EOF |
| |
| cd target_skipping || fail "couldn't cd into workspace" |
| |
| bazel build \ |
| --show_result=10 \ |
| --host_platform=@//target_skipping:foo3_platform \ |
| --platforms=@//target_skipping:foo3_platform \ |
| //target_skipping/... &> "${TEST_log}" \ |
| || fail "Bazel build failed unexpectedly." |
| expect_log 'Target //target_skipping:some_library up-to-date' |
| } |
| |
| function test_incompatible_with_aliased_target() { |
| cat >> target_skipping/BUILD <<'EOF' |
| alias( |
| name = "also_some_foo3_target", |
| actual = ":some_foo3_target", |
| ) |
| EOF |
| |
| # Try with :foo1. This should fail. |
| bazel test \ |
| --show_result=10 \ |
| --host_platform=@//target_skipping:foo1_bar1_platform \ |
| --platforms=@//target_skipping:foo1_bar1_platform \ |
| //target_skipping:also_some_foo3_target &> "${TEST_log}" \ |
| && fail "Bazel passed unexpectedly." |
| expect_log 'ERROR:.* Target //target_skipping:also_some_foo3_target is incompatible and cannot be built, but was explicitly requested' |
| expect_log 'ERROR: Build did NOT complete successfully' |
| } |
| |
| # Validate what happens when setting `target_compatible_with` directly on an |
| # alias(). This is a regression test for |
| # https://github.com/bazelbuild/bazel/issues/17663. |
| function test_alias_incompatibility() { |
| cat >> target_skipping/BUILD <<'EOF' |
| filegroup( |
| name = "test_cc_filegroup", |
| srcs = ["test.cc"], |
| ) |
| |
| alias( |
| name = "test_cc_filegroup_alias", |
| actual = ":test_cc_filegroup", |
| target_compatible_with = [":foo3"], |
| ) |
| |
| cc_library( |
| name = "test_cc", |
| srcs = [":test_cc_filegroup_alias"], |
| ) |
| EOF |
| |
| echo > target_skipping/test.cc |
| |
| cd target_skipping || fail "couldn't cd into workspace" |
| bazel build \ |
| --show_result=10 \ |
| --host_platform=@//target_skipping:foo1_bar1_platform \ |
| --platforms=@//target_skipping:foo1_bar1_platform \ |
| //target_skipping:test_cc &> "${TEST_log}" \ |
| && fail "Bazel passed unexpectedly" |
| expect_log_once 'ERROR:.* Target //target_skipping:test_cc is incompatible and cannot be built, but was explicitly requested.' |
| } |
| |
| # Validate that an incompatible target with a toolchain not available for the |
| # current platform will not cause an analysis error. This is a regression test |
| # for https://github.com/bazelbuild/bazel/issues/12897. |
| function test_incompatible_with_missing_toolchain() { |
| set_up_custom_toolchain |
| |
| cat >> target_skipping/BUILD <<'EOF' |
| load( |
| "//target_skipping/custom_tools:toolchain.bzl", |
| "compiler_flag", |
| "custom_binary", |
| ) |
| |
| objc_library( |
| name = "objc", |
| target_compatible_with = select({ |
| ":setting1": ["//target_skipping:foo1"], |
| "//conditions:default": ["//target_skipping:foo2"], |
| }), |
| ) |
| |
| custom_binary( |
| name = "custom1", |
| src = "custom.txt", |
| target_compatible_with = ["//target_skipping:foo1"], |
| ) |
| |
| compiler_flag(name = "compiler_flag") |
| |
| config_setting( |
| name = "using_custom_toolchain", |
| flag_values = { |
| ":compiler_flag": "customc", |
| }, |
| ) |
| |
| custom_binary( |
| name = "custom2", |
| src = "custom.txt", |
| target_compatible_with = select({ |
| ":using_custom_toolchain": ["@platforms//:incompatible"], |
| "//conditions:default": [], |
| }), |
| ) |
| EOF |
| |
| cat > target_skipping/custom.txt <<EOF |
| This is a custom dummy file. |
| EOF |
| |
| cd target_skipping || fail "couldn't cd into workspace" |
| |
| bazel build --define=foo=1 \ |
| --show_result=10 \ |
| --extra_toolchains=//target_skipping/custom_tools:custom_foo3_toolchain \ |
| --host_platform=@//target_skipping:foo3_platform \ |
| --platforms=@//target_skipping:foo3_platform \ |
| //target_skipping/... &> "${TEST_log}" \ |
| || fail "Bazel build failed unexpectedly." |
| expect_log 'Target //target_skipping:objc was skipped' |
| expect_log 'Target //target_skipping:custom1 was skipped' |
| expect_log 'Target //target_skipping:custom2 was skipped' |
| } |
| |
| # Validates that if a target is "directly incompatible" then its dependencies |
| # are not evaluated. I.e. there should be no need to guard the dependencies |
| # with a select() statement. |
| function test_invalid_deps_are_ignored_when_incompatible() { |
| cat >> target_skipping/BUILD <<'EOF' |
| cc_binary( |
| name = "incompatible_tool", |
| deps = [ |
| "//nonexistent_dep", |
| ], |
| target_compatible_with = [ |
| ":foo1", |
| ], |
| ) |
| EOF |
| |
| cd target_skipping || fail "couldn't cd into workspace" |
| |
| bazel build \ |
| --show_result=10 \ |
| --host_platform=@//target_skipping:foo3_platform \ |
| --platforms=@//target_skipping:foo3_platform \ |
| //target_skipping/... &> "${TEST_log}" \ |
| || fail "Bazel build failed unexpectedly." |
| expect_log 'Target //target_skipping:incompatible_tool was skipped' |
| } |
| |
| # Validates that a tool compatible with the host platform, but incompatible |
| # with the target platform can still be used as a host tool. |
| function test_host_tool() { |
| # Create an arbitrary host tool. |
| cat > target_skipping/host_tool.cc <<'EOF' |
| #include <cstdio> |
| int main() { |
| printf("Hello World\\n"); |
| return 0; |
| } |
| EOF |
| |
| cat >> target_skipping/BUILD <<'EOF' |
| cc_binary( |
| name = "host_tool", |
| srcs = ["host_tool.cc"], |
| target_compatible_with = [ |
| ":foo1", |
| ], |
| ) |
| |
| genrule( |
| name = "use_host_tool", |
| outs = ["host_tool_message.txt"], |
| cmd = "$(location :host_tool) >> $(OUTS)", |
| tools = [":host_tool"], |
| target_compatible_with = [ |
| ":foo2", |
| ], |
| ) |
| EOF |
| |
| cd target_skipping || fail "couldn't cd into workspace" |
| |
| # Run with :foo1 in the host platform, but with :foo2 in the target platform. |
| # Building the host tool should fail because it's incompatible with the |
| # target platform. |
| bazel build --show_result=10 \ |
| --host_platform=@//target_skipping:foo1_bar1_platform \ |
| --platforms=@//target_skipping:foo2_bar1_platform \ |
| //target_skipping:host_tool &> "${TEST_log}" && fail "Bazel passed unexpectedly." |
| expect_log 'ERROR:.* Target //target_skipping:host_tool is incompatible and cannot be built, but was explicitly requested' |
| expect_log 'ERROR: Build did NOT complete successfully' |
| |
| # Run with :foo1 in the host platform, but with :foo2 in the target platform. |
| # This should work fine because we're not asking for any constraints to be |
| # violated. |
| bazel build --host_platform=@//target_skipping:foo1_bar2_platform \ |
| --platforms=@//target_skipping:foo2_bar1_platform \ |
| //target_skipping:host_tool_message.txt &> "${TEST_log}" \ |
| || fail "Bazel failed unexpectedly." |
| expect_log " ${PRODUCT_NAME}-bin/target_skipping/host_tool_message.txt$" |
| expect_log ' Build completed successfully, ' |
| |
| # Make sure that the contents of the file are what we expect. |
| cp ../${PRODUCT_NAME}-bin/target_skipping/host_tool_message.txt "${TEST_log}" |
| expect_log 'Hello World' |
| } |
| |
| # Validates that we successfully skip analysistest rule targets when they |
| # depend on incompatible targets. |
| function test_analysistest() { |
| setup_skylib_support |
| |
| # Not using 'EOF' because injecting skylib_package |
| cat > target_skipping/analysistest.bzl <<EOF |
| load("${skylib_package}lib:unittest.bzl", "analysistest") |
| |
| def _analysistest_test_impl(ctx): |
| env = analysistest.begin(ctx) |
| print("Running the test") |
| return analysistest.end(env) |
| |
| analysistest_test = analysistest.make(_analysistest_test_impl) |
| EOF |
| |
| cat >> target_skipping/BUILD <<'EOF' |
| load(":analysistest.bzl", "analysistest_test") |
| |
| analysistest_test( |
| name = "foo3_analysistest_test", |
| target_under_test = ":some_foo3_target", |
| ) |
| EOF |
| |
| cd target_skipping || fail "couldn't cd into workspace" |
| |
| bazel test --show_result=10 \ |
| --host_platform=@//target_skipping:foo3_platform \ |
| --platforms=@//target_skipping:foo3_platform \ |
| //target_skipping:foo3_analysistest_test &> "${TEST_log}" \ |
| || fail "Bazel failed unexpectedly." |
| expect_log '^//target_skipping:foo3_analysistest_test * PASSED in' |
| |
| bazel test --show_result=10 \ |
| --host_platform=@//target_skipping:foo1_bar1_platform \ |
| --platforms=@//target_skipping:foo1_bar1_platform \ |
| //target_skipping:all &> "${TEST_log}" \ |
| || fail "Bazel failed unexpectedly." |
| expect_log '^Target //target_skipping:foo3_analysistest_test was skipped' |
| } |
| |
| function write_query_test_targets() { |
| cat >> target_skipping/BUILD <<'EOF' |
| genrule( |
| name = "genrule_foo1", |
| target_compatible_with = [":foo1"], |
| outs = ["foo1.sh"], |
| cmd = "echo 'exit 0' > $(OUTS)", |
| ) |
| |
| sh_binary( |
| name = "sh_foo1", |
| srcs = ["foo1.sh"], |
| ) |
| EOF |
| } |
| |
| function test_query() { |
| write_query_test_targets |
| cd target_skipping || fail "couldn't cd into workspace" |
| |
| bazel query \ |
| 'deps(//target_skipping:sh_foo1)' &> "${TEST_log}" \ |
| || fail "Bazel query failed unexpectedly." |
| expect_log '^//target_skipping:sh_foo1' |
| expect_log '^//target_skipping:genrule_foo1' |
| } |
| |
| # Regression test for http://b/189071321: --notool_deps should exclude constraints. |
| function test_query_no_tools() { |
| write_query_test_targets |
| cd target_skipping || fail "couldn't cd into workspace" |
| |
| bazel query \ |
| --notool_deps \ |
| 'deps(//target_skipping:sh_foo1)' &> "${TEST_log}" \ |
| || fail "Bazel query failed unexpectedly." |
| |
| if "$is_windows"; then |
| sed -i 's/\r//g' "${TEST_log}" |
| fi |
| |
| expect_log '^//target_skipping:sh_foo1$' |
| expect_log '^//target_skipping:genrule_foo1$' |
| expect_not_log '^//target_skipping:foo1$' |
| } |
| |
| # Run a cquery on a target that is compatible. This should pass. |
| function test_cquery_compatible_target() { |
| write_query_test_targets |
| cd target_skipping || fail "couldn't cd into workspace" |
| |
| bazel cquery \ |
| --host_platform=@//target_skipping:foo3_platform \ |
| --platforms=@//target_skipping:foo3_platform \ |
| 'deps(//target_skipping:some_foo3_target)' &> "${TEST_log}" \ |
| || fail "Bazel cquery failed unexpectedly." |
| } |
| |
| # Run a cquery with a glob. This should only pick up compatible targets and |
| # should therefore pass. |
| function test_cquery_with_glob() { |
| write_query_test_targets |
| cd target_skipping || fail "couldn't cd into workspace" |
| |
| bazel cquery \ |
| --host_platform=@//target_skipping:foo3_platform \ |
| --platforms=@//target_skipping:foo3_platform \ |
| 'deps(//target_skipping/...)' &> "${TEST_log}" \ |
| || fail "Bazel cquery failed unexpectedly." |
| expect_log '^//target_skipping:some_foo3_target ' |
| expect_log '^//target_skipping:sh_foo1 ' |
| expect_log '^//target_skipping:genrule_foo1 ' |
| } |
| |
| # Run a cquery on an incompatible target. This should also pass. Incompatibility |
| # is more important for builds, where users want meaningful output. For queries, |
| # understanding target and dependency relationships is more important than |
| # erroring on unbuildable targets. |
| function test_cquery_incompatible_target() { |
| mkdir -p target_skipping |
| cat >> target_skipping/BUILD <<'EOF' |
| sh_test( |
| name = "depender", |
| srcs = ["depender.sh"], |
| data = [":never_compatible"], |
| target_compatible_with = [":foo3"], |
| ) |
| sh_binary( |
| name = "never_compatible", |
| srcs = [":never_used.sh"], |
| target_compatible_with = ["@platforms//:incompatible"], |
| ) |
| EOF |
| |
| bazel cquery \ |
| --platforms=@//target_skipping:foo3_platform \ |
| 'somepath(//target_skipping:depender, //target_skipping:never_compatible)' \ |
| &> "${TEST_log}" \ |
| || fail "Bazel cquery failed unexpectedly." |
| expect_log 'INFO: Found 2 targets' |
| expect_log '//target_skipping:depender (.*)' |
| expect_log "//target_skipping:never_compatible (.*)" |
| } |
| |
| # Runs a cquery and makes sure that we can properly distinguish between |
| # incompatible targets and compatible targets. |
| function test_cquery_with_starlark_formatting() { |
| cat > target_skipping/compatibility.cquery <<'EOF' |
| def format(target): |
| if "IncompatiblePlatformProvider" in providers(target): |
| result = "incompatible" |
| else: |
| result = "compatible" |
| |
| return "%s is %s" % (target.label, result) |
| EOF |
| |
| cd target_skipping || fail "couldn't cd into workspace" |
| |
| bazel cquery \ |
| --host_platform=//target_skipping:foo1_bar1_platform \ |
| --platforms=//target_skipping:foo1_bar1_platform \ |
| :all \ |
| --output=starlark --starlark:file=target_skipping/compatibility.cquery \ |
| &> "${TEST_log}" |
| |
| expect_log '^@//target_skipping:pass_on_foo1 is compatible$' |
| expect_log '^@//target_skipping:fail_on_foo2 is incompatible$' |
| expect_log '^@//target_skipping:some_foo3_target is incompatible$' |
| |
| bazel cquery \ |
| --host_platform=//target_skipping:foo3_platform \ |
| --platforms=//target_skipping:foo3_platform \ |
| :all \ |
| --output=starlark --starlark:file=target_skipping/compatibility.cquery \ |
| &> "${TEST_log}" |
| |
| expect_log '^@//target_skipping:pass_on_foo1 is incompatible$' |
| expect_log '^@//target_skipping:fail_on_foo2 is incompatible$' |
| expect_log '^@//target_skipping:some_foo3_target is compatible$' |
| } |
| |
| # Run an aquery on a target that is compatible. This should pass. |
| function test_aquery_compatible_target() { |
| write_query_test_targets |
| cd target_skipping || fail "couldn't cd into workspace" |
| |
| bazel aquery \ |
| --host_platform=@//target_skipping:foo3_platform \ |
| --platforms=@//target_skipping:foo3_platform \ |
| '//target_skipping:some_foo3_target' &> "${TEST_log}" \ |
| || fail "Bazel aquery failed unexpectedly." |
| } |
| |
| # Run an aquery with a glob. This should only pick up compatible targets and |
| # should therefore pass. |
| function test_aquery_with_glob() { |
| write_query_test_targets |
| cd target_skipping || fail "couldn't cd into workspace" |
| |
| bazel aquery \ |
| --host_platform=@//target_skipping:foo3_platform \ |
| --platforms=@//target_skipping:foo3_platform \ |
| '//target_skipping/...' &> "${TEST_log}" \ |
| || fail "Bazel aquery failed unexpectedly." |
| } |
| |
| # Run an aquery on an incompatible target. This should fail. |
| function test_aquery_incompatible_target() { |
| write_query_test_targets |
| cd target_skipping || fail "couldn't cd into workspace" |
| |
| bazel aquery \ |
| --host_platform=@//target_skipping:foo3_platform \ |
| --platforms=@//target_skipping:foo3_platform \ |
| '//target_skipping:sh_foo1' &> "${TEST_log}" \ |
| && fail "Bazel aquery passed unexpectedly." |
| expect_log_once 'Target //target_skipping:sh_foo1 is incompatible and cannot be built, but was explicitly requested' |
| expect_log_once "target platform (//target_skipping:foo3_platform) didn't satisfy constraint //target_skipping:foo1" |
| } |
| |
| # Use aspects to interact with incompatible targets and validate the behaviour. |
| function test_aspect_skipping() { |
| cat >> target_skipping/BUILD <<'EOF' |
| load(":defs.bzl", "basic_rule", "rule_with_aspect") |
| |
| # This target is compatible with all platforms and configurations. This target |
| # exists to validate the behaviour of aspects running against incompatible |
| # targets. The expectation is that the aspect should _not_ propagate to this |
| # compatible target from an incompatible target. I.e. an aspect should _not_ |
| # evaluate this target if "basic_foo3_target" is incompatible. |
| basic_rule( |
| name = "basic_universal_target", |
| ) |
| # An alias to validate that incompatible target skipping works as expected with |
| # aliases and aspects. |
| alias( |
| name = "aliased_basic_universal_target", |
| actual = ":basic_universal_target", |
| ) |
| basic_rule( |
| name = "basic_foo3_target", |
| deps = [ |
| ":aliased_basic_universal_target", |
| ], |
| target_compatible_with = [ |
| ":foo3", |
| ], |
| ) |
| # This target is only compatible when "basic_foo3_target" is compatible. This |
| # target exists to validate the behaviour of aspects running against |
| # incompatible targets. The expectation is that the aspect should _not_ |
| # evaluate this target when "basic_foo3_target" is incompatible. |
| basic_rule( |
| name = "other_basic_target", |
| deps = [ |
| ":basic_foo3_target", |
| ], |
| ) |
| alias( |
| name = "aliased_other_basic_target", |
| actual = ":other_basic_target", |
| ) |
| rule_with_aspect( |
| name = "inspected_foo3_target", |
| inspect = ":aliased_other_basic_target", |
| ) |
| basic_rule( |
| name = "previously_inspected_basic_target", |
| deps = [ |
| ":inspected_foo3_target", |
| ], |
| ) |
| rule_with_aspect( |
| name = "twice_inspected_foo3_target", |
| inspect = ":previously_inspected_basic_target", |
| ) |
| genrule( |
| name = "generated_file", |
| outs = ["generated_file.txt"], |
| cmd = "echo '' > $(OUTS)", |
| target_compatible_with = [ |
| ":foo1", |
| ], |
| ) |
| rule_with_aspect( |
| name = "inspected_generated_file", |
| inspect = ":generated_file", |
| ) |
| EOF |
| cat > target_skipping/defs.bzl <<'EOF' |
| BasicProvider = provider() |
| def _basic_rule_impl(ctx): |
| return [DefaultInfo(), BasicProvider()] |
| basic_rule = rule( |
| implementation = _basic_rule_impl, |
| attrs = { |
| "deps": attr.label_list( |
| providers = [BasicProvider], |
| ), |
| }, |
| ) |
| def _inspecting_aspect_impl(target, ctx): |
| print("Running aspect on " + str(target)) |
| return [] |
| _inspecting_aspect = aspect( |
| implementation = _inspecting_aspect_impl, |
| attr_aspects = ["deps"], |
| ) |
| def _rule_with_aspect_impl(ctx): |
| out = ctx.actions.declare_file(ctx.label.name) |
| ctx.actions.write(out, "") |
| return [ |
| DefaultInfo(files=depset([out])), |
| BasicProvider(), |
| ] |
| rule_with_aspect = rule( |
| implementation = _rule_with_aspect_impl, |
| attrs = { |
| "inspect": attr.label( |
| aspects = [_inspecting_aspect], |
| ), |
| }, |
| ) |
| EOF |
| cd target_skipping || fail "couldn't cd into workspace" |
| local debug_message1="Running aspect on <target //target_skipping:basic_universal_target>" |
| local debug_message2="Running aspect on <target //target_skipping:basic_foo3_target>" |
| local debug_message3="Running aspect on <target //target_skipping:other_basic_target>" |
| local debug_message4="Running aspect on <target //target_skipping:previously_inspected_basic_target>" |
| local debug_message5="Running aspect on <target //target_skipping:generated_file>" |
| # Validate that aspects run against compatible targets. |
| bazel build \ |
| --show_result=10 \ |
| --host_platform=@//target_skipping:foo3_platform \ |
| --platforms=@//target_skipping:foo3_platform \ |
| //target_skipping:all &> "${TEST_log}" \ |
| || fail "Bazel failed unexpectedly." |
| expect_log "${debug_message1}" |
| expect_log "${debug_message2}" |
| expect_log "${debug_message3}" |
| expect_log "${debug_message4}" |
| expect_not_log "${debug_message5}" |
| # Invert the compatibility and validate that aspects run on the other targets |
| # now. |
| bazel build \ |
| --show_result=10 \ |
| --host_platform=@//target_skipping:foo1_bar1_platform \ |
| --platforms=@//target_skipping:foo1_bar1_platform \ |
| //target_skipping:all &> "${TEST_log}" \ |
| || fail "Bazel failed unexpectedly." |
| expect_not_log "${debug_message1}" |
| expect_not_log "${debug_message2}" |
| expect_not_log "${debug_message3}" |
| expect_not_log "${debug_message4}" |
| expect_log "${debug_message5}" |
| # Validate that explicitly trying to build a target with an aspect against an |
| # incompatible target produces the normal error message. |
| bazel build \ |
| --show_result=10 \ |
| --host_platform=@//target_skipping:foo1_bar1_platform \ |
| --platforms=@//target_skipping:foo1_bar1_platform \ |
| //target_skipping:twice_inspected_foo3_target &> "${TEST_log}" \ |
| && fail "Bazel passed unexpectedly." |
| expect_log_once 'ERROR:.* Target //target_skipping:twice_inspected_foo3_target is incompatible and cannot be built, but was explicitly requested.' |
| expect_log_once '^Dependency chain:$' |
| expect_log_once '^ //target_skipping:twice_inspected_foo3_target ' |
| expect_log_once '^ //target_skipping:previously_inspected_basic_target ' |
| expect_log_once '^ //target_skipping:inspected_foo3_target ' |
| expect_log_once '^ //target_skipping:aliased_other_basic_target ' |
| expect_log_once '^ //target_skipping:other_basic_target ' |
| expect_log_once " //target_skipping:basic_foo3_target .* <-- target platform (//target_skipping:foo1_bar1_platform) didn't satisfy constraint //target_skipping:foo3$" |
| expect_log 'ERROR: Build did NOT complete successfully' |
| expect_not_log "${debug_message1}" |
| expect_not_log "${debug_message2}" |
| expect_not_log "${debug_message3}" |
| expect_not_log "${debug_message4}" |
| expect_not_log "${debug_message5}" |
| } |
| |
| function test_skipping_with_missing_toolchain() { |
| mkdir -p missing_toolchain |
| |
| cat > missing_toolchain/BUILD <<'EOF' |
| load(":rule.bzl", "my_rule") |
| |
| toolchain_type(name = "my_toolchain_type") |
| |
| my_rule( |
| name = "my_rule", |
| target_compatible_with = ["@platforms//:incompatible"], |
| ) |
| EOF |
| |
| cat > missing_toolchain/rule.bzl <<'EOF' |
| def _my_rule_impl(ctx): |
| pass |
| |
| my_rule = rule( |
| _my_rule_impl, |
| toolchains = ["//missing_toolchain:my_toolchain_type"], |
| ) |
| EOF |
| |
| bazel build --show_result=10 //missing_toolchain:all &> "${TEST_log}" \ |
| || fail "Bazel failed unexpectedly." |
| expect_log "Target //missing_toolchain:my_rule was skipped" |
| } |
| |
| run_suite "target_compatible_with tests" |