From bfcc52e0b9f4a947ce11b08af2e2b06c00c49de2 Mon Sep 17 00:00:00 2001 From: Byoungchan Lee Date: Thu, 30 Apr 2026 10:39:53 +0900 Subject: [PATCH 1/3] android-instrumentation-testing: Setup project and add basic java target --- android/instrumentation-testing/.bazelrc | 3 +++ android/instrumentation-testing/.bazelversion | 1 + android/instrumentation-testing/MODULE.bazel | 3 +++ .../app/src/main/AndroidManifest.xml | 2 ++ .../instrumentation-testing/app/src/main/BUILD.bazel | 9 +++++++++ .../com/example/android/instrumentation/Greeter.java | 11 +++++++++++ 6 files changed, 29 insertions(+) create mode 100644 android/instrumentation-testing/.bazelrc create mode 100644 android/instrumentation-testing/.bazelversion create mode 100644 android/instrumentation-testing/MODULE.bazel create mode 100644 android/instrumentation-testing/app/src/main/AndroidManifest.xml create mode 100644 android/instrumentation-testing/app/src/main/BUILD.bazel create mode 100644 android/instrumentation-testing/app/src/main/java/com/example/android/instrumentation/Greeter.java diff --git a/android/instrumentation-testing/.bazelrc b/android/instrumentation-testing/.bazelrc new file mode 100644 index 000000000..f78e7f9e4 --- /dev/null +++ b/android/instrumentation-testing/.bazelrc @@ -0,0 +1,3 @@ +common --enable_bzlmod + +try-import %workspace%/.bazelrc.user diff --git a/android/instrumentation-testing/.bazelversion b/android/instrumentation-testing/.bazelversion new file mode 100644 index 000000000..47da986f8 --- /dev/null +++ b/android/instrumentation-testing/.bazelversion @@ -0,0 +1 @@ +9.1.0 diff --git a/android/instrumentation-testing/MODULE.bazel b/android/instrumentation-testing/MODULE.bazel new file mode 100644 index 000000000..876e7bf03 --- /dev/null +++ b/android/instrumentation-testing/MODULE.bazel @@ -0,0 +1,3 @@ +module(name = "android_instrumentation_testing") + +bazel_dep(name = "rules_android", version = "0.7.2") diff --git a/android/instrumentation-testing/app/src/main/AndroidManifest.xml b/android/instrumentation-testing/app/src/main/AndroidManifest.xml new file mode 100644 index 000000000..7f5abafe2 --- /dev/null +++ b/android/instrumentation-testing/app/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + diff --git a/android/instrumentation-testing/app/src/main/BUILD.bazel b/android/instrumentation-testing/app/src/main/BUILD.bazel new file mode 100644 index 000000000..378ae4a73 --- /dev/null +++ b/android/instrumentation-testing/app/src/main/BUILD.bazel @@ -0,0 +1,9 @@ +load("@rules_android//android:rules.bzl", "android_library") + +android_library( + name = "greeter_lib", + srcs = ["java/com/example/android/instrumentation/Greeter.java"], + custom_package = "com.example.android.instrumentation", + manifest = "AndroidManifest.xml", + visibility = ["//visibility:public"], +) diff --git a/android/instrumentation-testing/app/src/main/java/com/example/android/instrumentation/Greeter.java b/android/instrumentation-testing/app/src/main/java/com/example/android/instrumentation/Greeter.java new file mode 100644 index 000000000..0d62b8899 --- /dev/null +++ b/android/instrumentation-testing/app/src/main/java/com/example/android/instrumentation/Greeter.java @@ -0,0 +1,11 @@ +package com.example.android.instrumentation; + +public final class Greeter { + public String greet(String name) { + String normalizedName = name == null ? "" : name.trim(); + if (normalizedName.isEmpty()) { + return "Hello, Android!"; + } + return "Hello, " + normalizedName + "!"; + } +} From 700bd8801db2394f53b3ca72016ebd99bcb5e769 Mon Sep 17 00:00:00 2001 From: Byoungchan Lee Date: Thu, 30 Apr 2026 21:16:14 +0900 Subject: [PATCH 2/3] android-instrumentation-testing: Add local-device test sample Add a Bzlmod-only Android instrumentation testing sample that builds a small Java Android app and runs an AndroidX/JUnit4 instrumentation test on a connected local device. Add a small Starlark android_instrumentation_test rule that consumes rules_android's ApkInfo and AndroidInstrumentationInfo providers. The rule adds the target APK, instrumentation APK, Android SDK tools, and AndroidX Test host-side runner to runfiles, then leaves local device selection to the local_device Bazel config. Vendor AndroidX Test through a separate third_party/android-test Bazel module and repository-rule overlay. Keeping AndroidX Test in its own module avoids forcing the root sample module to carry AndroidX Test's dependency graph and overrides directly. Patch the generated AndroidX Test repository for local retail devices: make dalvik.vm.dexopt-flags updates best-effort because upstream assumes a rooted/userdebug device, and fall back to /data/anr/traces.txt when dalvik.vm.stack-trace-file is absent. The sample also uses @RunWith(AndroidJUnit4.class) so AndroidX Test's dex parser discovers JUnit4 methods without relying on legacy android.test APIs. Pass Bazel's Android SDK dexdump into the AndroidX Test host runner instead of using AndroidX Test's embedded Linux dexdump_annotations resource. The embedded binary does not run on macOS, which breaks local device test discovery before instrumentation starts. Overlay TestInfoRepository so the generated AndroidX Test repository uses modern SDK-compatible dexdump arguments, canonicalizes APK paths before invoking dexdump, and normalizes the modern annotation preamble back into the XML shape expected by AndroidX Test's legacy parser. Add a focused normalizer test that feeds the normalized output through DumpUtils.parseDexDump. This covers both JUnit4 annotation discovery and the dalvik.annotation.AnnotationDefault parser behavior needed after switching away from the embedded binary. --- android/instrumentation-testing/.bazelignore | 1 + android/instrumentation-testing/.bazelrc | 7 + android/instrumentation-testing/MODULE.bazel | 12 + .../app/src/main/AndroidManifest.xml | 9 +- .../app/src/main/AndroidTestManifest.xml | 13 + .../app/src/main/BUILD.bazel | 30 +- .../GreeterInstrumentationTest.java | 20 ++ .../instrumentation-testing/bazel/BUILD.bazel | 1 + .../bazel/android_instrumentation_test.bzl | 117 +++++++ .../bazel/android_instrumentation_test.sh.tpl | 91 +++++ .../third_party/android-test/.bazelignore | 1 + .../third_party/android-test/BUILD.bazel | 0 .../third_party/android-test/MODULE.bazel | 108 ++++++ .../third_party/android-test/extensions.bzl | 8 + .../third_party/android-test/overlay/BUILD | 67 ++++ .../maven/axt_android_aar.bzl | 129 ++++++++ .../build_extensions/maven/axt_maven_apk.bzl | 40 +++ .../build_extensions/maven/maven_info.bzl | 211 ++++++++++++ .../android-test/overlay/opensource/BUILD | 33 ++ .../overlay/opensource/androidx/BUILD | 29 ++ .../overlay/opensource/auto_value/BUILD | 19 ++ .../overlay/opensource/dagger/BUILD | 30 ++ .../java/androidx/test/BUILD | 98 ++++++ .../java/androidx/test/orchestrator/BUILD | 46 +++ .../android_test_orchestrator/stubapp/BUILD | 44 +++ .../runner/monitor/java/androidx/test/BUILD | 136 ++++++++ .../android-test/overlay/services/BUILD | 57 ++++ .../java/androidx/test/services/events/BUILD | 31 ++ .../overlay/services/proguard_library.cfg | 55 +++ .../overlay/services/shellexecutor/BUILD | 31 ++ .../test/services/shellexecutor/BUILD | 115 +++++++ .../androidx/test/services/speakeasy/BUILD | 16 + .../test/services/speakeasy/client/BUILD | 62 ++++ .../speakeasy/compilehelp/hidden_api/BUILD | 32 ++ .../test/services/speakeasy/server/BUILD | 46 +++ .../java/androidx/test/services/storage/BUILD | 95 ++++++ .../androidx/test/services/storage/file/BUILD | 22 ++ .../test/services/storage/provider/BUILD | 22 ++ .../tools/android/emulator/BUILD.bazel | 313 ++++++++++++++++++ .../apps/common/testing/broker/BUILD.bazel | 311 +++++++++++++++++ .../broker/LocalAdbServerDeviceBroker.java | 292 ++++++++++++++++ .../broker/ModernDexDumpOutputNormalizer.java | 141 ++++++++ .../ModernDexDumpOutputNormalizerTest.java | 176 ++++++++++ .../testing/broker/TestInfoRepository.java | 300 +++++++++++++++++ .../common/testing/broker/shell/BUILD.bazel | 15 + .../testing/suite/AndroidDeviceTestSuite.java | 253 ++++++++++++++ .../apps/common/testing/suite/BUILD.bazel | 59 ++++ .../apps/common/testing/suite/dex/BUILD.bazel | 17 + .../suite/filter/AnnotationPredicates.java | 212 ++++++++++++ .../common/testing/suite/filter/BUILD.bazel | 20 ++ .../testrunner/testsuitepbutil/BUILD.bazel | 22 ++ .../tools/device_broker/proto/BUILD.bazel | 36 ++ .../third_party/android-test/repository.bzl | 67 ++++ 53 files changed, 4116 insertions(+), 2 deletions(-) create mode 100644 android/instrumentation-testing/.bazelignore create mode 100644 android/instrumentation-testing/app/src/main/AndroidTestManifest.xml create mode 100644 android/instrumentation-testing/app/src/main/java/com/example/android/instrumentation/GreeterInstrumentationTest.java create mode 100644 android/instrumentation-testing/bazel/BUILD.bazel create mode 100644 android/instrumentation-testing/bazel/android_instrumentation_test.bzl create mode 100644 android/instrumentation-testing/bazel/android_instrumentation_test.sh.tpl create mode 100644 android/instrumentation-testing/third_party/android-test/.bazelignore create mode 100644 android/instrumentation-testing/third_party/android-test/BUILD.bazel create mode 100644 android/instrumentation-testing/third_party/android-test/MODULE.bazel create mode 100644 android/instrumentation-testing/third_party/android-test/extensions.bzl create mode 100644 android/instrumentation-testing/third_party/android-test/overlay/BUILD create mode 100644 android/instrumentation-testing/third_party/android-test/overlay/build_extensions/maven/axt_android_aar.bzl create mode 100644 android/instrumentation-testing/third_party/android-test/overlay/build_extensions/maven/axt_maven_apk.bzl create mode 100644 android/instrumentation-testing/third_party/android-test/overlay/build_extensions/maven/maven_info.bzl create mode 100644 android/instrumentation-testing/third_party/android-test/overlay/opensource/BUILD create mode 100644 android/instrumentation-testing/third_party/android-test/overlay/opensource/androidx/BUILD create mode 100644 android/instrumentation-testing/third_party/android-test/overlay/opensource/auto_value/BUILD create mode 100644 android/instrumentation-testing/third_party/android-test/overlay/opensource/dagger/BUILD create mode 100644 android/instrumentation-testing/third_party/android-test/overlay/runner/android_junit_runner/java/androidx/test/BUILD create mode 100644 android/instrumentation-testing/third_party/android-test/overlay/runner/android_test_orchestrator/java/androidx/test/orchestrator/BUILD create mode 100644 android/instrumentation-testing/third_party/android-test/overlay/runner/android_test_orchestrator/stubapp/BUILD create mode 100644 android/instrumentation-testing/third_party/android-test/overlay/runner/monitor/java/androidx/test/BUILD create mode 100644 android/instrumentation-testing/third_party/android-test/overlay/services/BUILD create mode 100644 android/instrumentation-testing/third_party/android-test/overlay/services/events/java/androidx/test/services/events/BUILD create mode 100644 android/instrumentation-testing/third_party/android-test/overlay/services/proguard_library.cfg create mode 100644 android/instrumentation-testing/third_party/android-test/overlay/services/shellexecutor/BUILD create mode 100644 android/instrumentation-testing/third_party/android-test/overlay/services/shellexecutor/java/androidx/test/services/shellexecutor/BUILD create mode 100644 android/instrumentation-testing/third_party/android-test/overlay/services/speakeasy/java/androidx/test/services/speakeasy/BUILD create mode 100644 android/instrumentation-testing/third_party/android-test/overlay/services/speakeasy/java/androidx/test/services/speakeasy/client/BUILD create mode 100644 android/instrumentation-testing/third_party/android-test/overlay/services/speakeasy/java/androidx/test/services/speakeasy/compilehelp/hidden_api/BUILD create mode 100644 android/instrumentation-testing/third_party/android-test/overlay/services/speakeasy/java/androidx/test/services/speakeasy/server/BUILD create mode 100644 android/instrumentation-testing/third_party/android-test/overlay/services/storage/java/androidx/test/services/storage/BUILD create mode 100644 android/instrumentation-testing/third_party/android-test/overlay/services/storage/java/androidx/test/services/storage/file/BUILD create mode 100644 android/instrumentation-testing/third_party/android-test/overlay/services/storage/java/androidx/test/services/storage/provider/BUILD create mode 100644 android/instrumentation-testing/third_party/android-test/overlay/tools/android/emulator/BUILD.bazel create mode 100644 android/instrumentation-testing/third_party/android-test/overlay/tools/device_broker/java/com/google/android/apps/common/testing/broker/BUILD.bazel create mode 100644 android/instrumentation-testing/third_party/android-test/overlay/tools/device_broker/java/com/google/android/apps/common/testing/broker/LocalAdbServerDeviceBroker.java create mode 100644 android/instrumentation-testing/third_party/android-test/overlay/tools/device_broker/java/com/google/android/apps/common/testing/broker/ModernDexDumpOutputNormalizer.java create mode 100644 android/instrumentation-testing/third_party/android-test/overlay/tools/device_broker/java/com/google/android/apps/common/testing/broker/ModernDexDumpOutputNormalizerTest.java create mode 100644 android/instrumentation-testing/third_party/android-test/overlay/tools/device_broker/java/com/google/android/apps/common/testing/broker/TestInfoRepository.java create mode 100644 android/instrumentation-testing/third_party/android-test/overlay/tools/device_broker/java/com/google/android/apps/common/testing/broker/shell/BUILD.bazel create mode 100644 android/instrumentation-testing/third_party/android-test/overlay/tools/device_broker/java/com/google/android/apps/common/testing/suite/AndroidDeviceTestSuite.java create mode 100644 android/instrumentation-testing/third_party/android-test/overlay/tools/device_broker/java/com/google/android/apps/common/testing/suite/BUILD.bazel create mode 100644 android/instrumentation-testing/third_party/android-test/overlay/tools/device_broker/java/com/google/android/apps/common/testing/suite/dex/BUILD.bazel create mode 100644 android/instrumentation-testing/third_party/android-test/overlay/tools/device_broker/java/com/google/android/apps/common/testing/suite/filter/AnnotationPredicates.java create mode 100644 android/instrumentation-testing/third_party/android-test/overlay/tools/device_broker/java/com/google/android/apps/common/testing/suite/filter/BUILD.bazel create mode 100644 android/instrumentation-testing/third_party/android-test/overlay/tools/device_broker/java/com/google/android/apps/common/testing/testrunner/testsuitepbutil/BUILD.bazel create mode 100644 android/instrumentation-testing/third_party/android-test/overlay/tools/device_broker/proto/BUILD.bazel create mode 100644 android/instrumentation-testing/third_party/android-test/repository.bzl diff --git a/android/instrumentation-testing/.bazelignore b/android/instrumentation-testing/.bazelignore new file mode 100644 index 000000000..ba4c7139b --- /dev/null +++ b/android/instrumentation-testing/.bazelignore @@ -0,0 +1 @@ +third_party/android-test/overlay diff --git a/android/instrumentation-testing/.bazelrc b/android/instrumentation-testing/.bazelrc index f78e7f9e4..befb08f9f 100644 --- a/android/instrumentation-testing/.bazelrc +++ b/android/instrumentation-testing/.bazelrc @@ -1,3 +1,10 @@ common --enable_bzlmod +common --java_language_version=17 +common --java_runtime_version=remotejdk_17 +common --tool_java_language_version=17 +common --tool_java_runtime_version=remotejdk_17 + +test:local_device --test_strategy=exclusive +test:local_device --test_arg=--device_broker_type=LOCAL_ADB_SERVER try-import %workspace%/.bazelrc.user diff --git a/android/instrumentation-testing/MODULE.bazel b/android/instrumentation-testing/MODULE.bazel index 876e7bf03..91ea8d589 100644 --- a/android/instrumentation-testing/MODULE.bazel +++ b/android/instrumentation-testing/MODULE.bazel @@ -1,3 +1,15 @@ module(name = "android_instrumentation_testing") +bazel_dep(name = "android_test_overlay", version = "0.0.0") bazel_dep(name = "rules_android", version = "0.7.2") + +android_sdk_repository_extension = use_extension("@rules_android//rules/android_sdk_repository:rule.bzl", "android_sdk_repository_extension") +use_repo(android_sdk_repository_extension, "androidsdk") + +android_test = use_extension("@android_test_overlay//:extensions.bzl", "android_test") +use_repo(android_test, "android_test_support") + +local_path_override( + module_name = "android_test_overlay", + path = "third_party/android-test", +) diff --git a/android/instrumentation-testing/app/src/main/AndroidManifest.xml b/android/instrumentation-testing/app/src/main/AndroidManifest.xml index 7f5abafe2..20733fa6b 100644 --- a/android/instrumentation-testing/app/src/main/AndroidManifest.xml +++ b/android/instrumentation-testing/app/src/main/AndroidManifest.xml @@ -1,2 +1,9 @@ + package="com.example.android.instrumentation"> + + + + + diff --git a/android/instrumentation-testing/app/src/main/AndroidTestManifest.xml b/android/instrumentation-testing/app/src/main/AndroidTestManifest.xml new file mode 100644 index 000000000..261cce334 --- /dev/null +++ b/android/instrumentation-testing/app/src/main/AndroidTestManifest.xml @@ -0,0 +1,13 @@ + + + + + + + + diff --git a/android/instrumentation-testing/app/src/main/BUILD.bazel b/android/instrumentation-testing/app/src/main/BUILD.bazel index 378ae4a73..bb7a04eb4 100644 --- a/android/instrumentation-testing/app/src/main/BUILD.bazel +++ b/android/instrumentation-testing/app/src/main/BUILD.bazel @@ -1,4 +1,11 @@ -load("@rules_android//android:rules.bzl", "android_library") +load("@rules_android//android:rules.bzl", "android_binary", "android_library") +load("//bazel:android_instrumentation_test.bzl", "android_instrumentation_test") + +android_binary( + name = "app", + manifest = "AndroidManifest.xml", + deps = [":greeter_lib"], +) android_library( name = "greeter_lib", @@ -7,3 +14,24 @@ android_library( manifest = "AndroidManifest.xml", visibility = ["//visibility:public"], ) + +android_binary( + name = "greeter_test_app", + testonly = True, + srcs = ["java/com/example/android/instrumentation/GreeterInstrumentationTest.java"], + instruments = ":app", + manifest = "AndroidTestManifest.xml", + deps = [ + ":greeter_lib", + "@android_test_support//:junit", + "@android_test_support//runner/android_junit_runner", + ], +) + +android_instrumentation_test( + name = "greeter_instrumentation_test", + bootstrap_instrumentation_package = "com.example.android.instrumentation.test", + tags = ["manual"], + test_app = ":greeter_test_app", + test_packages = ["com.example.android.instrumentation.test"], +) diff --git a/android/instrumentation-testing/app/src/main/java/com/example/android/instrumentation/GreeterInstrumentationTest.java b/android/instrumentation-testing/app/src/main/java/com/example/android/instrumentation/GreeterInstrumentationTest.java new file mode 100644 index 000000000..5c214a55a --- /dev/null +++ b/android/instrumentation-testing/app/src/main/java/com/example/android/instrumentation/GreeterInstrumentationTest.java @@ -0,0 +1,20 @@ +package com.example.android.instrumentation; + +import static org.junit.Assert.assertEquals; + +import androidx.test.runner.AndroidJUnit4; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +public final class GreeterInstrumentationTest { + @Test + public void testDefaultGreeting() { + assertEquals("Hello, Android!", new Greeter().greet(null)); + } + + @Test + public void testNamedGreeting() { + assertEquals("Hello, Bazel!", new Greeter().greet(" Bazel ")); + } +} diff --git a/android/instrumentation-testing/bazel/BUILD.bazel b/android/instrumentation-testing/bazel/BUILD.bazel new file mode 100644 index 000000000..410562035 --- /dev/null +++ b/android/instrumentation-testing/bazel/BUILD.bazel @@ -0,0 +1 @@ +exports_files(["android_instrumentation_test.sh.tpl"]) diff --git a/android/instrumentation-testing/bazel/android_instrumentation_test.bzl b/android/instrumentation-testing/bazel/android_instrumentation_test.bzl new file mode 100644 index 000000000..ac738e2c3 --- /dev/null +++ b/android/instrumentation-testing/bazel/android_instrumentation_test.bzl @@ -0,0 +1,117 @@ +load("@rules_android//providers:providers.bzl", "AndroidInstrumentationInfo", "ApkInfo") + +def _apk_from_target(target, attr_name): + if ApkInfo in target: + apk = target[ApkInfo].signed_apk + if not apk: + fail("%s must provide a signed APK" % attr_name) + return apk + + apks = [f for f in target[DefaultInfo].files.to_list() if f.basename.endswith(".apk")] + if len(apks) != 1: + fail("%s must provide exactly one .apk file, got %d" % (attr_name, len(apks))) + return apks[0] + +def _runfiles_path(file): + path = file.short_path + if path.startswith("../"): + return path[3:] + return path + +def _apparent_label(label): + return "//%s:%s" % (label.package, label.name) + +def _android_instrumentation_test_impl(ctx): + test_app = ctx.attr.test_app + test_apk = test_app[ApkInfo].signed_apk + target_apk = test_app[AndroidInstrumentationInfo].target.signed_apk + if not target_apk: + fail("test_app must set instruments to an android_binary that produces a signed APK") + + support_apks = [_apk_from_target(apk, "support_apks") for apk in ctx.attr.support_apks] + executable = ctx.actions.declare_file(ctx.label.name) + + substitutions = { + "%workspace%": ctx.workspace_name, + "%test_label%": _apparent_label(ctx.label), + "%test_entry_point%": _runfiles_path(ctx.executable._test_entry_point), + "%adb%": _runfiles_path(ctx.file._adb), + "%aapt%": _runfiles_path(ctx.executable._aapt), + "%dexdump%": _runfiles_path(ctx.file._dexdump), + "%target_apk%": _runfiles_path(target_apk), + "%instrumentation_apk%": _runfiles_path(test_apk), + "%support_apks%": " ".join([_runfiles_path(apk) for apk in support_apks]), + "%test_packages%": " ".join([ + "additional_test_packages=%s" % package + for package in ctx.attr.test_packages + ]), + "%device_broker_type%": ctx.attr.device_broker_type, + "%bootstrap_instrumentation_package%": ctx.attr.bootstrap_instrumentation_package, + "%install_basic_services%": str(ctx.attr.install_basic_services).lower(), + "%install_test_services%": str(ctx.attr.install_test_services).lower(), + "%scan_target_package_for_tests%": str(ctx.attr.scan_target_package_for_tests).lower(), + } + + ctx.actions.expand_template( + template = ctx.file._template, + output = executable, + substitutions = substitutions, + is_executable = True, + ) + + runfiles = ctx.runfiles(files = [ + executable, + ctx.executable._test_entry_point, + ctx.file._adb, + ctx.executable._aapt, + ctx.file._dexdump, + target_apk, + test_apk, + ] + support_apks) + runfiles = runfiles.merge(ctx.attr._test_entry_point[DefaultInfo].default_runfiles) + runfiles = runfiles.merge(ctx.attr._aapt[DefaultInfo].default_runfiles) + + return [DefaultInfo( + executable = executable, + runfiles = runfiles, + )] + +android_instrumentation_test = rule( + implementation = _android_instrumentation_test_impl, + attrs = { + "bootstrap_instrumentation_package": attr.string(), + "device_broker_type": attr.string(default = "LOCAL_ADB_SERVER"), + "install_basic_services": attr.bool(default = False), + "install_test_services": attr.bool(default = True), + "scan_target_package_for_tests": attr.bool(default = False), + "support_apks": attr.label_list(allow_files = [".apk"]), + "test_app": attr.label( + mandatory = True, + providers = [[ApkInfo, AndroidInstrumentationInfo]], + ), + "test_packages": attr.string_list(), + "_aapt": attr.label( + default = Label("@androidsdk//:aapt_binary"), + executable = True, + cfg = "exec", + ), + "_adb": attr.label( + default = Label("@androidsdk//:adb"), + allow_single_file = True, + ), + "_dexdump": attr.label( + default = Label("@androidsdk//:dexdump"), + allow_single_file = True, + ), + "_template": attr.label( + default = Label("//bazel:android_instrumentation_test.sh.tpl"), + allow_single_file = True, + ), + "_test_entry_point": attr.label( + default = Label("@android_test_support//:instrumentation_test_runner"), + executable = True, + cfg = "exec", + ), + }, + test = True, +) diff --git a/android/instrumentation-testing/bazel/android_instrumentation_test.sh.tpl b/android/instrumentation-testing/bazel/android_instrumentation_test.sh.tpl new file mode 100644 index 000000000..b56ea59cc --- /dev/null +++ b/android/instrumentation-testing/bazel/android_instrumentation_test.sh.tpl @@ -0,0 +1,91 @@ +#!/usr/bin/env bash +set -euo pipefail + +if [[ -z "${TEST_SRCDIR:-}" && -z "${RUNFILES_DIR:-}" ]]; then + echo "TEST_SRCDIR or RUNFILES_DIR must be set by Bazel test." >&2 + exit 1 +fi + +workspace="%workspace%" + +function resolve_runfile() { + local path="$1" + local base + for base in "${RUNFILES_DIR:-}" "${TEST_SRCDIR:-}"; do + if [[ -z "${base}" ]]; then + continue + fi + if [[ -e "${base}/${path}" ]]; then + echo "${base}/${path}" + return + fi + if [[ -e "${base}/${workspace}/${path}" ]]; then + echo "${base}/${workspace}/${path}" + return + fi + done + echo "Could not resolve runfile: ${path}" >&2 + exit 1 +} + +function join_runfiles() { + local separator="$1" + shift + local result="" + local path + for path in "$@"; do + if [[ -z "${path}" ]]; then + continue + fi + if [[ -n "${result}" ]]; then + result+="${separator}" + fi + result+="$(resolve_runfile "${path}")" + done + echo "${result}" +} + +if [[ -z "${TESTBRIDGE_TEST_ONLY+set}" ]]; then + android_testbridge_test_only="" +else + android_testbridge_test_only="${TESTBRIDGE_TEST_ONLY}" + unset TESTBRIDGE_TEST_ONLY +fi + +test_entry_point="$(resolve_runfile "%test_entry_point%")" +adb="$(resolve_runfile "%adb%")" +aapt="$(resolve_runfile "%aapt%")" +dexdump="$(resolve_runfile "%dexdump%")" +target_apk="$(resolve_runfile "%target_apk%")" +instrumentation_apk="$(resolve_runfile "%instrumentation_apk%")" +support_apks="$(join_runfiles "," %support_apks%)" + +if [[ -n "${support_apks}" ]]; then + apks_to_install="${support_apks},${target_apk},${instrumentation_apk}" +else + apks_to_install="${target_apk},${instrumentation_apk}" +fi + +argv=$(cat <