blob: dc45e2ff22789a92af48b96e9f7d908ca67b9f6f [file]
# Copyright 2026 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.
"""Starlark macros for defining Fuchsia system test suites (upgrade, reboot, recovery).
This is the Bazel port of //src/sys/pkg/tests/system-tests/system-tests.gni.
"""
load("//build/bazel/rules/host_tests:host_test.bzl", "host_test")
load(
"//build/bazel/rules/testing:fx_test_environment.bzl",
"FxTestEnvironmentInfo",
)
visibility("private")
# The default service account that allows system tests to download build artifacts.
DEFAULT_SERVICE_ACCOUNT = (
"artifact-readers" + "@" + "fuchsia-infra.iam.gserviceaccount.com"
)
# Environment tag used in GN's disabled_env to prevent infra from scheduling raw binaries.
DISABLED_ENV_TAG = "system-tests-disabled"
# Default runtime test_data dependencies shared across all system test suites.
# Note: `//src/sys/pkg/tests/system-tests:test_data` currently stages AVB keys
# and `test_private_key.pem`; `artifacts`, `lkg`, `mock-omaha-server`, and `zbi`
# from GN `test_tools` (in //src/sys/pkg/tests/system-tests/BUILD.gn and
# //src/testing/host-target-testing/omaha_tool/BUILD.gn) are pending Bazel
# migration/export prerequisites (see `SYSTEM_TESTS_TOOLS_DATA`).
DEFAULT_SYSTEM_TESTS_DATA = [
"//src/sys/pkg/tests/system-tests:non_go_deps",
]
# Host tool binaries staged into `test_data/system-tests/` by GN `test_tools`
# (in //src/sys/pkg/tests/system-tests/BUILD.gn and
# //src/testing/host-target-testing/omaha_tool/BUILD.gn).
# Merge `SYSTEM_TESTS_TOOLS_DATA` into `//src/sys/pkg/tests/system-tests:test_data`
# `files_map` once these targets (including `cipd_prebuilt_file` targets for
# `//prebuilt/tools/artifacts/artifacts` and `//prebuilt/tools/lkg/lkg`) are
# migrated/exported in Bazel.
SYSTEM_TESTS_TOOLS_DATA = {
"test_data/system-tests/artifacts": "//src/sys/pkg/tests/system-tests:artifacts",
"test_data/system-tests/lkg": "//src/sys/pkg/tests/system-tests:lkg",
"test_data/system-tests/mock-omaha-server": "//src/sys/pkg/testing/mock-omaha-server:bin",
"test_data/system-tests/zbi": "//zircon/tools/zbi",
}
# ffx host_test_data targets required at runtime by system-tests (ported in parallel).
# Add `FFX_SYSTEM_TESTS_DATA` to `//src/sys/pkg/tests/system-tests:non_go_deps` (or pass via
# `extra_test_data = FFX_SYSTEM_TESTS_DATA`) once those targets are available in Bazel.
FFX_SYSTEM_TESTS_DATA = [
"//src/developer/ffx:test_data",
"//src/developer/ffx/plugins/component:ffx_component_tool_test_data",
"//src/developer/ffx/plugins/emulator:ffx_emulator_tool_test_data",
"//src/developer/ffx/plugins/inspect:ffx_inspect_tool_test_data",
"//src/developer/ffx/plugins/log:ffx_log_tool_test_data",
"//src/developer/ffx/plugins/package:ffx_package_tool_test_data",
"//src/developer/ffx/plugins/product:ffx_product_tool_test_data",
"//src/developer/ffx/plugins/product_bundle:ffx_product_bundle_tool_test_data",
"//src/developer/ffx/plugins/repository:ffx_repository_tool_test_data",
]
SystemTestSuiteMetadataInfo = provider(
doc = "Infra scheduling and invocation metadata for a system_test_*_suite() target.",
fields = {
"suite_name": "Name of the system test suite.",
"test_binary": "Name of the underlying Go system test binary.",
"test_args": "CLI flags passed to the underlying Go system test binary.",
"timeout": "Go test timeout duration string.",
"service_account": "Service account injected into all test environments.",
"environments": "List of normalized environment dicts (dimensions, tags, service_account).",
"metadata_json": "Generated JSON File recording the resolved environments and invocation spec.",
},
)
def _system_test_metadata_impl(ctx):
inline_envs = json.decode(ctx.attr.inline_environments)
resolved_envs = []
seen = {}
for raw_env in inline_envs:
env = dict(raw_env)
env["service_account"] = ctx.attr.service_account
key = json.encode(env)
if key not in seen:
seen[key] = True
resolved_envs.append(env)
for target in ctx.attr.environment_targets:
env = dict(target[FxTestEnvironmentInfo].environment)
env["service_account"] = ctx.attr.service_account
key = json.encode(env)
if key not in seen:
seen[key] = True
resolved_envs.append(env)
if not resolved_envs:
fail("environments must not be empty for {}".format(ctx.attr.suite_name))
out = ctx.actions.declare_file(ctx.attr.name + ".json")
payload = {
"environments": resolved_envs,
"service_account": ctx.attr.service_account,
"suite_name": ctx.attr.suite_name,
"test_args": ctx.attr.test_args,
"test_binary": ctx.attr.test_binary,
"timeout": ctx.attr.test_timeout,
}
ctx.actions.write(
output = out,
content = json.encode_indent(payload, indent = " ") + "\n",
)
return [
DefaultInfo(
files = depset([out]),
runfiles = ctx.runfiles(files = [out]),
),
SystemTestSuiteMetadataInfo(
suite_name = ctx.attr.suite_name,
test_binary = ctx.attr.test_binary,
test_args = ctx.attr.test_args,
timeout = ctx.attr.test_timeout,
service_account = ctx.attr.service_account,
environments = resolved_envs,
metadata_json = out,
),
]
_system_test_metadata = rule(
implementation = _system_test_metadata_impl,
doc = "Records infra environment dimensions, tags, timeout, and service_account metadata for a system test suite.",
provides = [SystemTestSuiteMetadataInfo],
attrs = {
"suite_name": attr.string(mandatory = True),
"test_binary": attr.string(mandatory = True),
"test_args": attr.string_list(default = []),
"test_timeout": attr.string(mandatory = True),
"service_account": attr.string(mandatory = True),
"inline_environments": attr.string(default = "[]"),
"environment_targets": attr.label_list(
providers = [FxTestEnvironmentInfo],
default = [],
),
},
)
def _require_non_empty_str(val, field_name, target_name, allow_int = False):
if allow_int and type(val) == "int":
return str(val)
if type(val) != "string" or val == "":
fail("'{}' cannot have an empty {}".format(target_name, field_name))
return val
def _normalize_environments(name, environments, service_account):
if environments == None or len(environments) == 0:
fail("environments must be defined and non-empty for {}".format(name))
inline_envs = []
env_targets = []
derived_tags = ["service_account:" + service_account]
for env in environments:
if type(env) == "dict":
dimensions = env.get("dimensions")
if type(dimensions) != "dict" or not dimensions:
fail("environment dict in '{}' must define a non-empty 'dimensions' dict".format(name))
normalized = {
"dimensions": dict(dimensions),
"service_account": service_account,
}
env_tags = env.get("tags", env.get("env_tags"))
if env_tags:
normalized["tags"] = list(env_tags)
for tag in env_tags:
tag_entry = "env_tag:" + tag
if tag_entry not in derived_tags:
derived_tags.append(tag_entry)
if "device_type" in dimensions:
dt_entry = "device_type:" + dimensions["device_type"]
if dt_entry not in derived_tags:
derived_tags.append(dt_entry)
if env.get("emulator"):
normalized["emulator"] = dict(env["emulator"])
if env.get("netboot"):
normalized["netboot"] = True
inline_envs.append(normalized)
elif type(env) == "string":
env_targets.append(env)
else:
fail("environments entry in '{}' must be an environment dict or fx_test_environment label string, got {}".format(
name,
type(env),
))
return inline_envs, env_targets, derived_tags
def _dedupe_labels(labels):
result = []
seen = {}
for label in labels:
if label not in seen:
seen[label] = True
result.append(label)
return result
def _define_system_test_suite(
*,
name,
test_binary_name,
test_binary_data,
args,
environments,
service_account,
timeout,
test_data,
extra_test_data,
tags,
visibility):
host_test_target_name = "{}_{}".format(name, test_binary_name)
metadata_target_name = "{}_metadata".format(host_test_target_name)
resolved_service_account = DEFAULT_SERVICE_ACCOUNT
if service_account != None:
resolved_service_account = _require_non_empty_str(
service_account,
"service_account",
host_test_target_name,
)
resolved_timeout = "5m"
if timeout != None:
resolved_timeout = _require_non_empty_str(
timeout,
"timeout",
host_test_target_name,
)
inline_envs, env_targets, derived_tags = _normalize_environments(
name = name,
environments = environments,
service_account = resolved_service_account,
)
base_test_data = DEFAULT_SYSTEM_TESTS_DATA if test_data == None else list(test_data)
all_data = _dedupe_labels(
[
test_binary_data,
":" + metadata_target_name,
] + base_test_data + list(extra_test_data),
)
tags = list(tags)
if "manual" not in tags:
tags.append("manual")
host_test_tags = list(tags)
for t in derived_tags:
if t not in host_test_tags:
host_test_tags.append(t)
# System tests are Linux-only, matching `assert(is_linux, ...)` in system-tests.gni.
linux_only = ["@platforms//os:linux"]
_system_test_metadata(
name = metadata_target_name,
testonly = True,
suite_name = name,
test_binary = test_binary_name,
test_args = args,
test_timeout = resolved_timeout,
service_account = resolved_service_account,
inline_environments = json.encode(inline_envs),
environment_targets = env_targets,
target_compatible_with = linux_only,
visibility = visibility,
)
# Wrap the Go system test binary with //tools/go_test_parser, matching host_go_test.bzl
# and //build/go/go_test.gni.
wrapped_test_args = [
"./" + test_binary_name,
"-test.timeout",
resolved_timeout,
"-test.v",
] + args
host_test(
name = host_test_target_name,
binary = "//tools/go_test_parser:go_test_parser",
test_args = wrapped_test_args,
data = all_data,
tags = host_test_tags,
target_compatible_with = linux_only,
visibility = visibility,
)
native.test_suite(
name = name,
tests = [":" + host_test_target_name],
tags = list(tags),
visibility = visibility,
)
def system_test_upgrade_suite(
name,
environments,
builds = None,
downgrade_release_builder = None,
downgrade_release_build_id = None,
downgrade_ota_attempts = None,
upgrade_release_builder = None,
upgrade_release_build_id = None,
installer = None,
service_account = None,
timeout = None,
pave_timeout = None,
cycle_timeout = None,
cycle_count = None,
device_connect_timeout = None,
workaround_broken_time_skip = False,
workaround_downgrade_ota_no_rewrite_rules = False,
require_cup = False,
use_flash = False,
build_expect_unknown_firmware = False,
max_system_image_size = None,
max_update_images_size = None,
max_update_package_size = None,
bootfs_compression = None,
check_abr = True,
resolver_mode = None,
extra_args = [],
test_data = None,
extra_test_data = [],
tags = [],
visibility = None):
"""Configures a System Test Upgrade Suite (Bazel port of system_test_upgrade_suite in system-tests.gni).
Generates:
- `<name>_system_tests_upgrade_metadata`: JSON metadata & SystemTestSuiteMetadataInfo provider
recording environments, dimensions, tags, timeout, and service_account.
- `<name>_system_tests_upgrade`: `host_test` wrapping `system_tests_upgrade` via `go_test_parser`.
- `<name>`: `test_suite` grouping the generated host test target.
Args:
name: Name of the system test suite target.
environments: List of environment dicts or fx_test_environment labels.
builds: Optional list of build dicts with release_builder or release_build_id.
downgrade_release_builder: Optional downgrade release builder name.
downgrade_release_build_id: Optional downgrade release build ID.
downgrade_ota_attempts: Optional number of downgrade OTA attempts.
upgrade_release_builder: Optional upgrade release builder name.
upgrade_release_build_id: Optional upgrade release build ID.
installer: Optional OTA installer name.
service_account: Optional service account for artifact downloads.
timeout: Optional test timeout duration string.
pave_timeout: Optional pave timeout duration string.
cycle_timeout: Optional cycle timeout duration string.
cycle_count: Optional number of test cycles.
device_connect_timeout: Optional device connect timeout duration string.
workaround_broken_time_skip: Whether to enable broken time skip workaround.
workaround_downgrade_ota_no_rewrite_rules: Whether to skip rewrite rules on downgrade OTA.
require_cup: Whether mock-omaha-server requires CUP.
use_flash: Whether to use ffx flash instead of paving.
build_expect_unknown_firmware: Whether to expect unknown firmware during build.
max_system_image_size: Optional maximum system image size.
max_update_images_size: Optional maximum update images size.
max_update_package_size: Optional maximum update package size.
bootfs_compression: Optional bootfs compression setting.
check_abr: Whether to check ABR slot after boot.
resolver_mode: Optional resolver mode string.
extra_args: Additional CLI flags passed to the test binary.
test_data: Optional replacement list of base runtime test_data labels.
extra_test_data: Additional runtime test_data labels.
tags: Additional Bazel tags applied to generated targets.
visibility: Visibility applied to generated targets.
"""
if downgrade_release_builder != None and downgrade_release_build_id != None:
fail("downgrade_release_builder and downgrade_release_build_id are mutually exclusive for {}".format(name))
if upgrade_release_builder != None and upgrade_release_build_id != None:
fail("upgrade_release_builder and upgrade_release_build_id are mutually exclusive for {}".format(name))
if builds != None and downgrade_release_builder != None:
fail("builds is mutually exclusive with downgrade_release_builder for {}".format(name))
if builds != None and downgrade_release_build_id != None:
fail("builds is mutually exclusive with downgrade_release_build_id for {}".format(name))
if builds != None and upgrade_release_builder != None:
fail("builds is mutually exclusive with upgrade_release_builder for {}".format(name))
if builds != None and upgrade_release_build_id != None:
fail("builds is mutually exclusive with upgrade_release_build_id for {}".format(name))
resolved_builds = []
if builds != None:
for build in builds:
if type(build) != "dict":
fail("each entry in builds must be a dict for {}".format(name))
has_builder = build.get("release_builder") != None
has_build_id = build.get("release_build_id") != None
if not has_builder and not has_build_id:
fail("release_builder or release_build_id must be defined for {}".format(name))
if has_builder and has_build_id:
fail("release_builder and release_build_id are mutually exclusive for {}".format(name))
resolved_builds.append(build)
else:
if downgrade_release_builder != None:
resolved_builds.append({"release_builder": downgrade_release_builder})
elif downgrade_release_build_id != None:
resolved_builds.append({"release_build_id": downgrade_release_build_id})
if upgrade_release_builder != None:
resolved_builds.append({"release_builder": upgrade_release_builder})
elif upgrade_release_build_id != None:
resolved_builds.append({"release_build_id": upgrade_release_build_id})
if not resolved_builds:
fail("upgrade builds must be specified for {}".format(name))
host_test_target_name = "{}_system_tests_upgrade".format(name)
args = []
for build in resolved_builds:
if build.get("release_build_id") != None:
args.extend([
"--build-id",
_require_non_empty_str(build["release_build_id"], "release_build_id", host_test_target_name),
])
if build.get("release_builder") != None:
args.extend([
"--builder-name",
_require_non_empty_str(build["release_builder"], "release_builder", host_test_target_name),
])
if downgrade_ota_attempts != None:
args.extend([
"-downgrade-ota-attempts",
_require_non_empty_str(
downgrade_ota_attempts,
"downgrade_ota_attempts",
host_test_target_name,
allow_int = True,
),
])
if pave_timeout != None:
args.extend([
"-pave-timeout",
_require_non_empty_str(pave_timeout, "pave timeout", host_test_target_name),
])
if cycle_timeout != None:
args.extend([
"-cycle-timeout",
_require_non_empty_str(cycle_timeout, "cycle timeout", host_test_target_name),
])
if cycle_count != None:
args.extend([
"-cycle-count",
_require_non_empty_str(cycle_count, "cycle count", host_test_target_name, allow_int = True),
])
if installer != None:
args.extend([
"-installer",
_require_non_empty_str(installer, "installer", host_test_target_name),
])
if device_connect_timeout != None:
args.extend([
"-device-connect-timeout",
_require_non_empty_str(device_connect_timeout, "device connect timeout", host_test_target_name),
])
if workaround_broken_time_skip:
args.append("-workaround-broken-time-skip")
if workaround_downgrade_ota_no_rewrite_rules:
args.append("-workaround-downgrade-ota-no-rewrite-rules")
if require_cup:
args.append("-require-cup")
if use_flash:
args.append("-use-flash")
if build_expect_unknown_firmware:
args.append("-build-expect-unknown-firmware")
if max_system_image_size != None:
args.extend([
"-max-system-image-size",
_require_non_empty_str(
max_system_image_size,
"max_system_image_size",
host_test_target_name,
allow_int = True,
),
])
if max_update_images_size != None:
args.extend([
"-max-update-images-size",
_require_non_empty_str(
max_update_images_size,
"max_update_images_size",
host_test_target_name,
allow_int = True,
),
])
if max_update_package_size != None:
args.extend([
"-max-update-package-size",
_require_non_empty_str(
max_update_package_size,
"max_update_package_size",
host_test_target_name,
allow_int = True,
),
])
if bootfs_compression != None:
args.extend([
"-bootfs-compression",
_require_non_empty_str(bootfs_compression, "bootfs_compression", host_test_target_name),
])
if check_abr:
args.append("--check-abr=true")
else:
args.append("--check-abr=false")
if resolver_mode != None:
args.append("--resolver-mode=" + _require_non_empty_str(resolver_mode, "resolver_mode", host_test_target_name))
else:
args.append("--resolver-mode=constant")
args.extend(extra_args)
_define_system_test_suite(
name = name,
test_binary_name = "system_tests_upgrade",
test_binary_data = "//src/sys/pkg/tests/system-tests/upgrade_test:system_tests_upgrade.test_data",
args = args,
environments = environments,
service_account = service_account,
timeout = timeout,
test_data = test_data,
extra_test_data = extra_test_data,
tags = tags,
visibility = visibility,
)
def system_test_reboot_suite(
name,
environments,
release_builder = None,
release_build_id = None,
service_account = None,
timeout = None,
pave_timeout = None,
cycle_timeout = None,
cycle_count = None,
device_connect_timeout = None,
sleep_after_reboot = None,
use_flash = False,
check_abr = True,
resolver_mode = None,
extra_args = [],
test_data = None,
extra_test_data = [],
tags = [],
visibility = None):
"""Configures a System Test Reboot Suite (Bazel port of system_test_reboot_suite in system-tests.gni).
Generates:
- `<name>_system_tests_reboot_metadata`: JSON metadata & SystemTestSuiteMetadataInfo provider.
- `<name>_system_tests_reboot`: `host_test` wrapping `system_tests_reboot` via `go_test_parser`.
- `<name>`: `test_suite` grouping the generated host test target.
Args:
name: Name of the system test suite target.
environments: List of environment dicts or fx_test_environment labels.
release_builder: Optional release builder name.
release_build_id: Optional release build ID.
service_account: Optional service account for artifact downloads.
timeout: Optional test timeout duration string.
pave_timeout: Optional pave timeout duration string.
cycle_timeout: Optional cycle timeout duration string.
cycle_count: Optional number of test cycles.
device_connect_timeout: Optional device connect timeout duration string.
sleep_after_reboot: Optional duration to sleep after reboot.
use_flash: Whether to use ffx flash instead of paving.
check_abr: Whether to check ABR slot after boot.
resolver_mode: Optional resolver mode string.
extra_args: Additional CLI flags passed to the test binary.
test_data: Optional replacement list of base runtime test_data labels.
extra_test_data: Additional runtime test_data labels.
tags: Additional Bazel tags applied to generated targets.
visibility: Visibility applied to generated targets.
"""
if release_builder != None and release_build_id != None:
fail("release_builder and release_build_id are mutually exclusive for {}".format(name))
host_test_target_name = "{}_system_tests_reboot".format(name)
args = []
if release_builder != None:
args.extend([
"-builder-name",
_require_non_empty_str(release_builder, "release_builder", host_test_target_name),
])
if release_build_id != None:
args.extend([
"-build-id",
_require_non_empty_str(release_build_id, "release_build_id", host_test_target_name),
])
if pave_timeout != None:
args.extend([
"-pave-timeout",
_require_non_empty_str(pave_timeout, "pave timeout", host_test_target_name),
])
if cycle_timeout != None:
args.extend([
"-cycle-timeout",
_require_non_empty_str(cycle_timeout, "cycle timeout", host_test_target_name),
])
if cycle_count != None:
args.extend([
"-cycle-count",
_require_non_empty_str(cycle_count, "cycle count", host_test_target_name, allow_int = True),
])
if device_connect_timeout != None:
args.extend([
"-device-connect-timeout",
_require_non_empty_str(device_connect_timeout, "device connect timeout", host_test_target_name),
])
if sleep_after_reboot != None:
args.extend([
"-sleep-after-reboot",
_require_non_empty_str(sleep_after_reboot, "sleep after reboot", host_test_target_name),
])
if use_flash:
args.append("-use-flash")
if check_abr:
args.append("--check-abr=true")
else:
args.append("--check-abr=false")
if resolver_mode != None:
args.append("--resolver-mode=" + _require_non_empty_str(resolver_mode, "resolver_mode", host_test_target_name))
args.extend(extra_args)
_define_system_test_suite(
name = name,
test_binary_name = "system_tests_reboot",
test_binary_data = "//src/sys/pkg/tests/system-tests/reboot_test:system_tests_reboot.test_data",
args = args,
environments = environments,
service_account = service_account,
timeout = timeout,
test_data = test_data,
extra_test_data = extra_test_data,
tags = tags,
visibility = visibility,
)
def system_test_recovery_suite(
name,
environments,
release_builder = None,
release_build_id = None,
service_account = None,
timeout = None,
pave_timeout = None,
cycle_timeout = None,
cycle_count = None,
device_connect_timeout = None,
use_flash = False,
check_abr = True,
resolver_mode = None,
extra_args = [],
test_data = None,
extra_test_data = [],
tags = [],
visibility = None):
"""Configures a System Test Recovery Suite (Bazel port of system_test_recovery_suite in system-tests.gni).
Generates:
- `<name>_system_tests_recovery_metadata`: JSON metadata & SystemTestSuiteMetadataInfo provider.
- `<name>_system_tests_recovery`: `host_test` wrapping `system_tests_recovery` via `go_test_parser`.
- `<name>`: `test_suite` grouping the generated host test target.
Args:
name: Name of the system test suite target.
environments: List of environment dicts or fx_test_environment labels.
release_builder: Optional release builder name.
release_build_id: Optional release build ID.
service_account: Optional service account for artifact downloads.
timeout: Optional test timeout duration string.
pave_timeout: Optional pave timeout duration string.
cycle_timeout: Optional cycle timeout duration string.
cycle_count: Optional number of test cycles.
device_connect_timeout: Optional device connect timeout duration string.
use_flash: Whether to use ffx flash instead of paving.
check_abr: Whether to check ABR slot after boot.
resolver_mode: Optional resolver mode string.
extra_args: Additional CLI flags passed to the test binary.
test_data: Optional replacement list of base runtime test_data labels.
extra_test_data: Additional runtime test_data labels.
tags: Additional Bazel tags applied to generated targets.
visibility: Visibility applied to generated targets.
"""
if release_builder != None and release_build_id != None:
fail("release_builder and release_build_id are mutually exclusive for {}".format(name))
host_test_target_name = "{}_system_tests_recovery".format(name)
args = []
if release_builder != None:
args.extend([
"-builder-name",
_require_non_empty_str(release_builder, "release_builder", host_test_target_name),
])
if release_build_id != None:
args.extend([
"-build-id",
_require_non_empty_str(release_build_id, "release_build_id", host_test_target_name),
])
if pave_timeout != None:
args.extend([
"-pave-timeout",
_require_non_empty_str(pave_timeout, "pave timeout", host_test_target_name),
])
if cycle_timeout != None:
args.extend([
"-cycle-timeout",
_require_non_empty_str(cycle_timeout, "cycle timeout", host_test_target_name),
])
if cycle_count != None:
args.extend([
"-cycle-count",
_require_non_empty_str(cycle_count, "cycle count", host_test_target_name, allow_int = True),
])
if device_connect_timeout != None:
args.extend([
"-device-connect-timeout",
_require_non_empty_str(device_connect_timeout, "device connect timeout", host_test_target_name),
])
if use_flash:
args.append("-use-flash")
if check_abr:
args.append("--check-abr=true")
else:
args.append("--check-abr=false")
if resolver_mode != None:
args.append("--resolver-mode=" + _require_non_empty_str(resolver_mode, "resolver_mode", host_test_target_name))
args.extend(extra_args)
_define_system_test_suite(
name = name,
test_binary_name = "system_tests_recovery",
test_binary_data = "//src/sys/pkg/tests/system-tests/recovery_test:system_tests_recovery.test_data",
args = args,
environments = environments,
service_account = service_account,
timeout = timeout,
test_data = test_data,
extra_test_data = extra_test_data,
tags = tags,
visibility = visibility,
)