blob: 0613efb5a652e3161ac0b7293c8de59bb88e5f9f [file]
# 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 argparse
import pathlib
from typing import Final
from unittest import mock
from pyfakefs.fake_filesystem import OSType
from typing_extensions import override
from crossbench import path as pth
from crossbench.helper.version import VersionParseError
from crossbench.plt.android_adb import Adb, AndroidAdbPlatform, \
AndroidDeviceInfo, AndroidVersion
from crossbench.plt.arch import MachineArch
from crossbench.plt.port_manager import PortForwardException
from crossbench.plt.process_meminfo import ProcessMeminfo
from tests import test_helper
from tests.crossbench.mock_helper import ShResult, WinMockPlatform
from tests.crossbench.plt.helper import BasePosixMockPlatformTestCase
ADB_DEVICE_SAMPLE_OUTPUT = (
"List of devices attached\n"
"emulator-5556 device product:sdk_google_phone_x86_64 "
"model:Android_SDK_built_for_x86_64 device:generic_x86_64\n")
ADB_DEVICES_SAMPLE_OUTPUT = (
f"{ADB_DEVICE_SAMPLE_OUTPUT}"
"emulator-5554 device product:sdk_google_phone_x86 "
"model:Android_SDK_built_for_x86 device:generic_x86\n"
"0a388e93 device usb:1-1 product:razor model:Nexus_7 device:flo\n")
DUMPSYS_DISPLAY_OUTPUT: Final[str] = """
SensorObserver
mIsProxActive=false
mDozeStateByDisplay:
0 -> false
BrightnessSynchronizer
mLatestIntBrightness=43
mLatestFloatBrightness=0.163
mCurrentUpdate=null
"""
def load_pb(path: str):
return (pth.LocalPath(__file__).parent / "pb" / path).read_bytes()
DUMPSYS_MEMINFO_OUTPUT = load_pb("dumpsys_meminfo.pb")
AC_POWERED_OUTPUT = load_pb("battery/ac_powered.pb")
BATTERY_POWERED_OUTPUT = load_pb("battery/battery_powered.pb")
DUMPSYS_WINDOW_DISPLAYS_OUTPUT = load_pb("display/1080p.pb")
DUMPSYS_MEMINFO_TIMEOUT_OUTPUT = b"""
*** SERVICE 'meminfo' DUMP TIMEOUT (1ms) EXPIRED ***
"""
DUMPSYS_MEMINFO_SYSTEM_OUTPUT = b"""
0K: GL mtrack
0K: Other mtrack
Total RAM: 7,698,860K (status normal)
Free RAM: 1,234K (2,345K cached pss + 3,456K cached kernel + 4,567K free)
DMA-BUF: 817,715K ( 152K mapped + 817,563K unmapped)
DMA-BUF Heaps: 24,844K
DMA-BUF Heaps pool: 0K
GPU: 258,796K ( 258,796K dmabuf + 0K private)
Kernel CMA: 0K
Used RAM: 3,528,301K (1,772,358K used pss + 1,755,943K kernel)
Lost RAM: 362,207K
ZRAM: 557,480K physical used for 1,723,064K in swap (11,284K total swap)
Tuning: 192 (large 512), oom 322,560K, restore limit 107,520K (high-end-gfx)
"""
DUMPSYS_MEMINFO_SYSTEM_OUTPUT_NO_DMA_BUF = b"""
800K: Ashmem
324K: .ttf mmap
0K: Cursor
0K: Other mtrack
Total RAM: 3,486,196K (status moderate)
Free RAM: 1,234K (2,345K cached pss + 3,456K cached kernel + 4,567K free)
ION: 132,124K ( 6,924K mapped + 125,200K unmapped + 0K pools)
GPU: 194,788K
Used RAM: 2,835,979K (2,170,795K used pss + 665,184K kernel)
Lost RAM: 282,400K
ZRAM: 203,732K physical used for 745,216K in swap (4,194,300K total swap)
Tuning: 256 (large 512), oom 322,560K, restore limit 107,520K (high-end-gfx)
"""
class BaseAndroidAdbMockPlatformTestCase(BasePosixMockPlatformTestCase):
DEVICE_ID = "emulator-5554"
platform: AndroidAdbPlatform
adb: Adb
@override
def setUp(self) -> None:
self.adb_setup()
super().setUp()
@override
def setup_platform(self):
self.expect_startup_devices()
self.adb = Adb(self.host_platform, self.DEVICE_ID)
platform = AndroidAdbPlatform(
self.host_platform, self.DEVICE_ID, adb=self.adb)
self.mock_platform_str(platform, "adb.mock_platform.arm64")
return platform
def test_str(self):
self.assertEqual(str(self.platform), "adb.mock_platform.arm64")
def adb_setup(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)
def expect_startup_devices(self, devices: str = ADB_DEVICES_SAMPLE_OUTPUT):
if self.host_platform.is_macos:
self.host_platform.expect_sh(
"brew", "--prefix", result=ShResult(returncode=1))
self.host_platform.expect_sh(pathlib.Path("adb"), "start-server")
self.host_platform.expect_sh(
pathlib.Path("adb"), "devices", "-l", result=devices)
def expect_sh(self, *args, result=""):
self.expect_adb("shell", *args, result=result)
def expect_adb(self, *args, result=""):
self.host_platform.expect_sh(
pathlib.Path("adb"), "-s", self.DEVICE_ID, *args, result=result)
def test_is_android(self):
self.assertTrue(self.platform.is_android)
def test_is_battery_powered(self):
self.expect_sh("dumpsys battery --proto", result=AC_POWERED_OUTPUT)
self.assertFalse(self.platform.is_battery_powered)
self.expect_sh("dumpsys battery --proto", result=BATTERY_POWERED_OUTPUT)
self.assertTrue(self.platform.is_battery_powered)
def test_display_details(self):
self.expect_sh(
"dumpsys window displays --proto",
result=DUMPSYS_WINDOW_DISPLAYS_OUTPUT)
result = self.platform.display_details()
self.assertEqual(len(result), 1)
self.assertDictEqual(result[0], {
"resolution": (1920, 1080),
"refresh_rate": -1
})
def test_unique_name(self):
self.expect_sh("getprop ro.product.cpu.abi", result="arm64-v8a")
self.expect_sh("getprop ro.product.cpu.abi", result="arm64-v8a")
platform_2 = AndroidAdbPlatform(
self.host_platform, "SomeDeviceId", adb=self.adb)
self.assertNotEqual(self.platform.unique_name, platform_2.unique_name)
class AndroidAdbOnWinMockPlatformTestCase(BaseAndroidAdbMockPlatformTestCase):
__test__ = True
@override
def setUp(self) -> None:
super().setUp()
self.fs.os = OSType.WINDOWS
@override
def setup_host_platform(self):
return WinMockPlatform()
def test_host_platform(self):
self.assertTrue(self.platform.host_platform.is_win)
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_sh("mktemp -d /data/local/tmp/custom_prefix.XXXXXXXXXXX")
self.platform.mkdtemp(prefix="custom_prefix.")
def test_mktemp_prefix_and_suffix(self):
# suffix need special handling on android.
self.assertTrue(self.platform.default_tmp_dir.is_absolute())
self.assertIsInstance(self.platform.default_tmp_dir, pathlib.PurePosixPath)
self.expect_sh(
"mktemp -d /data/local/tmp/custom_prefix.XXXXXXXXXXX",
result="/data/local/tmp/custom_prefix.RANDOM")
self.expect_sh(("mv /data/local/tmp/custom_prefix.RANDOM "
"/data/local/tmp/custom_prefix.RANDOM.custom_suffix"))
self.platform.mkdtemp(".custom_suffix", "custom_prefix.")
def test_mktemp_suffix(self):
# suffix need special handling on android.
self.assertTrue(self.platform.default_tmp_dir.is_absolute())
self.assertIsInstance(self.platform.default_tmp_dir, pathlib.PurePosixPath)
self.expect_sh(
"mktemp -d /data/local/tmp/XXXXXXXXXXX",
result="/data/local/tmp/RANDOM")
self.expect_sh(
"mv /data/local/tmp/RANDOM /data/local/tmp/RANDOM.custom_suffix")
self.platform.mkdtemp(".custom_suffix")
def test_push(self):
local_path = self.host_platform.path("C:/foo/push.local.data")
remote_path = self.platform.default_tmp_dir / "push.remote.data"
self.assertIsInstance(local_path, pathlib.PureWindowsPath)
self.fs.create_file(local_path, contents="some data")
self.expect_adb("push", "C:\\foo\\push.local.data",
"/data/local/tmp/push.remote.data")
self.platform.push(local_path, remote_path)
def test_push_remote_win_path(self):
local_path = self.host_platform.path("C:/foo/push.local.data")
remote_path = self.platform.path("custom/push.remote.data")
self.assertIsInstance(local_path, pathlib.PureWindowsPath)
self.fs.create_file(local_path, contents="some data")
self.expect_adb("push", "C:\\foo\\push.local.data",
"custom/push.remote.data")
self.platform.push(local_path, remote_path)
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.host_platform, self.DEVICE_ID)
def test_create_default_too_many_devices(self):
self.expect_startup_devices()
with self.assertRaises(ValueError) as cm:
Adb(self.host_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.host_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.host_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.host_platform, "Nexus_7")
self.assertEqual(adb.serial_id, "0a388e93")
self.expect_startup_devices(ADB_DEVICES_SAMPLE_OUTPUT)
adb = Adb(self.host_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.host_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.host_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.assertEqual(
self.adb.device_info,
AndroidDeviceInfo(
device_id=self.DEVICE_ID,
name="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_sh("id", result="uid=2000(shell) gid=2000(shell)")
self.assertFalse(self.adb.has_root())
self.expect_sh("id", result="uid=0(root)n gid=0(root)")
self.assertTrue(self.adb.has_root())
def test_version(self):
version_str = "13 (Tiramisu)"
self.expect_sh("getprop ro.build.description", result=version_str)
version = self.platform.version
self.assertEqual(version.parts, (13,))
self.assertEqual(version.version_str, version_str)
self.assertIs(version, self.platform.version)
def test_version_long(self):
version_str = "oriole-user 13 TQ3A.230805.001 10452339 release-keys"
self.expect_sh("getprop ro.build.description", result=version_str)
version = self.platform.version
self.assertEqual(version.parts, (13,))
self.assertEqual(version.version_str, version_str)
self.assertIs(version, self.platform.version)
def test_device(self):
self.expect_sh("getprop ro.product.model", result="Pixel 999")
self.assertEqual(self.platform.model, "Pixel 999")
# Subsequent calls are cached.
self.assertEqual(self.platform.model, "Pixel 999")
def test_cpu(self):
self.expect_sh("getprop dalvik.vm.isa.arm.variant", result="cortex-a999")
self.expect_sh("getprop ro.board.platform", result="msmnile")
cpu_info = "processor : 0\nprocessor : 1"
self.expect_sh(
"grep -E 'processor|core id|physical id' /proc/cpuinfo",
result=cpu_info)
self.assertEqual(self.platform.cpu, "cortex-a999 msmnile 2 cores")
# Subsequent calls are cached.
self.assertEqual(self.platform.cpu, "cortex-a999 msmnile 2 cores")
def test_cpu_detailed(self):
self.expect_sh("getprop dalvik.vm.isa.arm.variant", result="cortex-a999")
self.expect_sh("getprop ro.board.platform", result="msmnile")
cpu_info = "processor : 0\nprocessor : 1"
self.expect_sh(
"grep -E 'processor|core id|physical id' /proc/cpuinfo",
result=cpu_info)
self.assertEqual(self.platform.cpu, "cortex-a999 msmnile 2 cores")
# Subsequent calls are cached.
self.assertEqual(self.platform.cpu, "cortex-a999 msmnile 2 cores")
def test_adb(self):
self.assertIs(self.platform.adb, self.adb)
def test_machine_unknown(self):
self.expect_sh("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_sh("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_sh("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(self.platform.path(path)), str(cm.exception))
def test_app_path_to_package_not_installed(self):
with self.assertRaises(ValueError) as cm:
self.expect_sh(
"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_sh(
"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_sh("cmd package list packages", result="package:com.custom.app")
self.expect_sh("dumpsys package com.custom.app", result="versionName=9.999")
self.assertEqual(self.platform.app_version(path), "9.999")
def test_app_version_unknown(self):
path = pathlib.Path("com.custom.app")
self.expect_sh("cmd package list packages", result="package:com.custom.app")
self.expect_sh("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_sh("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_sh("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):
ls_path = self.platform.path("/system/bin/ls")
self.expect_sh("which ls", result=str(ls_path))
self.expect_sh(f"'[' -e {ls_path} ']'", result="")
path = self.platform.search_binary("ls")
self.assertEqual(str(path), str(ls_path))
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_sh(f"which {override_path}", result=str(override_path))
self.expect_sh(f"'[' -e {override_path} ']'", 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_sh("which com.google.chrome", result="")
self.expect_sh("cmd package list packages", result="")
path = self.platform.search_binary("com.google.chrome")
self.assertIsNone(path)
self.expect_sh("which com.google.chrome", result="")
self.expect_sh(
"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_sh(f"which {chrome_dev_package}", result="")
self.expect_sh("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_sh(f"which {chrome_dev_package}", result="")
self.expect_sh("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_sh("dumpsys display", result=DUMPSYS_DISPLAY_OUTPUT)
brightness = self.platform.get_main_display_brightness()
self.assertEqual(brightness, 16)
def test_iterdir(self):
self.expect_sh("'[' -d parent_dir/child_dir ']'")
self.expect_sh("ls -1 parent_dir/child_dir", result="file1\nfile2\n")
self.assertSetEqual(
set(self.platform.iterdir(pth.AnyWindowsPath("parent_dir\\child_dir"))),
{
pth.AnyPosixPath("parent_dir/child_dir/file1"),
pth.AnyPosixPath("parent_dir/child_dir/file2")
})
def test_cat_file(self):
self.expect_sh("cat path/to/a/file")
self.platform.cat(self.platform.path("path/to/a/file"))
self.expect_sh("cat 'path/with a space/to/a/file'")
self.platform.cat(self.platform.path("path/with a space/to/a/file"))
def test_sh_shell_invalid(self):
with self.assertRaisesRegex(ValueError, "shell=True"):
self.platform.sh_stdout("ls", "folder with space", shell=True)
def test_sh_shell(self):
self.expect_sh("ls sdcard", result="FILE1\nFILE2\n")
self.assertEqual(self.platform.sh_stdout("ls", "sdcard"), "FILE1\nFILE2\n")
self.expect_sh("ls 'folder with space'", result="FOLDER\n")
self.assertEqual(
self.platform.sh_stdout("ls", "folder with space"), "FOLDER\n")
self.expect_sh("'ls foo && ls bar'", result="FILE1\nFILE2\n")
self.assertEqual(
self.platform.sh_stdout("ls foo && ls bar"), "FILE1\nFILE2\n")
self.expect_sh("ls foo && ls bar", result="FILE1\nFILE2\n")
self.assertEqual(
self.platform.sh_stdout("ls foo && ls bar", shell=True),
"FILE1\nFILE2\n")
self.expect_sh("ls foo '&&' ls bar", result="FILE1\nFILE2\n")
self.assertEqual(
self.platform.sh_stdout("ls", "foo", "&&", "ls", "bar"),
"FILE1\nFILE2\n")
def test_port_forward_default(self):
# Closing the default port-manager happens in the atexit handler.
self.expect_adb("forward", "tcp:0", "tcp:33221", result="666")
self.platform.ports.forward(0, 33221)
self.expect_adb("forward", "--remove", "tcp:666")
self.platform.ports.stop_forward(666)
def test_port_forward(self):
self.expect_adb("forward", "tcp:0", "tcp:33221", result="666")
self.expect_adb("forward", "--remove", "tcp:666")
with self.platform.ports.nested() as ports:
port = ports.forward(0, 33221)
self.assertEqual(port, 666)
# Cannot forward the same ports in a nested scope.
with self.platform.ports.nested() as ports_2:
with self.assertRaises(PortForwardException):
ports_2.forward(666, 33221)
ports.stop_forward(port)
with self.assertRaises(PortForwardException):
ports.stop_forward(port)
def test_port_forward_auto_close(self):
self.expect_adb("forward", "tcp:0", "tcp:33221", result="666")
self.expect_adb("forward", "--remove", "tcp:666")
with self.platform.ports.nested() as ports:
port = ports.forward(0, 33221)
self.assertEqual(port, 666)
def test_reverse_port_forward_default(self):
self.expect_adb("reverse", "tcp:0", "tcp:33221", result="666")
self.platform.ports.reverse_forward(0, 33221)
self.expect_adb("reverse", "--remove", "tcp:666")
self.platform.ports.stop_reverse_forward(666)
def test_reverse_port_forward(self):
with self.platform.ports.nested() as ports:
self.expect_adb("reverse", "tcp:0", "tcp:33221", result="666")
self.expect_adb("reverse", "--remove", "tcp:666")
port = ports.reverse_forward(0, 33221)
self.assertEqual(port, 666)
# Cannot forward the same ports in a nested scope.
with self.platform.ports.nested() as ports_2:
with self.assertRaises(PortForwardException):
ports_2.reverse_forward(666, 33221)
ports.stop_reverse_forward(port)
with self.assertRaises(PortForwardException):
ports.stop_reverse_forward(port)
def test_reverse_port_forward_nested_auto_close(self):
self.expect_adb("reverse", "tcp:0", "tcp:33300", result="333")
self.expect_adb("reverse", "tcp:0", "tcp:33221", result="666")
self.expect_adb("reverse", "--remove", "tcp:666")
self.expect_adb("reverse", "--remove", "tcp:333")
with self.platform.ports.nested() as ports_1:
port = ports_1.reverse_forward(0, 33300)
self.assertEqual(port, 333)
with self.platform.ports.nested() as ports_2:
port = ports_2.reverse_forward(0, 33221)
self.assertEqual(port, 666)
def test_reverse_port_forward_auto_close(self):
self.expect_adb("reverse", "tcp:0", "tcp:33221", result="666")
self.expect_adb("reverse", "--remove", "tcp:666")
with self.platform.ports.nested() as ports:
port = ports.reverse_forward(0, 33221)
self.assertEqual(port, 666)
def test_port_forward_invalid_adb(self):
with self.platform.ports.nested() as ports:
with self.assertRaisesRegex(argparse.ArgumentTypeError, "remote_port"):
ports.forward(1111, 0)
def test_reverse_port_forward_invalid_adb(self):
with self.platform.ports.nested() as ports:
with self.assertRaisesRegex(argparse.ArgumentTypeError, "local_port"):
ports.reverse_forward(1111, 0)
def test_display_resolution(self):
self.expect_sh(
"dumpsys window displays --proto",
result=DUMPSYS_WINDOW_DISPLAYS_OUTPUT)
[horizontal, vertical] = self.platform.display_resolution()
self.assertEqual(horizontal, 1920)
self.assertEqual(vertical, 1080)
def test_user_id(self):
self.expect_sh("am get-current-user", result="10")
self.assertEqual(self.platform.user_id(), 10)
def test_process_meminfo_no_process(self):
self.expect_sh(
"dumpsys -T 10000 meminfo --proto --package com.android.chrome",
result=b"")
meminfo = self.platform.process_meminfo("com.android.chrome")
self.assertEqual(len(meminfo), 0)
def test_process_meminfo(self):
self.expect_sh(
"dumpsys -T 10000 meminfo --proto --package com.android.chrome",
result=DUMPSYS_MEMINFO_OUTPUT)
meminfo = self.platform.process_meminfo("com.android.chrome")
self.assertEqual(len(meminfo), 4)
privileged_process = "com.android.chrome:privileged_process0"
sandbox_prefix = ("com.android.chrome:sandboxed_process0:org.chromium."
"content.app.SandboxedProcessService0:")
self.assertEqual(meminfo, [
ProcessMeminfo(20533, privileged_process, 37794, 186356, 203),
ProcessMeminfo(20527, f"{sandbox_prefix}0", 49907, 184636, 245),
ProcessMeminfo(20596, f"{sandbox_prefix}1", 30679, 156928, 244),
ProcessMeminfo(20438, "com.android.chrome", 200986, 412436, 148)
])
def test_process_meminfo_timeout(self):
self.expect_sh(
"dumpsys -T 10000 meminfo --proto --package com.android.chrome",
result=DUMPSYS_MEMINFO_TIMEOUT_OUTPUT)
with self.assertRaises(TimeoutError):
self.platform.process_meminfo("com.android.chrome")
def test_system_meminfo(self):
self.expect_sh(
"dumpsys -T 10000 meminfo", result=DUMPSYS_MEMINFO_SYSTEM_OUTPUT)
meminfo = self.platform.system_meminfo()
self.assertDictEqual(
meminfo, {
"total_ram_kb": 7698860.0,
"cached_pss_kb": 2345.0,
"cached_kernel_kb": 3456.0,
"free_kb": 4567.0,
"dma_buf_kb": 817715.0,
"dma_buf_mapped_kb": 152.0,
"dma_buf_unmapped_kb": 817563.0,
})
def test_system_meminfo_no_dma_buf(self):
self.expect_sh(
"dumpsys -T 10000 meminfo",
result=DUMPSYS_MEMINFO_SYSTEM_OUTPUT_NO_DMA_BUF)
meminfo = self.platform.system_meminfo()
self.assertDictEqual(
meminfo, {
"total_ram_kb": 3486196.0,
"cached_pss_kb": 2345.0,
"cached_kernel_kb": 3456.0,
"free_kb": 4567.0,
})
def test_system_meminfo_timeout(self):
self.expect_sh(
"dumpsys -T 10000 meminfo", result=DUMPSYS_MEMINFO_TIMEOUT_OUTPUT)
with self.assertRaises(TimeoutError):
self.platform.system_meminfo()
def test_doze(self):
self.expect_sh("dumpsys deviceidle force-idle")
self.platform.doze()
def test_exit_doze(self):
self.expect_sh("dumpsys deviceidle unforce")
self.expect_sh("dumpsys battery reset")
self.platform.exit_doze()
def test_lock_screen(self):
self.expect_sh("input keyevent KEYCODE_POWER")
self.platform.lock_screen()
def test_unlock_screen(self):
self.expect_sh("input keyevent KEYCODE_WAKEUP")
self.expect_sh("input keyevent KEYCODE_MENU")
self.platform.unlock_screen()
def test_platform_version_cls(self):
version = AndroidVersion.parse("13 (Tiramisu)")
self.assertEqual(version.parts, (13,))
self.assertEqual(version.version_str, "13 (Tiramisu)")
with self.assertRaises(VersionParseError):
AndroidVersion.parse("foo")
if __name__ == "__main__":
test_helper.run_pytest(__file__)