"""This module defines the android_test macro.""" load("//bazel:skia_rules.bzl", "skia_cc_binary") load("//tools/testrunners/common:binary_wrapper_script_with_cmdline_flags.bzl", "binary_wrapper_script_with_cmdline_flags") load("//tools/testrunners/common/android:adb_test.bzl", "adb_test") def android_test( name, srcs, deps = [], extra_args = [], benchmark = False, requires_resources_dir = False, save_output_files = False): """Defines an Android test. Note: This macro is not intended to be used directly in BUILD files. Instead, please use macros android_unit_test, android_gm_test, android_benchmark_test, etc. This macro compiles one or more C++ tests into a single Android binary and produces a script that runs the test on an attached Android device via `adb`. This macro is compatible with unit, GM and benchmark tests. The test target produced by this macro can be executed on a machine attached to an Android device. This can be either via USB, or by port-forwarding a remote ADB server (TCP port 5037) running on a machine attached to the target device, such as a Skolo Raspberry Pi. High-level overview of how this rule works: - It produces a .tar.gz archive containing the Android binary, a minimal launcher script that invokes the binary on the device under test with any necessary command-line arguments, and any static resources needed by the C++ tests, such as fonts and images under //resources. - It produces a test runner script that extracts the tarball into the device via `adb`, sets up the device, runs the test, cleans up and pipes through the test's exit code. - Optionally, the test runner script can be configured to download from the device any files produced by the C++ tests (such as PNG and JSON files produced by GM tests). These files will be available as undeclared test outputs (see documentation for the TEST_UNDECLARED_OUTPUTS_DIR environment variable at https://bazel.build/reference/test-encyclopedia#initial-conditions). For CI jobs, rather than invoking "bazel test" on a Raspberry Pi attached to the Android device under test, we compile and run the test in two separate tasks: - A build task running on a GCE machine compiles the test on RBE with Bazel and stores the .tar.gz and output files to CAS. - A test task running on a Skolo Raspberry Pi downloads .tar.gz and from CAS and executes *outside of Bazel*. The reason why we don't want to run Bazel on a Raspberry Pi is due to its constrained resources. Note: Although not currently supported, we could use a similar approach for Apple devices in in the future. Args: name: The name of the test. srcs: A list of C++ source files. deps: Any dependencies needed by the srcs. extra_args: Additional command-line arguments to pass to the test, for example, any device-specific --skip flags to skip incompatible or buggy test cases. benchmark: Set up the device for benchmark tests. This might affect e.g. CPU and GPU settings specific to the Android device under test. requires_resources_dir: If set, the contents of the //resources directory will be included in the tarball that is pushed to the device via `adb push`, and the test binary will be invoked with flag --resourcePath set to the path to said directory. save_output_files: If true, save any files produced by this test (e.g. PNG and JSON files in the case of GM tests) as undeclared outputs (see documentation for the TEST_UNDECLARED_OUTPUTS_DIR environment variable at https://bazel.build/reference/test-encyclopedia#initial-conditions). """ test_binary = "%s_binary" % name skia_cc_binary( name = test_binary, srcs = srcs, deps = deps, testonly = True, # Needed to gain access to test-only files. ) test_runner = "%s_runner" % name binary_wrapper_script_with_cmdline_flags( name = test_runner, binary = test_binary, extra_args = extra_args, requires_resources_dir = requires_resources_dir, testonly = True, # Needed to gain access to test-only files. ) archive = "%s_archive" % name archive_srcs = [test_runner, test_binary] + ( ["//resources"] if requires_resources_dir else [] ) # Create an archive containing the test and its resources, with a structure that emulates # the environment expected by the test when executed via "bazel test". This archive can be # pushed to an Android device via "adb push", and once extracted, the test binary can be # executed on the device via "adb shell" as long as the working directory is set to the # directory where the archive is extracted. # # See https://bazel.build/reference/test-encyclopedia#initial-conditions. native.genrule( name = archive, srcs = archive_srcs, outs = ["%s.tar.gz" % name], cmd = """ $(location //tools/testrunners/common/make_tarball) \ --execpaths "{execpaths}" \ --rootpaths "{rootpaths}" \ --output-file $@ """.format( execpaths = " ".join(["$(execpaths %s)" % src for src in archive_srcs]), rootpaths = " ".join(["$(rootpaths %s)" % src for src in archive_srcs]), ), testonly = True, # Needed to gain access to test-only files. # Tools are always built for the exec platform # (https://bazel.build/reference/be/general#genrule.tools), e.g. Linux on x86_64 when # running on a gLinux workstation or on a Linux GCE machine. tools = ["//tools/testrunners/common/make_tarball"], ) adb_test( name = name, archive = archive, test_runner = test_runner, benchmark = benchmark, save_output_files = save_output_files, tags = ["no-remote"], # Incompatible with RBE because it requires an Android device. target_compatible_with = ["@platforms//os:android"], )