blob: 5a7170b9f8e83fb6854c0584e4d6049ac381da3c [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/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.
#
# Parameters
#
# * 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"
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,
]
metadata = {
test_runtime_deps = inputs + outputs
}
}
test_spec(main_target) {
target = get_label_info(invoker.label, "label_with_toolchain")
path = test_script
os = host_os
cpu = invoker.cpu_for_host
isolated = true
forward_variables_from(invoker,
[
"assert_no_deps",
"visibility",
])
if (defined(invoker.timeout)) {
if (invoker.timeout != false) {
timeout_secs = invoker.timeout
}
} else {
timeout_secs = 600
}
deps = [ ":$script_target" ]
if (defined(invoker.efi)) {
deps += [ invoker.efi ]
}
if (defined(invoker.qemu_kernel)) {
deps += [ invoker.qemu_kernel ]
}
if (defined(invoker.vbmeta)) {
deps += [ invoker.vbmeta ]
}
if (defined(invoker.zbi)) {
deps += [ invoker.zbi ]
}
environments = []
foreach(device_type, invoker.device_types) {
environments += [
{
dimensions = {
device_type = device_type
}
image_overrides = {
forward_variables_from(invoker,
[
"efi",
"qemu_kernel",
"vbmeta",
"zbi",
])
# Absolutize the path part in any provided labels.
if (defined(efi)) {
efi = get_label_info(efi, "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")
}
}
},
]
}
}
}
# 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
# - Optional: A label specifying a ZBI, QEMU kernel, VBMeta, or UEFI
# filesystem to boot, 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)
#
# * visibility, assert_no_deps
# - 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),
"boot_test(\"$target_name\") must define at least one of `zbi`, `qemu_kernel`, `vbmeta`, or `efi`")
hw_types = invoker.device_types + _all_emu_types - _all_emu_types
emu_types = invoker.device_types - hw_types
if (emu_types == [] && hw_types == []) { # Disabled
group(target_name) {
testonly = true
forward_variables_from(invoker,
[
"efi",
"qemu_kernel",
"vbmeta",
"zbi",
])
deps = []
if (defined(efi)) {
deps += [ efi ]
}
if (defined(qemu_kernel)) {
deps += [ qemu_kernel ]
}
if (defined(vbmeta)) {
deps += [ vbmeta ]
}
if (defined(zbi)) {
deps += [ zbi ]
}
}
not_needed(invoker, [ "timeout" ])
} else if (emu_types == [] || host_cpu == target_cpu) {
_boot_test(target_name) {
label = ":$target_name"
forward_variables_from(invoker, "*")
cpu_for_host = host_cpu
}
} else {
common_params = {
forward_variables_from(invoker,
"*",
[
"assert_no_deps",
"device_types",
"visibility",
])
visibility = [ ":*" ]
label = ":$target_name"
}
# If an emulator is specified and $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.
_boot_test("$target_name.emu") {
cpu_for_host = target_cpu
device_types = emu_types
forward_variables_from(common_params, "*")
}
group_deps = [ ":$target_name.emu" ]
if (hw_types != []) {
_boot_test("$target_name.hw") {
cpu_for_host = host_cpu
device_types = hw_types
forward_variables_from(common_params, "*")
}
group_deps += [ ":$target_name.hw" ]
}
group(target_name) {
forward_variables_from(invoker,
[
"assert_no_deps",
"visibility",
])
testonly = true
deps = group_deps
}
}
}