blob: 250cf4fa74599b912ce63f880107f46e4d89cca9 [file] [log] [blame]
#!/bin/bash
#
# Copyright 2017 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.
#
# configured_query_test.sh: integration tests for bazel configured query.
# This tests the command line ui of configured query while
# ConfiguredTargetQueryTest tests its internal functionality.
# --- begin runfiles.bash initialization ---
# Copy-pasted from Bazel's Bash runfiles library (tools/bash/runfiles/runfiles.bash).
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
add_to_bazelrc "build --package_path=%workspace%"
#### TESTS #############################################################
function test_basic_query() {
local -r pkg=$FUNCNAME
mkdir -p $pkg
cat > $pkg/BUILD <<'EOF'
sh_library(name='maple', deps=[':japanese'])
sh_library(name='japanese')
EOF
bazel cquery "deps(//$pkg:maple)" > output 2>"$TEST_log" || fail "Expected success"
assert_contains "//$pkg:maple" output
assert_contains "//$pkg:japanese" output
}
function test_basic_query_output_textproto() {
local -r pkg=$FUNCNAME
mkdir -p $pkg
cat > $pkg/BUILD <<'EOF'
sh_library(name='maple', deps=[':japanese'])
sh_library(name='japanese')
EOF
bazel cquery --output=textproto "deps(//$pkg:maple)" > output 2>"$TEST_log" || fail "Expected success"
assert_contains "name: \"//$pkg:maple\"" output
assert_contains "name: \"//$pkg:japanese\"" output
}
function test_basic_query_output_labelkind() {
local -r pkg=$FUNCNAME
mkdir -p $pkg
cat > $pkg/BUILD <<'EOF'
sh_library(name='maple', data=[':japanese'])
cc_binary(name='japanese', srcs = ['japanese.cc'])
EOF
bazel cquery --output=label_kind "deps(//$pkg:maple)" > output 2>"$TEST_log" || fail "Expected success"
assert_contains "sh_library rule //$pkg:maple" output
assert_contains "cc_binary rule //$pkg:japanese" output
assert_contains "source file //$pkg:japanese.cc" output
}
function test_config_checksum_determinism() {
local -r pkg=$FUNCNAME
mkdir -p $pkg
cat > $pkg/BUILD <<'EOF'
sh_library(name = 'lib')
EOF
bazel cquery "$pkg:lib" > out1 2>"$TEST_log" || fail "Expected success"
bazel shutdown >& "$TEST_log" || fail "Failed to shutdown"
bazel cquery "$pkg:lib" > out2 2>"$TEST_log" || fail "Expected success"
output1="$(cat out1)"
output2="$(cat out2)"
if [[ "$output1" != "$output2" ]]
then
fail "$(cat<<EOF
Nondeterminism in cquery:
${output1}
!=
${output2}
You may have added an option without a meaningful toString() implementation
EOF
)"
fi
}
function test_respects_selects() {
local -r pkg=$FUNCNAME
mkdir -p $pkg
cat > $pkg/BUILD <<'EOF'
sh_library(
name = "ash",
deps = select({
":excelsior": [":foo"],
":americana": [":bar"],
}),
)
sh_library(name = "foo")
sh_library(name = "bar")
config_setting(
name = "excelsior",
values = {"define": "species=excelsior"},
)
config_setting(
name = "americana",
values = {"define": "species=americana"},
)
EOF
bazel cquery "deps(//$pkg:ash)" --define species=excelsior > output \
2>"$TEST_log" || fail "Excepted success"
assert_contains "//$pkg:foo" output
assert_not_contains "//$pkg:bar" output
}
function test_empty_results_printed() {
local -r pkg=$FUNCNAME
mkdir -p $pkg
cat > $pkg/BUILD <<'EOF'
sh_library(name='redwood', deps=[':sequoia',':sequoiadendron'])
sh_library(name='sequoia')
sh_library(name='sequoiadendron')
EOF
bazel cquery "somepath(//$pkg:sequoia,//$pkg:sequoiadendron)" \
> output 2>"$TEST_log" || fail "Expected success"
expect_log "INFO: Empty query results"
assert_not_contains "//$pkg:sequoiadendron" output
}
function test_universe_scope_specified() {
local -r pkg=$FUNCNAME
write_test_targets $pkg
# The java_library rule has a host transition on its plugins attribute.
bazel cquery //$pkg:target+//$pkg:host --universe_scope=//$pkg:main \
> output 2>"$TEST_log" || fail "Excepted success"
# Find the lines of output for //$pkg:plugin and //$pkg:dep.
PKG_HOST=$(grep "//$pkg:host" output)
PKG_TARGET=$(grep "//$pkg:target" output)
# Trim to just configurations.
HOST_CONFIG=${PKG_HOST/"//$pkg:host"}
TARGET_CONFIG=${PKG_TARGET/"//$pkg:target"}
# Ensure they are are not equal.
assert_not_equals $HOST_CONFIG $TARGET_CONFIG
}
function test_transitions_lite() {
local -r pkg=$FUNCNAME
write_test_targets $pkg
bazel cquery "deps(//$pkg:main)" --transitions=lite \
> output 2>"$TEST_log" || fail "Excepted success"
assert_contains "//$pkg:main" output
assert_contains "host_dep#//$pkg:host#(exec + (TestTrimmingTransition + ConfigFeatureFlagTaggedTrimmingTransition))" output
}
function test_transitions_full() {
local -r pkg=$FUNCNAME
write_test_targets $pkg
bazel cquery "deps(//$pkg:main)" --transitions=full \
> output 2>"$TEST_log" || fail "Excepted success"
assert_contains "//$pkg:main" output
assert_contains "host_dep#//$pkg:host#(exec + (TestTrimmingTransition + ConfigFeatureFlagTaggedTrimmingTransition))" output
}
function write_test_targets() {
mkdir -p $pkg
cat > $pkg/rule.bzl <<'EOF'
def _my_rule_impl(ctx):
pass
my_rule = rule(
implementation = _my_rule_impl,
attrs = {
"src_dep": attr.label(allow_single_file = True),
"target_dep": attr.label(cfg = 'target'),
"host_dep": attr.label(cfg = 'exec'),
},
)
EOF
cat > $pkg/BUILD <<'EOF'
load(':rule.bzl', 'my_rule')
filegroup(name = "target")
filegroup(name = "host")
my_rule(
name = "main",
src_dep = "file.txt",
target_dep = ":target",
host_dep = ":host",
)
EOF
touch $pkg/file.txt
}
# TODO(gregce): --show_config_fragments and RequiredConfigFragmentsProvider
# (the native Java code that powers --show_config_fragments) were originally
# conceived as two pieces of the same functionality. But the former is just
# a provider, which means it can be consumed by other logic. Consider moving
# these tests out of cquery and into proper Java integration tests.
function test_show_transitive_config_fragments() {
local -r pkg=$FUNCNAME
mkdir -p $pkg
cat > $pkg/BUILD <<'EOF'
cc_library(
name = "cclib",
srcs = ["mylib.cc"],
)
cc_library(
name = "cclib_with_py_dep",
srcs = ["mylib2.cc"],
data = [":pylib"],
)
py_library(
name = "pylib",
srcs = ["pylib.py"],
)
EOF
bazel cquery "//$pkg:*" --show_config_fragments=transitive > output \
2>"$TEST_log" || fail "Expected success"
assert_contains "//$pkg:cclib .*CppConfiguration" output
assert_not_contains "//$pkg:cclib .*PythonConfiguration" output
assert_contains "//$pkg:cclib_with_py_dep .*CppConfiguration" output
assert_contains "//$pkg:cclib_with_py_dep .*PythonConfiguration" output
assert_not_contains "//$pkg:pylib .*CppConfiguration" output
assert_contains "//$pkg:pylib .*PythonConfiguration" output
assert_contains "//$pkg:mylib.cc (null) \[\]" output
}
function test_show_transitive_config_fragments_select() {
local -r pkg=$FUNCNAME
mkdir -p $pkg
cat > $pkg/BUILD <<'EOF'
cc_library(
name = "cclib",
srcs = ["mylib.cc"],
deps = [":cclib_with_select"]
)
config_setting(
name = "py_reading_condition",
values = {"build_python_zip": "1"})
cc_library(
name = "cclib_with_select",
srcs = select({
":py_reading_condition": ["version1.cc"],
"//conditions:default": ["version2.cc"],
})
)
EOF
bazel cquery "//$pkg:all" --show_config_fragments=transitive > output \
2>"$TEST_log" || fail "Expected success"
assert_contains "//$pkg:cclib .*CppConfiguration" output
assert_contains "//$pkg:cclib .*PythonOptions" output
assert_contains "//$pkg:py_reading_condition .*PythonOptions" output
assert_contains "//$pkg:cclib_with_select .*CppConfiguration" output
assert_contains "//$pkg:cclib_with_select .*PythonOptions" output
}
function test_show_transitive_config_fragments_alias() {
local -r pkg=$FUNCNAME
mkdir -p $pkg
cat > $pkg/BUILD <<'EOF'
cc_library(
name = "cclib_with_py_dep",
srcs = ["mylib2.cc"],
data = [":myalias"],
)
alias(
name = "myalias",
actual = ":pylib"
)
py_library(
name = "pylib",
srcs = ["pylib.py"],
)
EOF
bazel cquery "//$pkg:all" --show_config_fragments=transitive > output \
2>"$TEST_log" || fail "Expected success"
assert_contains "//$pkg:cclib_with_py_dep .*CppConfiguration" output
assert_contains "//$pkg:cclib_with_py_dep .*PythonConfiguration" output
}
function test_direct_alias_requirements() {
# Aliases delegate many read calls to their actual targets. This test
# ensures we don't skip requirements that the alias has but its actual
# target doesn't.
local -r pkg=$FUNCNAME
mkdir -p $pkg
cat > $pkg/BUILD <<'EOF'
cc_library(
name = "ccrule",
srcs = ["ccrule.cc"],
)
config_setting(
name = "cfg",
define_values = {"abc": "1"},
)
alias(
name = "al",
actual = select({
":cfg": ":ccrule",
}),
)
EOF
bazel cquery "//$pkg:al" --show_config_fragments=direct --define=abc=1 \
> output 2>"$TEST_log" || fail "Expected success"
assert_contains "//$pkg:al .*--define:abc" output
# CppConfiguration is a transitive, not direct, requirement.
assert_not_contains "//$pkg:al .*CppConfiguration" output
}
function test_show_transitive_config_fragments_host_deps() {
local -r pkg=$FUNCNAME
mkdir -p $pkg
cat > $pkg/BUILD <<'EOF'
cc_library(
name = "cclib_with_py_dep",
srcs = ["mylib2.cc"],
data = [":g"],
)
genrule(
name = "g",
srcs = [],
outs = ["g.out"],
cmd = "echo Hello! > $@",
tools = [":pylib"])
py_library(
name = "pylib",
srcs = ["pylib.py"],
)
EOF
bazel cquery "//$pkg:cclib_with_py_dep" --show_config_fragments=transitive > \
output 2>"$TEST_log" || fail "Expected success"
assert_contains "//$pkg:cclib_with_py_dep .*PythonConfiguration" output
}
function test_show_transitive_config_fragments_through_output_file() {
local -r pkg=$FUNCNAME
mkdir -p $pkg
cat > $pkg/BUILD <<'EOF'
cc_library(
name = "cclib_with_py_dep",
srcs = ["mylib2.cc"],
data = [":g.out"], # Output file dependency declared here.
)
genrule(
name = "g",
srcs = [],
outs = ["g.out"],
cmd = "echo Hello! > $@",
tools = [":pylib"])
py_library(
name = "pylib",
srcs = ["pylib.py"],
)
EOF
bazel cquery "//$pkg:cclib_with_py_dep" --show_config_fragments=transitive > \
output 2>"$TEST_log" || fail "Expected success"
assert_contains "//$pkg:cclib_with_py_dep .*PythonConfiguration" output
}
function test_show_direct_config_fragments() {
local -r pkg=$FUNCNAME
mkdir -p $pkg
cat > $pkg/BUILD <<'EOF'
cc_library(
name = "cclib",
srcs = ["mylib.cc"],
)
cc_library(
name = "cclib_with_py_dep",
srcs = ["mylib2.cc"],
data = [":pylib"],
)
py_library(
name = "pylib",
srcs = ["pylib.py"],
)
EOF
bazel cquery "//$pkg:all" --show_config_fragments=direct > output \
2>"$TEST_log" || fail "Expected success"
assert_contains "//$pkg:cclib .*CppConfiguration" output
assert_not_contains "//$pkg:cclib .*PythonConfiguration" output
assert_contains "//$pkg:cclib_with_py_dep .*CppConfiguration" output
assert_not_contains "//$pkg:cclib_with_py_dep .*PythonConfiguration" output
}
function test_show_direct_config_fragments_select() {
local -r pkg=$FUNCNAME
mkdir -p $pkg
cat > $pkg/BUILD <<'EOF'
cc_library(
name = "cclib",
srcs = ["mylib.cc"],
deps = [":cclib_with_select"]
)
config_setting(
name = "py_reading_condition",
values = {
"build_python_zip": "1",
"shell_executable": "foo"
}
)
cc_library(
name = "cclib_with_select",
srcs = select({
":py_reading_condition": ["version1.cc"],
"//conditions:default": ["version2.cc"],
})
)
EOF
bazel cquery "//$pkg:all" --show_config_fragments=direct > output \
2>"$TEST_log" || fail "Expected success"
assert_contains "//$pkg:cclib .*CppConfiguration" output
assert_not_contains "//$pkg:cclib .*PythonOptions" output
assert_contains "//$pkg:py_reading_condition .*PythonOptions" output
assert_contains "//$pkg:py_reading_condition .*ShellConfiguration\$Options" output
assert_contains "//$pkg:cclib_with_select .*CppConfiguration" output
assert_contains "//$pkg:cclib_with_select .*PythonOptions" output
assert_contains "//$pkg:cclib_with_select .*ShellConfiguration\$Options" output
}
function test_show_config_fragments_select_on_starlark_option() {
local -r pkg=$FUNCNAME
mkdir -p $pkg
cat > $pkg/defs.bzl <<'EOF'
def _string_flag_impl(ctx):
pass
string_flag = rule(
implementation = _string_flag_impl,
build_setting = config.string()
)
EOF
cat > $pkg/BUILD <<'EOF'
load(":defs.bzl", "string_flag")
string_flag(
name = "my_flag",
build_setting_default = "default_value"
)
config_setting(
name = "is_my_flag_foo",
flag_values = {":my_flag": "foo"}
)
cc_library(
name = "cclib_with_select",
srcs = select({
":is_my_flag_foo": ["version_foo.cc"],
"//conditions:default": ["version_default.cc"],
})
)
cc_library(
name = "cclib_plain",
srcs = ["version_plain.cc"]
)
EOF
bazel cquery "//$pkg:all" --show_config_fragments=direct > output \
2>"$TEST_log" || fail "Expected success"
assert_contains "//$pkg:my_flag .*//$pkg:my_flag" output
assert_contains "//$pkg:is_my_flag_foo .*//$pkg:my_flag" output
assert_contains "//$pkg:cclib_with_select .*//$pkg:my_flag" output
assert_not_contains "//$pkg:cclib_plain .*//$pkg:my_flag" output
}
function test_show_config_fragments_starlark_rule_requires_starlark_option() {
local -r pkg=$FUNCNAME
mkdir -p $pkg
cat > $pkg/defs.bzl <<EOF
def _string_flag_impl(ctx):
pass
string_flag = rule(
implementation = _string_flag_impl,
build_setting = config.string()
)
def _rule_with_flag_dep_impl(ctx):
pass
rule_with_flag_dep = rule(
implementation = _rule_with_flag_dep_impl,
attrs = {
"_flagdep": attr.label(default = "//$pkg:my_flag")
}
)
EOF
cat > $pkg/BUILD <<'EOF'
load(":defs.bzl", "rule_with_flag_dep", "string_flag")
string_flag(
name = "my_flag",
build_setting_default = "default_value"
)
rule_with_flag_dep(
name = "my_rule"
)
EOF
bazel cquery "//$pkg:all" --show_config_fragments=direct > output \
2>"$TEST_log" || fail "Expected success"
assert_contains "//$pkg:my_rule .*//$pkg:my_flag" output
bazel cquery "//$pkg:all" --show_config_fragments=transitive > output \
2>"$TEST_log" || fail "Expected success"
assert_contains "//$pkg:my_rule .*//$pkg:my_flag" output
}
function test_show_config_fragments_select_on_feature_flag_info_provider() {
local -r pkg=$FUNCNAME
mkdir -p $pkg
cat > $pkg/defs.bzl <<'EOF'
def _feature_flag_provider_rule_impl(ctx):
return [config_common.FeatureFlagInfo(value = "foo")]
feature_flag_provider_rule = rule(
implementation = _feature_flag_provider_rule_impl,
)
EOF
cat > $pkg/BUILD <<'EOF'
load(":defs.bzl", "feature_flag_provider_rule")
feature_flag_provider_rule(name = "foo_feature")
config_setting(
name = "is_foo_feature",
flag_values = {":foo_feature": "foo"},
)
cc_library(
name = "cclib_select_on_foo_feature",
srcs = ["hi.cc"],
deps = select({
":is_foo_feature": [],
"//conditions:default": [],
}),
)
cc_library(
name = "cclib_no_select",
srcs = ["heya.cc"]
)
EOF
bazel cquery "//$pkg:all" --show_config_fragments=direct > output \
2>"$TEST_log" || fail "Expected success"
assert_contains "//$pkg:is_foo_feature .*//$pkg:foo_feature" output
assert_contains "//$pkg:cclib_select_on_foo_feature .*//$pkg:foo_feature" output
assert_not_contains "//$pkg:cclib_no_select .*//$pkg:foo_feature" output
# Starlark rules exposing FeatureFlagInfo aren't really part of the
# configuration. You can't "set" them as part of the configuration like you
# can Starlark flags or Android feature flags. All they do is provide a new
# interface for rules to select() over the existing configuration.
#
# Nevertheless, since you can select() on them as this test illustrates, it's
# reasonable to "pretend" for the purposes of --show_config_fragments. At best
# they still show interesting dependencies. At worst they provide a bit more
# conceptual clutter to wade through when analyzing a build graph.
#
# If we're going to support them, it conceptually makes sense to consider
# //$pkg:foo_feature a config dependency on itself. That doesn't currently
# work. The only reason is because the most natural place to encode this
# is to have lib.analysis.RuleConfiguredTargetBuilder check if the rule
# provides lib.rules.config.ConfigFeatureFlagProvider. But that adds an
# unwanted dependency from lib.analysis onto lib.rules.
#
# Given this use case's unimportance, we just leave things as-is for the sake
# of simplicity in the wider code base. We can always re-evaluate if needed.
assert_not_contains "//$pkg:foo_feature .*//$pkg:foo_feature" output
}
function test_show_config_fragments_on_define() {
local -r pkg=$FUNCNAME
mkdir -p $pkg
cat > $pkg/BUILD <<'EOF'
config_setting(
name = "is_a_on",
define_values = {"a": "on"}
)
cc_library(
name = "cclib_with_select",
srcs = select({
":is_a_on": ["version1.cc"],
"//conditions:default": ["version2.cc"],
})
)
EOF
bazel cquery "//$pkg:all" --show_config_fragments=direct --define a=on \
--define b=on > output 2>"$TEST_log" || fail "Expected success"
assert_contains "//$pkg:cclib_with_select .*CppConfiguration" output
assert_contains "//$pkg:cclib_with_select .*--define:a" output
assert_not_contains "//$pkg:cclib_with_select .*--define:b" output
}
function test_show_config_fragments_on_starlark_required_fragments() {
local -r pkg=$FUNCNAME
mkdir -p $pkg
cat > $pkg/defs.bzl <<'EOF'
def _impl(ctx):
pass
java_requiring_rule = rule(
implementation = _impl,
fragments = ["java"],
attrs = {}
)
EOF
cat > $pkg/BUILD <<EOF
load("//$pkg:defs.bzl", "java_requiring_rule")
java_requiring_rule(
name = "buildme"
)
EOF
bazel cquery "//$pkg:all" --show_config_fragments=direct \
> output 2>"$TEST_log" || fail "Expected success"
assert_contains "//$pkg:buildme .*JavaConfiguration" output
}
# Starlark aspects can't directly require configuration fragments. But they can
# have implicit label dependencies on rules that do. This test ensures that
# gets factored in.
#
# Note that cquery doesn't support queries over aspects: `deps(//foo)` won't
# list aspects or traverse their dependencies. This makes it hard to understand
# *why* a rule requires a fragment if only through an aspect. That's an argument
# for making cquery generally aspect-aware.
function test_show_config_fragments_includes_starlark_aspects() {
local -r pkg=$FUNCNAME
mkdir -p $pkg
cat > $pkg/defs.bzl <<EOF
def _aspect_impl(target, ctx):
return []
cc_depending_aspect = aspect(
attrs = {
# This creates an implicit dependency on a C++ library that
# only comes through the aspect.
"_extra_dep": attr.label(default = "//$pkg:cclib"),
},
implementation = _aspect_impl,
)
def _impl(ctx):
pass
simple_rule = rule(
implementation = _impl,
attrs = {
"deps": attr.label_list(aspects = [cc_depending_aspect])
}
)
EOF
cat > $pkg/BUILD <<EOF
load("//$pkg:defs.bzl", "simple_rule")
simple_rule(
name = "buildme",
deps = [":simple_dep"],
)
simple_rule(
name = "simple_dep",
)
cc_library(
name = "cclib",
srcs = ["cclib.cc"],
)
EOF
# No direct requirement:
bazel cquery "//$pkg:buildme" --show_config_fragments=direct \
> output 2>"$TEST_log" || fail "Expected success"
assert_not_contains "//$pkg:buildme .*CppConfiguration" output
# But there is a transitive requirement through the aspect:
bazel cquery "//$pkg:buildme" --show_config_fragments=transitive \
> output 2>"$TEST_log" || fail "Expected success"
assert_contains "//$pkg:buildme .*CppConfiguration" output
}
function test_manual_tagged_targets_always_included_for_queries() {
local -r pkg=$FUNCNAME
mkdir -p $pkg
cat > $pkg/BUILD <<'EOF'
genrule(
name = "always_build",
srcs = [],
outs = ["always_build.out"],
cmd = "echo hi > $@")
genrule(
name = "only_build_explicitly",
tags = ["manual"],
srcs = [],
outs = ["only_build_explicitly.out"],
cmd = "echo hi > $@")
EOF
bazel cquery "//$pkg:all" > output 2>"$TEST_log" || fail "Expected success"
assert_contains "//$pkg:always_build" output
assert_contains "//$pkg:only_build_explicitly" output
}
function test_include_test_suites() {
local -r pkg=$FUNCNAME
mkdir -p $pkg
cat > $pkg/BUILD <<'EOF'
test_suite(
name = "my_suite",
tests = [":my_test"])
cc_test(
name = "my_test",
srcs = ["my_test.cc"])
EOF
bazel cquery "//$pkg:all" > output 2>"$TEST_log" || fail "Expected success"
assert_contains "//$pkg:my_suite" output
assert_contains "//$pkg:my_test" output
}
function test_build_tests_only_override() {
local -r pkg=$FUNCNAME
mkdir -p $pkg
cat > $pkg/BUILD <<'EOF'
cc_binary(
name = "not_a_test",
srcs = ["not_a_test.cc"])
EOF
bazel cquery --build_tests_only "//$pkg:all" > output 2>"$TEST_log" || \
fail "Expected success"
assert_contains "//$pkg:not_a_test" output
}
function test_label_output_shows_alias_labels() {
local -r pkg=$FUNCNAME
mkdir -p $pkg
cat > $pkg/BUILD <<'EOF'
filegroup(name = "fg", srcs = [":the_alias"])
alias(name = "the_alias", actual = "some_file")
EOF
bazel cquery "deps(//$pkg:fg)" > output 2>"$TEST_log" || fail "Expected
success"
assert_contains "//$pkg:the_alias" output
assert_contains "//$pkg:some_file (null)" output
assert_equals "$(grep some_file output | wc -l | egrep -o '[0-9]+')" "1"
}
function test_transitions_output_shows_alias_labels() {
local -r pkg=$FUNCNAME
mkdir -p $pkg
cat > $pkg/BUILD <<'EOF'
filegroup(name = "fg", srcs = [":the_alias"])
alias(name = "the_alias", actual = "some_file")
EOF
bazel cquery "deps(//$pkg:fg)" --transitions=lite > output 2>"$TEST_log" || fail "Expected
success"
assert_contains "//$pkg:the_alias" output
assert_contains "//$pkg:some_file (null)" output
assert_equals "$(grep some_file output | wc -l | egrep -o '[0-9]+')" "1"
}
function test_starlark_output_mode() {
local -r pkg=$FUNCNAME
mkdir -p $pkg
cat > $pkg/BUILD <<'EOF'
py_library(
name = "pylib",
srcs = ["pylib.py"],
)
py_library(
name = "pylibtwo",
srcs = ["pylibtwo.py", "pylibtwo2.py",],
)
EOF
bazel cquery "//$pkg:all" --output=starlark \
--starlark:expr="str(target.label) + '%foo'" > output \
2>"$TEST_log" || fail "Expected success"
assert_contains "//$pkg:pylib%foo" output
assert_contains "//$pkg:pylibtwo%foo" output
# Test that the default for --starlark:expr str(target.label)
bazel cquery "//$pkg:all" --output=starlark >output \
2>"$TEST_log" || fail "Expected success"
assert_contains "//$pkg:pylib" output
assert_contains "//$pkg:pylibtwo" output
bazel cquery "//$pkg:all" --output=starlark \
--starlark:expr="str(target.label) + '%' + str(target.files.to_list()[1].is_directory)" \
> output 2>"$TEST_log" || fail "Expected success"
assert_contains "//$pkg:pylibtwo%False" output
# pylib evaluation will fail, as it has only one output file.
assert_contains "Starlark evaluation error for //$pkg:pylib" "$TEST_log"
cat > $pkg/outfunc.bzl <<'EOF'
SUFFIX='%foo_file'
def format(t):
return str(t.label) + SUFFIX
UNUSED_THING_AT_END=1
EOF
bazel cquery "//$pkg:all" --output=starlark --starlark:file="$pkg/outfunc.bzl" >output \
2>"$TEST_log" || fail "Expected success"
assert_contains "//$pkg:pylib%foo_file" output
assert_contains "//$pkg:pylibtwo%foo_file" output
cat > $pkg/outfunc_isdir.bzl <<'EOF'
def format(t):
return str(t.label) + '%' + str(t.files.to_list()[1].is_directory)
EOF
bazel cquery "//$pkg:all" --output=starlark --starlark:file="$pkg/outfunc_isdir.bzl" \
>output 2>"$TEST_log" || fail "Expected success"
assert_contains "//$pkg:pylibtwo%False" output
# pylib evaluation will fail, as it has only one output file.
assert_contains "Starlark evaluation error for //$pkg:pylib" "$TEST_log"
}
function test_starlark_build_options() {
local -r pkg=$FUNCNAME
mkdir -p $pkg
cat > tools/allowlists/function_transition_allowlist/BUILD <<EOF
package_group(
name = "function_transition_allowlist",
packages = [
"//...",
],
)
EOF
cat > "$pkg/rules.bzl" <<EOF
BuildSettingInfo = provider(fields = ["value"])
def _flag_impl(ctx):
return BuildSettingInfo(value = ctx.build_setting_value)
bool_flag = rule(
implementation = _flag_impl,
build_setting = config.bool(flag = True),
)
def _dep_transition_impl(settings, attr):
return {
"//$pkg:myflag": True,
"//command_line_option:platform_suffix": "blah"
}
_dep_transition = transition(
implementation = _dep_transition_impl,
inputs = [],
outputs = [
"//$pkg:myflag",
"//command_line_option:platform_suffix",
],
)
def _root_rule_impl(ctx):
return []
root_rule = rule(
_root_rule_impl,
attrs = {
"_allowlist_function_transition": attr.label(default = "//tools/allowlists/function_transition_allowlist"),
"deps": attr.label_list(cfg = _dep_transition),
},
)
EOF
cat > $pkg/BUILD <<'EOF'
load(":rules.bzl", "bool_flag", "root_rule")
exports_files(["rules.bzl"])
bool_flag(
name = "myflag",
build_setting_default = False,
)
py_library(
name = "bar",
srcs = ["pylib.py"],
)
root_rule(
name = "foo",
deps = ["bar"],
)
EOF
cat > $pkg/expr.star <<EOF
def format(target):
bo = build_options(target)
print(bo)
if bo == None:
return str(target.label) + '%None'
first = str(bo['//command_line_option:platform_suffix'])
second = str(('//$pkg:myflag' in bo) and bo['//$pkg:myflag'])
return str(target.label) + '%' + first + '%' + second
EOF
bazel cquery "//$pkg:bar" --output=starlark \
--starlark:file=$pkg/expr.star > output 2>"$TEST_log" || fail "Expected success"
assert_contains "//$pkg:bar%None%False" output
bazel cquery "//$pkg:foo" --output=starlark \
--starlark:file=$pkg/expr.star > output 2>"$TEST_log" || fail "Expected success"
assert_contains "//$pkg:foo%None%False" output
bazel cquery "kind(rule, deps(//$pkg:foo))" --output=starlark \
--starlark:file=$pkg/expr.star > output 2>"$TEST_log" || fail "Expected success"
assert_contains "//$pkg:foo%None%False" output
assert_contains "//$pkg:bar%blah%True" output
bazel cquery "//$pkg:rules.bzl" --output=starlark \
--starlark:file=$pkg/expr.star > output 2>"$TEST_log" || fail "Expected success"
assert_contains "//$pkg:rules.bzl%None" output
}
function test_starlark_build_options_invalid_arg() {
local -r pkg=$FUNCNAME
mkdir -p $pkg
cat > $pkg/BUILD <<'EOF'
py_library(
name = "foo",
srcs = ["pylib.py"],
)
EOF
bazel cquery "//$pkg:foo" --output=starlark \
--starlark:expr="build_options(False)" > output 2>"$TEST_log" || fail "Expected success"
assert_contains "Error in build_options: in call to build_options()" "$TEST_log"
bazel cquery "//$pkg:foo" --output=starlark \
--starlark:expr="build_options()" > output 2>"$TEST_log" || fail "Expected success"
assert_contains "build_options() missing 1 required positional argument: target" "$TEST_log"
bazel cquery "//$pkg:foo" --output=starlark \
--starlark:expr="build_options(target, 'blah')" > output 2>"$TEST_log" || fail "Expected success"
assert_contains "build_options() accepts no more than 1 positional argument but got 2" "$TEST_log"
}
function test_starlark_output_both_options() {
local -r pkg=$FUNCNAME
mkdir -p $pkg
touch $pkg/BUILD
bazel cquery "//$pkg:all" --output=starlark --starlark:expr=a --starlark:file=b \
>output 2>"$TEST_log" && fail "Expected failure"
assert_contains ".*You must not specify both --starlark:expr and --starlark:file" \
"$TEST_log"
}
function test_starlark_output_invalid_expression() {
local -r pkg=$FUNCNAME
mkdir -p $pkg
touch $pkg/BUILD
bazel cquery "//$pkg:all" --output=starlark \
--starlark:expr="no_symbol" \
> output 2>"$TEST_log" && fail "Expected failure"
assert_contains "invalid --starlark:expr: name 'no_symbol' is not defined" $TEST_log
bazel cquery "//$pkg:all" --output=starlark \
--starlark:expr="def foo(): return 5" \
> output 2>"$TEST_log" && fail "Expected failure"
assert_contains "syntax error at 'def': expected expression" $TEST_log
}
function test_starlark_output_missing_file() {
local -r pkg=$FUNCNAME
mkdir -p $pkg
touch $pkg/BUILD
bazel cquery "//$pkg:all" --output=starlark --starlark:file="$pkg/outfunc.bzl" >output \
2>"$TEST_log" && fail "Expected failure"
assert_contains "--starlark:file: failed to read $pkg.outfunc.bzl" $TEST_log
}
function test_starlark_output_missing_format() {
local -r pkg=$FUNCNAME
mkdir -p $pkg
touch $pkg/BUILD
cat > $pkg/outfunc.bzl <<'EOF'
def foo(t):
return str(t.label) + '%foo_file'
EOF
bazel cquery "//$pkg:all" --output=starlark --starlark:file="$pkg/outfunc.bzl" >output \
2>"$TEST_log" && fail "Expected failure"
assert_contains "invalid --starlark:file:.*does not define 'format'" $TEST_log
}
function test_starlark_output_format_wrong_number_args() {
local -r pkg=$FUNCNAME
mkdir -p $pkg
touch $pkg/BUILD
cat > $pkg/outfunc.bzl <<'EOF'
def format(t, not_allowed_to_have_a_second_arg):
return str(t.label) + '%foo_file'
EOF
bazel cquery "//$pkg:all" --output=starlark --starlark:file="$pkg/outfunc.bzl" >output \
2>"$TEST_log" && fail "Expected failure"
assert_contains "invalid --starlark:file:.* must take exactly 1 argument" $TEST_log
}
function test_starlark_output_format_not_function() {
local -r pkg=$FUNCNAME
mkdir -p $pkg
touch $pkg/BUILD
cat > $pkg/outfunc.bzl <<'EOF'
format = 1
EOF
bazel cquery "//$pkg:all" --output=starlark --starlark:file="$pkg/outfunc.bzl" >output \
2>"$TEST_log" && fail "Expected failure"
assert_contains "invalid --starlark:file:.* for 'format', want function" $TEST_log
}
function test_starlark_output_cc_library_files() {
local -r pkg=$FUNCNAME
mkdir -p $pkg
cat > $pkg/BUILD <<'EOF'
cc_library(
name = "cclib",
srcs = ["mylib.cc"],
)
EOF
bazel cquery "//$pkg:all" --output=starlark \
--starlark:expr="' '.join([f.basename for f in target.files.to_list()])" \
> output 2>"$TEST_log" || fail "Expected failure"
if "$is_windows"; then
assert_contains "cclib.lib" output
elif is_darwin; then
assert_contains "libcclib.a" output
else
assert_contains "libcclib.a" output
assert_contains "libcclib.so" output
fi
}
function test_starlark_file_output() {
local -r pkg=$FUNCNAME
mkdir -p $pkg
cat > $pkg/BUILD <<'EOF'
exports_files(srcs = ["foo"])
EOF
bazel cquery "//$pkg:foo" --output=starlark \
--starlark:expr="'path=' + target.files.to_list()[0].path" \
> output 2>"$TEST_log" || fail "Expected failure"
assert_contains "^path=$pkg/foo$" output
}
function test_starlark_common_libs() {
local -r pkg=$FUNCNAME
mkdir -p $pkg
cat > $pkg/BUILD <<'EOF'
exports_files(srcs = ["foo"])
EOF
bazel cquery "//$pkg:foo" --output=starlark \
--starlark:expr="str(type(depset())) + ' ' + str(json.encode(struct(foo = 'bar')))" \
> output 2>"$TEST_log" || fail "Unexpected failure"
assert_contains "^depset {\"foo\":\"bar\"}$" output
}
function test_starlark_output_providers_function() {
local -r pkg=$FUNCNAME
mkdir -p $pkg
cat > $pkg/defs.bzl <<'EOF'
def foo_impl(ctx):
return [DefaultInfo()]
foo_library = rule(
implementation = foo_impl,
)
EOF
cat > $pkg/BUILD <<'EOF'
load(":defs.bzl", "foo_library")
foo_library(
name = "lib",
)
exports_files(["srcfile.txt"])
EOF
cat > $pkg/srcfile.txt <<'EOF'
hello, world
EOF
cat > $pkg/outfunc.bzl <<'EOF'
def format(target):
p = providers(target)
if not p:
return str(target.label) + ':no providers'
ret = str(target.label) + ':providers=' + str(sorted(p.keys()))
vis_info = p.get('VisibilityProvider')
if vis_info:
ret += '\n\tVisibilityProvider.label:' + str(vis_info.label)
output_group_info = p.get('OutputGroupInfo')
if output_group_info:
ret += '\n\tOutputGroupInfo found'
return ret
EOF
bazel cquery "//$pkg:lib" --output=starlark --starlark:file="$pkg/outfunc.bzl" >output \
2>"$TEST_log" || fail "Expected success"
assert_contains "//$pkg:lib:providers=.*OutputGroupInfo" output
assert_contains "OutputGroupInfo found" output
# A file
bazel cquery "//$pkg:srcfile.txt" --output=starlark --starlark:file="$pkg/outfunc.bzl" >output \
2>"$TEST_log" || fail "Expected success"
assert_contains "//$pkg:srcfile.txt:providers=.*FileProvider.*FilesToRunProvider.*LicensesProvider.*VisibilityProvider" \
output
assert_contains "VisibilityProvider.label:@//$pkg:srcfile.txt" output
}
function test_starlark_output_providers_starlark_provider() {
local -r pkg=$FUNCNAME
mkdir -p $pkg
cat > $pkg/BUILD <<EOF
load(":my_rule.bzl", "my_rule")
my_rule(name="myrule")
EOF
cat > $pkg/my_rule.bzl <<'EOF'
# A no-op rule that manifests a provider
MyRuleInfo = provider(fields={"label": "a_rule_label"})
def _my_rule_impl(ctx):
return [MyRuleInfo(label="some_value")]
my_rule = rule(
implementation = _my_rule_impl,
attrs = {},
)
EOF
cat > $pkg/outfunc.bzl <<EOF
def format(target):
p = providers(target)
return p["//$pkg:my_rule.bzl%MyRuleInfo"].label
EOF
bazel cquery "//$pkg:myrule" --output=starlark --starlark:file="$pkg/outfunc.bzl" >output \
2>"$TEST_log" || fail "Expected success"
assert_contains "some_value" output
}
function test_starlark_output_providers_starlark_provider_for_alias() {
local -r pkg=$FUNCNAME
mkdir -p $pkg
cat > $pkg/BUILD <<EOF
load(":my_rule.bzl", "my_rule")
my_rule(name="myrule")
alias(name="myalias", actual="myrule")
EOF
cat > $pkg/my_rule.bzl <<'EOF'
# A no-op rule that manifests a provider
MyRuleInfo = provider(fields={"label": "a_rule_label"})
def _my_rule_impl(ctx):
return [MyRuleInfo(label="some_value")]
my_rule = rule(
implementation = _my_rule_impl,
attrs = {},
)
EOF
cat > $pkg/outfunc.bzl <<EOF
def format(target):
p = providers(target)
return p["//$pkg:my_rule.bzl%MyRuleInfo"].label
EOF
bazel cquery "//$pkg:myalias" --output=starlark --starlark:file="$pkg/outfunc.bzl" >output \
2>"$TEST_log" || fail "Expected success"
assert_contains "some_value" output
}
function test_bazelignore_error_cquery_nocrash() {
local -r pkg=$FUNCNAME
mkdir -p $pkg/repo
touch $pkg/repo/WORKSPACE
cat > $pkg/repo/BUILD <<EOF
toolchain_type(name = "toolchain_type")
EOF
cat > $pkg/WORKSPACE <<EOF
local_repository(name = "repo", path = "./repo")
EOF
bazel cquery --output=starlark --starlark:expr 'target' @repo//:toolchain_type >output \
2>"$TEST_log" && fail "Expected failure"
# A Bazel crash would have exit codes 3x.
assert_equals $? 1
}
# Regression test for https://github.com/bazelbuild/bazel/issues/13301
function test_external_repo_scope() {
if [ "${PRODUCT_NAME}" != "bazel" ]; then
# Tests of external repositories only work under bazel.
return 0
fi
local -r dir=$FUNCNAME
mkdir -p $dir/repo
touch $dir/repo/WORKSPACE
cat > $dir/repo/BUILD <<EOF
sh_library(name='maple', deps=[':japanese'])
sh_library(name='japanese')
EOF
mkdir -p $dir/main
cat > $dir/main/WORKSPACE <<EOF
local_repository(name = "repo", path = "../repo")
EOF
touch $dir/main/BUILD
cd $dir/main
bazel cquery @repo//... &>"$TEST_log" || fail "Unexpected failure"
expect_not_log "no targets found beneath"
expect_log "@repo//:maple"
expect_log "@repo//:japanese"
}
function test_test_arg_in_bazelrc() {
local -r pkg=$FUNCNAME
mkdir -p $pkg
cat >$pkg/BUILD <<EOF
sh_test(
name = "test",
srcs = ["test.sh"],
)
EOF
touch $pkg/test.sh
chmod +x $pkg/test.sh
output_before="$(bazel cquery "//$pkg:test")"
add_to_bazelrc "test --test_arg=foo"
output_after="$(bazel cquery "//$pkg:test")"
assert_not_equals "${output_before}" "${output_after}"
}
function set_up_config_test() {
mkdir -p $pkg
# Use a rule that has a configuration transition.
cat > $pkg/rule.bzl <<EOF
def _impl(ctx):
pass
demo_rule = rule(
implementation = _impl,
attrs = {
"binary": attr.label(cfg = "exec"),
},
)
EOF
cat > $pkg/tool.sh <<EOF
echo "Hello"
exit 0
EOF
chmod +x $pkg/tool.sh
cat > $pkg/BUILD <<EOF
load("//$pkg:rule.bzl", "demo_rule")
sh_binary(name = "tool", srcs = ["tool.sh"])
demo_rule(
name = 'demo',
binary = ":tool",
)
EOF
# Find out what the specific configurations are.
bazel cquery "deps(//$pkg:demo)" &>"$TEST_log" || fail "Unexpected failure"
# Find the target config.
target_config="$(grep "^//$pkg:demo ([0-9a-f]\+)" $TEST_log | sed -e 's,.*(\([^)]*\)).*,\1,')"
tool_config="$(grep "^//$pkg:tool ([0-9a-f]\+)" $TEST_log | sed -e 's,.*(\([^)]*\)).*,\1,')"
assert_not_equals "$target_config" "$tool_config"
}
function test_config_function() {
local -r pkg=$FUNCNAME
set_up_config_test $pkg
# Actually call config, verify output
bazel cquery "config(//$pkg:demo, $target_config)" &>"$TEST_log" || fail "Unexpected failure"
expect_log "^//$pkg:demo ($target_config)"
bazel cquery "config(//$pkg:tool, $tool_config)" &>"$TEST_log" || fail "Unexpected failure"
expect_log "^//$pkg:tool ($tool_config)"
}
function test_config_function_wrong_order() {
local -r pkg=$FUNCNAME
set_up_config_test $pkg
# Actually call config, verify output
bazel cquery "config($target_config, //$pkg:demo)" &>"$TEST_log" && fail "Expected to fail"
expect_not_log "^//$pkg:demo ($target_config)"
expect_log "couldn't determine target from filename '$target_config'"
}
function test_config_function_invalid_config() {
local -r pkg=$FUNCNAME
set_up_config_test $pkg
# Actually call config, verify output
bazel cquery "config(//$pkg:demo, notaconfighash)" &>"$TEST_log" && fail "Expected to fail"
expect_not_log "^//$pkg:demo ($target_config)"
expect_log "Unknown configuration ID 'notaconfighash'"
}
function test_error_keep_going() {
local -r pkg=$FUNCNAME
mkdir -p $pkg
cat > $pkg/BUILD <<'EOF'
sh_library(name='maple', deps=[':japanese'])
sh_library(name='japanese')
EOF
# This causes a failure in the cquery function, which should produce an
# actionable error, not a stack trace.
bazel cquery --keep_going "config(//$pkg:oak, notaconfighash)" > output 2>"$TEST_log" && fail "Expected error"
expect_not_log "QueryException"
}
function test_does_not_fail_horribly_with_file() {
rm -rf peach
mkdir -p peach
cat > peach/BUILD <<EOF
sh_library(name='brighton', deps=[':harken'])
sh_library(name='harken')
EOF
echo "deps(//peach:brighton)" > query_file
bazel cquery --query_file=query_file > $TEST_log
expect_log "//peach:brighton"
expect_log "//peach:harken"
}
function test_files_include_source_files() {
local -r pkg=$FUNCNAME
mkdir -p $pkg
cat > $pkg/BUILD <<'EOF'
filegroup(name="files", srcs=["BUILD"])
alias(name="alias", actual="single_file")
EOF
touch $pkg/single_file
bazel cquery --output=files //$pkg:all > output 2>"$TEST_log" || fail "Unexpected failure"
assert_contains "$pkg/BUILD" output
assert_contains "$pkg/single_file" output
}
run_suite "${PRODUCT_NAME} configured query tests"