1"""This module defines the android_test macro.""" 2 3load("//bazel:skia_rules.bzl", "skia_cc_binary") 4load("//tools/testrunners/common:binary_wrapper_script_with_cmdline_flags.bzl", "binary_wrapper_script_with_cmdline_flags") 5load("//tools/testrunners/common/android:adb_test.bzl", "adb_test") 6 7def android_test( 8 name, 9 srcs, 10 deps = [], 11 extra_args = [], 12 benchmark = False, 13 requires_resources_dir = False, 14 save_output_files = False): 15 """Defines an Android test. 16 17 Note: This macro is not intended to be used directly in BUILD files. Instead, please use macros 18 android_unit_test, android_gm_test, android_benchmark_test, etc. 19 20 This macro compiles one or more C++ tests into a single Android binary and produces a script 21 that runs the test on an attached Android device via `adb`. This macro is compatible with unit, 22 GM and benchmark tests. 23 24 The test target produced by this macro can be executed on a machine attached to an Android 25 device. This can be either via USB, or by port-forwarding a remote ADB server (TCP port 5037) 26 running on a machine attached to the target device, such as a Skolo Raspberry Pi. 27 28 High-level overview of how this rule works: 29 30 - It produces a <name>.tar.gz archive containing the Android binary, a minimal launcher script 31 that invokes the binary on the device under test with any necessary command-line arguments, 32 and any static resources needed by the C++ tests, such as fonts and images under //resources. 33 - It produces a <name> test runner script that extracts the tarball into the device via `adb`, 34 sets up the device, runs the test, cleans up and pipes through the test's exit code. 35 - Optionally, the <name> test runner script can be configured to download from the device any 36 files produced by the C++ tests (such as PNG and JSON files produced by GM tests). These 37 files will be available as undeclared test outputs (see documentation for the 38 TEST_UNDECLARED_OUTPUTS_DIR environment variable at 39 https://bazel.build/reference/test-encyclopedia#initial-conditions). 40 41 For CI jobs, rather than invoking "bazel test" on a Raspberry Pi attached to the Android device 42 under test, we compile and run the test in two separate tasks: 43 44 - A build task running on a GCE machine compiles the test on RBE with Bazel and stores the 45 <name>.tar.gz and <name> output files to CAS. 46 - A test task running on a Skolo Raspberry Pi downloads <name>.tar.gz and <name> from CAS and 47 executes <name> *outside of Bazel*. 48 49 The reason why we don't want to run Bazel on a Raspberry Pi is due to its constrained 50 resources. 51 52 Note: Although not currently supported, we could use a similar approach for Apple devices in 53 in the future. 54 55 Args: 56 name: The name of the test. 57 srcs: A list of C++ source files. 58 deps: Any dependencies needed by the srcs. 59 extra_args: Additional command-line arguments to pass to the test, for example, any 60 device-specific --skip flags to skip incompatible or buggy test cases. 61 benchmark: Set up the device for benchmark tests. This might affect e.g. CPU and GPU 62 settings specific to the Android device under test. 63 requires_resources_dir: If set, the contents of the //resources directory will be included 64 in the tarball that is pushed to the device via `adb push`, and the test binary will be 65 invoked with flag --resourcePath set to the path to said directory. 66 save_output_files: If true, save any files produced by this test (e.g. PNG and JSON files 67 in the case of GM tests) as undeclared outputs (see documentation for the 68 TEST_UNDECLARED_OUTPUTS_DIR environment variable at 69 https://bazel.build/reference/test-encyclopedia#initial-conditions). 70 """ 71 72 test_binary = "%s_binary" % name 73 74 skia_cc_binary( 75 name = test_binary, 76 srcs = srcs, 77 deps = deps, 78 testonly = True, # Needed to gain access to test-only files. 79 ) 80 81 test_runner = "%s_runner" % name 82 83 binary_wrapper_script_with_cmdline_flags( 84 name = test_runner, 85 binary = test_binary, 86 extra_args = extra_args, 87 requires_resources_dir = requires_resources_dir, 88 testonly = True, # Needed to gain access to test-only files. 89 ) 90 91 archive = "%s_archive" % name 92 archive_srcs = [test_runner, test_binary] + ( 93 ["//resources"] if requires_resources_dir else [] 94 ) 95 96 # Create an archive containing the test and its resources, with a structure that emulates 97 # the environment expected by the test when executed via "bazel test". This archive can be 98 # pushed to an Android device via "adb push", and once extracted, the test binary can be 99 # executed on the device via "adb shell" as long as the working directory is set to the 100 # directory where the archive is extracted. 101 # 102 # See https://bazel.build/reference/test-encyclopedia#initial-conditions. 103 native.genrule( 104 name = archive, 105 srcs = archive_srcs, 106 outs = ["%s.tar.gz" % name], 107 cmd = """ 108 $(location //tools/testrunners/common/make_tarball) \ 109 --execpaths "{execpaths}" \ 110 --rootpaths "{rootpaths}" \ 111 --output-file $@ 112 """.format( 113 execpaths = " ".join(["$(execpaths %s)" % src for src in archive_srcs]), 114 rootpaths = " ".join(["$(rootpaths %s)" % src for src in archive_srcs]), 115 ), 116 testonly = True, # Needed to gain access to test-only files. 117 # Tools are always built for the exec platform 118 # (https://bazel.build/reference/be/general#genrule.tools), e.g. Linux on x86_64 when 119 # running on a gLinux workstation or on a Linux GCE machine. 120 tools = ["//tools/testrunners/common/make_tarball"], 121 ) 122 123 adb_test( 124 name = name, 125 archive = archive, 126 test_runner = test_runner, 127 benchmark = benchmark, 128 save_output_files = save_output_files, 129 tags = ["no-remote"], # Incompatible with RBE because it requires an Android device. 130 target_compatible_with = ["@platforms//os:android"], 131 ) 132