| # Copyright 2023 The Chromium Authors |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| from __future__ import annotations |
| |
| import pathlib |
| from typing import Final |
| from unittest import mock |
| |
| from crossbench.plt.android_adb import Adb, AndroidAdbPlatform |
| from crossbench.plt.arch import MachineArch |
| from tests import test_helper |
| from tests.crossbench.mock_helper import WinMockPlatform |
| from tests.crossbench.plt.helper import BasePosixMockPlatformTestCase |
| |
| ADB_DEVICE_SAMPLE_OUTPUT = """List of devices attached |
| emulator-5556 device product:sdk_google_phone_x86_64 model:Android_SDK_built_for_x86_64 device:generic_x86_64""" |
| ADB_DEVICES_SAMPLE_OUTPUT = ADB_DEVICE_SAMPLE_OUTPUT + """ |
| emulator-5554 device product:sdk_google_phone_x86 model:Android_SDK_built_for_x86 device:generic_x86 |
| 0a388e93 device usb:1-1 product:razor model:Nexus_7 device:flo""" |
| |
| DUMPSYS_DISPLAY_OUTPUT: Final[str] = """ |
| SensorObserver |
| mIsProxActive=false |
| mDozeStateByDisplay: |
| 0 -> false |
| BrightnessSynchronizer |
| mLatestIntBrightness=43 |
| mLatestFloatBrightness=0.163 |
| mCurrentUpdate=null |
| """ |
| |
| |
| class BaseAndroidAdbMockPlatformTestCase(BasePosixMockPlatformTestCase): |
| DEVICE_ID = "emulator-5554" |
| platform: AndroidAdbPlatform |
| |
| def setUp(self) -> None: |
| super().setUp() |
| self.setUpAdb() |
| self.platform = AndroidAdbPlatform( |
| self.mock_platform, self.DEVICE_ID, adb=self.adb) |
| |
| def setUpAdb(self): |
| adb_patcher = mock.patch( |
| "crossbench.plt.android_adb._find_adb_bin", |
| return_value=pathlib.Path("adb")) |
| adb_patcher.start() |
| self.addCleanup(adb_patcher.stop) |
| self.expect_startup_devices() |
| self.adb = Adb(self.mock_platform, self.DEVICE_ID) |
| |
| def expect_startup_devices(self, devices: str = ADB_DEVICES_SAMPLE_OUTPUT): |
| self.expect_sh(pathlib.Path("adb"), "start-server") |
| self.expect_sh(pathlib.Path("adb"), "devices", "-l", result=devices) |
| |
| def expect_adb(self, *args, result=""): |
| self.expect_sh( |
| pathlib.Path("adb"), "-s", self.DEVICE_ID, *args, result=result) |
| |
| def test_is_android(self): |
| self.assertTrue(self.platform.is_android) |
| |
| |
| |
| class AndroidAdbOnWinMockPlatformTestCase(BaseAndroidAdbMockPlatformTestCase): |
| __test__ = True |
| |
| def setUpMockPlatform(self): |
| self.mock_platform = WinMockPlatform() |
| |
| def test_host_platform(self): |
| self.assertTrue(self.platform.host_platform.is_win) |
| # Enable path type check once we have more mocking support |
| # self.assertIsInstance( |
| # self.platform.host_path("foo/bar"), pathlib.PureWindowsPath) |
| # self.assertNotEqual( |
| # str(self.platform.host_path("foo/bar")), |
| # str(self.platform.path("foo/bar"))) |
| |
| def test_mktemp(self): |
| self.assertTrue(self.platform.default_tmp_dir.is_absolute()) |
| self.assertIsInstance(self.platform.default_tmp_dir, pathlib.PurePosixPath) |
| self.expect_adb("shell", "mktemp", "-d", |
| "/data/local/tmp/custom_prefix.XXXXXXXXXXX") |
| self.platform.mkdtemp("custom_prefix") |
| |
| |
| class AndroidAdbMockPlatformTest(BaseAndroidAdbMockPlatformTestCase): |
| __test__ = True |
| |
| def test_create_no_devices(self): |
| self.expect_startup_devices("List of devices attached") |
| with self.assertRaises(ValueError): |
| Adb(self.mock_platform, self.DEVICE_ID) |
| |
| def test_create_default_too_many_devices(self): |
| self.expect_startup_devices() |
| with self.assertRaises(ValueError) as cm: |
| Adb(self.mock_platform) |
| self.assertIn("too many", str(cm.exception).lower()) |
| |
| def test_create_default_one_device(self): |
| self.expect_startup_devices(ADB_DEVICE_SAMPLE_OUTPUT) |
| adb = Adb(self.mock_platform) |
| self.assertEqual(adb.serial_id, "emulator-5556") |
| |
| def test_create_default_one_device_invalid(self): |
| self.expect_startup_devices(ADB_DEVICE_SAMPLE_OUTPUT) |
| with self.assertRaises(ValueError) as cm: |
| Adb(self.mock_platform, "") |
| self.assertIn("invalid device identifier", str(cm.exception).lower()) |
| |
| def test_create_by_name(self): |
| self.expect_startup_devices(ADB_DEVICES_SAMPLE_OUTPUT) |
| adb = Adb(self.mock_platform, "Nexus_7") |
| self.assertEqual(adb.serial_id, "0a388e93") |
| self.expect_startup_devices(ADB_DEVICES_SAMPLE_OUTPUT) |
| adb = Adb(self.mock_platform, "Nexus 7") |
| self.assertEqual(adb.serial_id, "0a388e93") |
| |
| def test_create_by_name_duplicate(self): |
| self.expect_startup_devices(ADB_DEVICES_SAMPLE_OUTPUT) |
| with self.assertRaises(ValueError) as cm: |
| Adb(self.mock_platform, "Android_SDK_built_for_x86") |
| self.assertIn("devices", str(cm.exception).lower()) |
| |
| def test_basic_properties(self): |
| self.assertTrue(self.platform.is_remote) |
| self.assertEqual(self.platform.name, "android") |
| self.assertIs(self.platform.host_platform, self.mock_platform) |
| self.assertEqual(self.platform.default_tmp_dir, |
| pathlib.PurePosixPath("/data/local/tmp/")) |
| |
| def test_adb_basic_properties(self): |
| self.assertEqual(self.adb.serial_id, self.DEVICE_ID) |
| self.assertDictEqual( |
| self.adb.device_info, { |
| "device": "generic_x86", |
| "model": "Android_SDK_built_for_x86", |
| "product": "sdk_google_phone_x86" |
| }) |
| self.assertIn(self.DEVICE_ID, str(self.adb)) |
| |
| def test_has_root(self): |
| self.expect_adb("shell", "id", result="uid=2000(shell) gid=2000(shell)") |
| self.assertFalse(self.adb.has_root()) |
| self.expect_adb("shell", "id", result="uid=0(root)n gid=0(root)") |
| self.assertTrue(self.adb.has_root()) |
| |
| def test_version(self): |
| self.expect_adb( |
| "shell", "getprop", "ro.build.version.release", result="999") |
| self.assertEqual(self.platform.version, "999") |
| # Subsequent calls are cached. |
| self.assertEqual(self.platform.version, "999") |
| |
| def test_device(self): |
| self.expect_adb("shell", "getprop", "ro.product.model", result="Pixel 999") |
| self.assertEqual(self.platform.device, "Pixel 999") |
| # Subsequent calls are cached. |
| self.assertEqual(self.platform.device, "Pixel 999") |
| |
| def test_cpu(self): |
| self.expect_adb( |
| "shell", "getprop", "dalvik.vm.isa.arm.variant", result="cortex-a999") |
| self.expect_adb("shell", "getprop", "ro.board.platform", result="msmnile") |
| self.assertEqual(self.platform.cpu, "cortex-a999 msmnile") |
| # Subsequent calls are cached. |
| self.assertEqual(self.platform.cpu, "cortex-a999 msmnile") |
| |
| def test_cpu_detailed(self): |
| self.expect_adb( |
| "shell", "getprop", "dalvik.vm.isa.arm.variant", result="cortex-a999") |
| self.expect_adb("shell", "getprop", "ro.board.platform", result="msmnile") |
| self.expect_adb( |
| "shell", "cat", "/sys/devices/system/cpu/possible", result="0-998") |
| self.assertEqual(self.platform.cpu, "cortex-a999 msmnile 999 cores") |
| # Subsequent calls are cached. |
| self.assertEqual(self.platform.cpu, "cortex-a999 msmnile 999 cores") |
| |
| def test_adb(self): |
| self.assertIs(self.platform.adb, self.adb) |
| |
| def test_machine_unknown(self): |
| self.expect_adb( |
| "shell", "getprop", "ro.product.cpu.abi", result="arm37-XXX") |
| with self.assertRaises(ValueError) as cm: |
| self.assertEqual(self.platform.machine, MachineArch.ARM_64) |
| self.assertIn("arm37-XXX", str(cm.exception)) |
| |
| def test_machine_arm64(self): |
| self.expect_adb( |
| "shell", "getprop", "ro.product.cpu.abi", result="arm64-v8a") |
| self.assertEqual(self.platform.machine, MachineArch.ARM_64) |
| # Subsequent calls are cached. |
| self.assertEqual(self.platform.machine, MachineArch.ARM_64) |
| |
| def test_machine_arm32(self): |
| self.expect_adb( |
| "shell", "getprop", "ro.product.cpu.abi", result="armeabi-v7a") |
| self.assertEqual(self.platform.machine, MachineArch.ARM_32) |
| # Subsequent calls are cached. |
| self.assertEqual(self.platform.machine, MachineArch.ARM_32) |
| |
| def test_app_path_to_package_invalid_path(self): |
| path = pathlib.Path("path/to/app.bin") |
| with self.assertRaises(ValueError) as cm: |
| self.platform.app_path_to_package(path) |
| self.assertIn(str(path), str(cm.exception)) |
| |
| def test_app_path_to_package_not_installed(self): |
| with self.assertRaises(ValueError) as cm: |
| self.expect_adb( |
| "shell", |
| "cmd", |
| "package", |
| "list", |
| "packages", |
| result=("package:com.google.android.wifi.resources\n" |
| "package:com.google.android.GoogleCamera")) |
| self.platform.app_path_to_package(pathlib.Path("com.custom.app")) |
| self.assertIn("com.custom.app", str(cm.exception)) |
| self.assertIn("not installed", str(cm.exception)) |
| |
| def test_app_path_to_package(self): |
| path = pathlib.Path("com.custom.app") |
| self.expect_adb( |
| "shell", |
| "cmd", |
| "package", |
| "list", |
| "packages", |
| result=("package:com.google.android.wifi.resources\n" |
| "package:com.custom.app")) |
| self.assertEqual(self.platform.app_path_to_package(path), "com.custom.app") |
| |
| def test_app_version(self): |
| path = pathlib.Path("com.custom.app") |
| self.expect_adb( |
| "shell", |
| "cmd", |
| "package", |
| "list", |
| "packages", |
| result="package:com.custom.app") |
| self.expect_adb( |
| "shell", |
| "dumpsys", |
| "package", |
| "com.custom.app", |
| result="versionName=9.999") |
| self.assertEqual(self.platform.app_version(path), "9.999") |
| |
| def test_app_version_unkown(self): |
| path = pathlib.Path("com.custom.app") |
| self.expect_adb( |
| "shell", |
| "cmd", |
| "package", |
| "list", |
| "packages", |
| result="package:com.custom.app") |
| self.expect_adb( |
| "shell", "dumpsys", "package", "com.custom.app", result="something") |
| with self.assertRaises(ValueError) as cm: |
| self.platform.app_version(path) |
| self.assertIn("something", str(cm.exception)) |
| self.assertIn("com.custom.app", str(cm.exception)) |
| |
| def test_get_relative_cpu_speed(self): |
| self.assertGreater(self.platform.get_relative_cpu_speed(), 0) |
| |
| def test_check_autobrightness(self): |
| self.assertTrue(self.platform.check_autobrightness()) |
| |
| def get_main_display_brightness(self): |
| display_info = ("BrightnessSynchronizer\n" |
| "mLatestFloatBrightness=0.5\n" |
| "mLatestIntBrightness=128\n" |
| "mPendingUpdate=null") |
| self.expect_adb("shell", "dumpsys", "display", result=display_info) |
| self.assertEqual(self.platform.get_main_display_brightness(), 50) |
| # Values are not cached |
| display_info = ("BrightnessSynchronizer\n" |
| "mLatestFloatBrightness=1.0\n" |
| "mLatestIntBrightness=255\n" |
| "mPendingUpdate=null") |
| self.expect_adb("shell", "dumpsys", "display", result=display_info) |
| self.assertEqual(self.platform.get_main_display_brightness(), 100) |
| |
| def test_search_binary_empty_path(self): |
| with self.assertRaises(ValueError) as cm: |
| self.platform.search_binary(pathlib.Path("")) |
| self.assertIn("empty path", str(cm.exception)) |
| with self.assertRaises(ValueError) as cm: |
| self.platform.search_binary("") |
| self.assertIn("empty path", str(cm.exception)) |
| |
| def test_search_binary(self): |
| self.expect_adb( |
| "shell", "which", self.platform.path("ls"), result="/system/bin/ls") |
| self.expect_adb("shell", "[", "-e", "/system/bin/ls", "]", result="") |
| path = self.platform.search_binary("ls") |
| self.assertEqual(path, self.platform.path("/system/bin/ls")) |
| |
| def test_binary_lookup_override(self): |
| # Overriding the default test for android. |
| ls_path = self.platform.path("ls") |
| override_path = self.platform.path("/root/sbin/ls") |
| # override_binary checks if the result binary exists. |
| self.expect_adb("shell", "which", override_path, result=str(override_path)) |
| self.expect_adb("shell", "[", "-e", "/root/sbin/ls", "]", result="") |
| with self.platform.override_binary(ls_path, override_path): |
| path = self.platform.search_binary("ls") |
| self.assertEqual(path, override_path) |
| |
| def test_search_binary_app_package_non(self): |
| self.expect_adb( |
| "shell", "which", self.platform.path("com.google.chrome"), result="") |
| self.expect_adb("shell", "cmd", "package", "list", "packages", result="") |
| path = self.platform.search_binary("com.google.chrome") |
| self.assertIsNone(path) |
| |
| self.expect_adb( |
| "shell", "which", self.platform.path("com.google.chrome"), result="") |
| self.expect_adb( |
| "shell", |
| "cmd", |
| "package", |
| "list", |
| "packages", |
| result="package:com.google.chrome") |
| path = self.platform.search_binary("com.google.chrome") |
| self.assertEqual(path, pathlib.PurePosixPath("com.google.chrome")) |
| |
| def test_search_binary_app_package_lookup_override(self): |
| chrome_package = self.platform.path("com.google.chrome") |
| chrome_dev_package = self.platform.path("com.chrome.dev") |
| self.expect_adb("shell", "which", chrome_dev_package, result="") |
| self.expect_adb( |
| "shell", |
| "cmd", |
| "package", |
| "list", |
| "packages", |
| result="package:com.chrome.dev") |
| with self.platform.override_binary(chrome_package, chrome_dev_package): |
| path = self.platform.search_binary(chrome_package) |
| self.assertEqual(chrome_dev_package, path) |
| |
| def test_override_binary_non_existing_package(self): |
| chrome_package = self.platform.path("com.google.chrome") |
| chrome_dev_package = self.platform.path("com.chrome.dev") |
| self.expect_adb("shell", "which", chrome_dev_package, result="") |
| self.expect_adb("shell", "cmd", "package", "list", "packages", result="") |
| with self.assertRaises(ValueError) as cm: |
| with self.platform.override_binary(chrome_package, chrome_dev_package): |
| pass |
| self.assertIn(str(chrome_package), str(cm.exception)) |
| self.assertIn(str(chrome_dev_package), str(cm.exception)) |
| |
| def test_home(self): |
| # not implemented yet |
| with self.assertRaises(RuntimeError): |
| self.platform.home() |
| |
| def test_get_main_display_brightness(self): |
| self.expect_adb( |
| "shell", "dumpsys", "display", result=DUMPSYS_DISPLAY_OUTPUT) |
| brightness = self.platform.get_main_display_brightness() |
| self.assertEqual(brightness, 16) |
| |
| if __name__ == "__main__": |
| test_helper.run_pytest(__file__) |