blob: 6e37f538f139b3252751893983da0c277ffd313f [file] [log] [blame]
# Copyright 2022 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import("//build/compiled_action.gni")
import("//build/components.gni")
import("//build/dist/resource.gni")
import("//src/lib/testing/expectation/preprocess/preprocess.gni")
import("//tools/cmc/build/expect_includes.gni")
# Defines a fuchsia_test_package that carries a set of expectations to apply to
# the results of tests in the package.
#
# Parameters
# test_components (required)
# `fuchsia_component()` targets to include in the package and also register
# as entry points for tests.
# Additional non-test components can be included via `deps`.
# Each target must `include` the `expectation_comparer` client shard
# (meta/client.shard.cml).
# Type: list(labels)
#
# expectations (optional)
# Path to a JSON5 test expectations file. See
# //src/lib/testing/expectation/example_expectations.json5 for an example of
# the format. Either expectations or generated_expectations is required.
# Type: path
#
# generated_expectations (optional)
# Name of the generated_expectations_file target that generates expectation file. Either
# expectations or generated_expectations is required.
# Type: target name
#
# test_specs (optional)
# Additional test specifications to apply to tests defined above.
# See `test_spec.gni`.
# Type: scope
#
# package_name (optional)
# The name of the package.
# Type: string
# Default: target_name
#
# renameable_subpackages (optional)
# A list of subpackages defined by scoped variables `package` (a
# `fuchsia_package()` target) and an optional `name`. See
# `fuchsia_package()` for more details.
# Type: list of scopes
#
# treatment_of_cases_with_error_logs (optional)
# Identifies how test cases that are expected to generate error logs
# should be run.
# Type: string
# Options:
# - "SKIP_CASES_WITH_ERROR_LOGS" indicates that tests expected to
# generate error logs should be skipped.
# - "RUN_ONLY_CASES_WITH_ERROR_LOGS" indicates that only those tests
# expected to generate error logs should be run.
# - By default, all test cases will be run.
# data_deps
# deps
# visibility
template("fuchsia_test_with_expectations_package") {
testonly = true
_base_target_name = target_name
_skip_err_logs_cases = "SKIP_CASES_WITH_ERROR_LOGS"
_run_err_logs_cases = "RUN_ONLY_CASES_WITH_ERROR_LOGS"
not_needed([
_skip_err_logs_cases,
_run_err_logs_cases,
])
_expectations_target = "${target_name}_preprocessed_expectations"
preprocess_expectations(_expectations_target) {
if (defined(invoker.treatment_of_cases_with_error_logs)) {
assert(
invoker.treatment_of_cases_with_error_logs == _skip_err_logs_cases ||
invoker.treatment_of_cases_with_error_logs == _run_err_logs_cases)
if (invoker.treatment_of_cases_with_error_logs == _skip_err_logs_cases) {
cases_to_run = "NoErrLogs"
} else {
cases_to_run = "WithErrLogs"
}
}
if (defined(invoker.generated_expectations)) {
assert(!defined(invoker.expectations))
deps = [ invoker.generated_expectations ]
expectations =
get_label_info(invoker.generated_expectations, "target_gen_dir") +
"/" + get_label_info(invoker.generated_expectations, "name") +
".json5"
} else {
expectations = invoker.expectations
}
output_path = "expectations.json5"
}
# The standard expect_includes build-time check allows you to enforce that, if
# a component depends on your client library, then its manifest must include
# your client shard. Unfortunately for us, there is no expectation client
# library -- the point of this framework is that use of the GN template to
# define the test package is sufficient, without you having to modify the test
# binary, as long as you include the client shard.
# Therefore, we have to discover each test component's manifest ourselves, and
# assert that each of those manifests includes the expectation client shard.
# We start by defining a target with metadata that will be included in our
# cmc_check_includes invocation's `deps`. cmc_check_includes will collect this
# as part of determining the set of shards that must be included in the
# checked manifest.
_expected_includes_metadata_target = "${_base_target_name}-expected-includes"
group(_expected_includes_metadata_target) {
metadata = {
cmc_expected_includes_cml =
[ "//src/lib/testing/expectation/meta/client.shard.cml" ]
}
}
_expected_includes_metadata_target = ":$_expected_includes_metadata_target"
_include_check_targets = []
_index = 0
foreach(test_component, invoker.test_components) {
_prefix = "${_base_target_name}-${_index}"
# Generates a JSON file that lists all the component manifest source paths
# that are transitively reachable along GN `deps` edges starting from
# test_component.
_find_manifest_target = "${_prefix}_locate_manifest"
generated_file(_find_manifest_target) {
outputs = [ "$target_out_dir/$_find_manifest_target.json" ]
data_keys = [ "component_manifest_path" ]
walk_keys = [ "component_manifest_path_barrier" ]
rebase = root_build_dir
output_conversion = "json"
deps = [ test_component ]
visibility = [ ":*" ]
}
_find_manifest_target = ":$_find_manifest_target"
# generated_file is guaranteed to emit the discovered component manifests in
# a postorder traversal, so the last manifest emitted will belong to the
# root component of the test, which is the component we want to ensure
# includes the expectation_comparer client shard.
# (See `fx gn help generated_file` which documents the postorder guarantee.)
_get_last_manifest_target = "${_prefix}_last_manifest"
action(_get_last_manifest_target) {
_jq_prebuilt = "//prebuilt/third_party/jq/${host_platform}/bin/jq"
script = "//src/lib/testing/expectation/get_last_manifest.sh"
sources = get_target_outputs(_find_manifest_target) + [ _jq_prebuilt ]
deps = [ _find_manifest_target ]
outputs = [ "$target_gen_dir/${_get_last_manifest_target}.txt" ]
args = [
rebase_path(_jq_prebuilt, root_build_dir),
rebase_path(sources[0], root_build_dir),
rebase_path(outputs[0], root_build_dir),
]
visibility = [ ":*" ]
}
_get_last_manifest_target = ":$_get_last_manifest_target"
_include_check_target = "${_prefix}-check-includes"
cmc_check_includes(_include_check_target) {
_get_last_manifest_outputs = get_target_outputs(_get_last_manifest_target)
assert(
_get_last_manifest_outputs == [ _get_last_manifest_outputs[0] ],
"$_get_last_manifest_target should have yielded exactly one output")
manifest = _get_last_manifest_outputs[0]
deps = [
_expected_includes_metadata_target,
_get_last_manifest_target,
]
visibility = [ ":*" ]
}
_include_check_target = ":$_include_check_target"
_include_check_targets += [ _include_check_target ]
_index += 1
}
fuchsia_test_package(_base_target_name) {
forward_variables_from(invoker,
[
"test_components",
"test_specs",
"package_name",
"data_deps",
"renameable_subpackages",
"subpackages",
"visibility",
])
deps = _include_check_targets + [
":${_expectations_target}",
"//src/lib/testing/expectation:expectation_comparer",
]
if (defined(invoker.deps)) {
deps += invoker.deps
}
}
}