blob: 234b3400bf4917d095d36959c6b4d4f6f3e3d3ce [file] [log] [blame] [edit]
# 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/sdk/product_bundle.gni")
import("//build/testing/test_spec.gni")
# The test runners have no better way to determine that a boot test succeeded
# than to look for an exact string in the console log output. zbi_test()
# targets produce metadata to drive the test runners, which tells them to
# match this particular string. When booted in standalone mode, userboot
# prints this message after the initial process exits iff its return_code was
# zero, but shutting down. This string includes some random data that
# shouldn't appear elsewhere, to avoid false-positive matches.
boot_test_success_string =
"***Boot-test-successful!-MDd7/O65SuVZ23yGAaQG4CedYQGH9E1/58r73pSAVK0=***"
_all_emu_types = [
"QEMU",
"AEMU",
]
# Helper template defining a boot test for a particular host architecture. This
# flexibility is needed as we wish to define one for emulators on $target_cpu
# hosts even when $target_cpu != $host_cpu in order to take advantage of KVM,
# HVF, etc.
#
# Subtargets
#
# * $target_name.product_bundle
# - The associated product_bundle() target, creating a testing product
# bundle based on the images comprising the boot test.
#
# Parameters
#
# * output_name
# - Optional: The name of the associated test.
# - Default: target_name
#
# * cpu_for_host
# - Required: The host CPU to generate the test for.
#
# See boot_test() for all other parameters.
template("_boot_test") {
main_target = target_name
script_target = "_boot_test.${target_name}.create_script"
toolchain = "//build/toolchain:host_${invoker.cpu_for_host}"
test_script = "$root_out_dir/$main_target.sh"
timeout_secs = 600
if (defined(invoker.timeout)) {
if (invoker.timeout != false) {
timeout_secs = invoker.timeout
}
}
action(script_target) {
visibility = [ ":*" ]
testonly = true
deps = [ "//tools/testing/seriallistener($toolchain)" ]
inputs = [ get_label_info(deps[0], "root_out_dir") + "/seriallistener" ]
outputs = [ test_script ]
script = "//build/testing/create_test.sh"
args = [
rebase_path(outputs[0], root_build_dir),
rebase_path(inputs[0], root_build_dir),
"-success-str",
boot_test_success_string,
"-timeout",
"${timeout_secs}s",
]
metadata = {
test_runtime_deps = []
if (defined(invoker.metadata)) {
forward_variables_from(invoker.metadata, "*")
}
test_runtime_deps += inputs + outputs
}
}
test_spec(main_target) {
target = get_label_info(invoker.label, "label_with_toolchain")
name = target_name
if (defined(invoker.output_name)) {
name = invoker.output_name
}
path = test_script
os = host_os
cpu = invoker.cpu_for_host
isolated = true
forward_variables_from(invoker,
[
"assert_no_deps",
"visibility",
])
timeout_secs = timeout_secs
deps = [ ":$script_target" ]
if (defined(invoker.efi_disk)) {
deps += [ invoker.efi_disk ]
}
if (defined(invoker.qemu_kernel)) {
deps += [ invoker.qemu_kernel ]
}
if (defined(invoker.vbmeta)) {
deps += [ invoker.vbmeta ]
}
if (defined(invoker.zbi)) {
deps += [ invoker.zbi ]
}
image_overrides = {
forward_variables_from(invoker,
[
"efi_disk",
"qemu_kernel",
"vbmeta",
"zbi",
])
# Absolutize the path part in any provided labels.
if (defined(efi_disk)) {
efi_disk = get_label_info(efi_disk, "label_with_toolchain")
}
if (defined(qemu_kernel)) {
qemu_kernel = get_label_info(qemu_kernel, "label_with_toolchain")
}
if (defined(vbmeta)) {
vbmeta = get_label_info(vbmeta, "label_with_toolchain")
}
if (defined(zbi)) {
zbi = get_label_info(zbi, "label_with_toolchain")
}
}
environments = []
foreach(device_type, invoker.device_types) {
environments += [
{
dimensions = {
device_type = device_type
}
},
]
}
}
}
# Specifies a boot test.
#
# A boot test is a general category of test defined by booting select images on
# a device and declaring success if a certain magic string is written by the
# booted system. This set-up allows us to execute test logic in constrained
# environments (e.g., in physical memory or UEFI) that lack finer command-control
# options for driving testing from the outside or a robust means of exfiltrating
# test results for later analysis.
#
# While this template does define host-side test target(s) for listening on
# serial for the success string, the contained logic expects to already be run
# after the associated system has been booted as a 'host-target interaction'
# test, specifically with the environment variables of `$FUCHSIA_SERIAL_SOCKET`
# and `$FUCHSIA_DEVICE_TYPE` set, specifying a Unix socket path from which
# serial can be read and a device type (as spelled in
# //build/testing/environments.gni). This eventually define a test that is
# less geared towards automation, but for now boot tests can be discovered and
# run locally with `fx run-boot-test`.
#
# Parameters:
#
# * device_types
# - Required: A list of device types on which this test is meant to run.
# The full set of device types can be found in
# //build/testing/environments.gni. An empty list signifies a disabled
# test.
# - Type: list of strings
#
# * zbi, qemu_kernel, vbmeta, efi_disk
# - Optional: A label specifying a ZBI, QEMU kernel, VBMeta, UEFI
# executable, or a bootable UEFI filesystem or disk image, respectively.
# At least one of these parameters must be set, but each on their own is
# optional.
# - Type: label
#
# * timeout
# - Optional: The test's timeout, in seconds.
# TODO(ihuh): Once we have more data, we can override this with a more
# sensible timeout for each test.
# - Type: int
# - Default: 600 (10 minutes)
#
# * assert_no_deps, metadata, visibility
# - Optional: Usual GN meanings.
#
template("boot_test") {
assert(defined(invoker.device_types),
"boot_test(\"$target_name\") must define `device_types`")
assert(
defined(invoker.zbi) || defined(invoker.qemu_kernel) ||
defined(invoker.vbmeta) || defined(invoker.efi_disk),
"boot_test(\"$target_name\") must define at least one of `zbi`, `qemu_kernel`, `vbmeta`, `efi_disk`")
main_target = target_name
image_manifest_target = "_boot_test.${target_name}.images_manifest"
product_bundle_target = target_name + ".product_bundle"
generated_file(image_manifest_target) {
forward_variables_from(invoker,
[
"zbi",
"qemu_kernel",
"vbmeta",
])
testonly = true
data_keys = [ "images" ]
output_conversion = "json"
deps = []
if (defined(zbi)) {
deps += [ zbi ]
}
if (defined(vbmeta)) {
deps += [ vbmeta ]
}
if (defined(qemu_kernel)) {
deps += [ qemu_kernel ]
}
# TODO(b/304820366): Uncomment this block when we can create product bundle
# with efi_disk
# if (defined(efi_disk)) {
# deps += [ efi_disk ]
# }
outputs = [ "${target_out_dir}/${main_target}.images.json" ]
}
_partitions_config = "//boards/partitions:default"
if (has_board) {
assert(partitions_config_label != false,
"Need to define partitions_config_label")
_partitions_config = partitions_config_label
}
_partitions_config_file =
get_label_info(_partitions_config, "target_out_dir") + "/" +
get_label_info(_partitions_config, "name") + ".json"
product_bundle(product_bundle_target) {
testonly = true
forward_variables_from(invoker, [ "deps" ])
system_a = ":image_manifest_target"
partitions = _partitions_config_file
deps = [ _partitions_config ]
# This is a testing product bundle, so no need for a scrutiny check for this.
skip_scrutiny = true
skip_scrutiny_recovery = true
# This Product bundle will not be distributed and only for testing purpose,
# so not need to create transfer manifest.
skip_transfer_manifest = true
}
# If host_cpu != target_cpu, then we make sure to define a separate boot
# test for a target_cpu host in order to take advantage of KVM, HVF, etc.
#
# TODO(mcgrathr): No riscv64 hosts are available yet.
if (host_cpu != target_cpu && target_cpu != "riscv64") {
hw_types = invoker.device_types + _all_emu_types - _all_emu_types
emu_types = invoker.device_types - hw_types
common_params = {
forward_variables_from(invoker,
"*",
[
"assert_no_deps",
"device_types",
"visibility",
])
visibility = [ ":*" ]
output_name = main_target
label = ":$main_target"
}
_boot_test("$main_target.emu") {
cpu_for_host = target_cpu
device_types = emu_types
forward_variables_from(common_params, "*")
}
_boot_test("$main_target.hw") {
cpu_for_host = host_cpu
device_types = hw_types
forward_variables_from(common_params, "*")
}
group(main_target) {
forward_variables_from(invoker,
[
"assert_no_deps",
"visibility",
])
testonly = true
deps = [
":$main_target.emu",
":$main_target.hw",
]
}
} else {
_boot_test(main_target) {
label = ":$main_target"
forward_variables_from(invoker, "*")
cpu_for_host = host_cpu
}
}
}