Test infrastructure with conftest fixtures mocking run_shell_args/run_adb for device-free testing across all 8 mixins. Fixed: UI parser regex couldn't match hyphenated XML attributes (content-desc, resource-id). Notification parser captured trailing parenthesis in package names.
182 lines
6.7 KiB
Python
182 lines
6.7 KiB
Python
"""Tests for devices mixin (list, use, current, info, reboot, logcat)."""
|
|
|
|
import pytest
|
|
|
|
from tests.conftest import fail, ok
|
|
|
|
|
|
class TestDevicesList:
|
|
async def test_parse_devices(self, server):
|
|
server.run_adb.return_value = ok(
|
|
stdout=(
|
|
"List of devices attached\n"
|
|
"ABC123\tdevice\tmodel:Pixel_6 product:oriole\n"
|
|
"10.20.0.25:5555\tdevice\tmodel:K2401 product:K2401\n"
|
|
)
|
|
)
|
|
devices = await server.devices_list()
|
|
assert len(devices) == 2
|
|
assert devices[0].device_id == "ABC123"
|
|
assert devices[0].model == "Pixel_6"
|
|
assert devices[1].device_id == "10.20.0.25:5555"
|
|
|
|
async def test_empty(self, server):
|
|
server.run_adb.return_value = ok(stdout="List of devices attached\n")
|
|
devices = await server.devices_list()
|
|
assert len(devices) == 0
|
|
|
|
async def test_failure(self, server):
|
|
server.run_adb.return_value = fail("adb not found")
|
|
devices = await server.devices_list()
|
|
assert len(devices) == 0
|
|
|
|
|
|
class TestDevicesUse:
|
|
async def test_select_device(self, server):
|
|
server.run_adb.return_value = ok(
|
|
stdout="List of devices attached\nABC123\tdevice\n"
|
|
)
|
|
result = await server.devices_use("ABC123")
|
|
assert result["success"] is True
|
|
assert server.get_current_device() == "ABC123"
|
|
|
|
async def test_not_found(self, server):
|
|
server.run_adb.return_value = ok(
|
|
stdout="List of devices attached\nOTHER\tdevice\n"
|
|
)
|
|
result = await server.devices_use("MISSING")
|
|
assert result["success"] is False
|
|
assert "not found" in result["error"]
|
|
|
|
async def test_offline_device(self, server):
|
|
server.run_adb.return_value = ok(
|
|
stdout="List of devices attached\nABC123\toffline\n"
|
|
)
|
|
result = await server.devices_use("ABC123")
|
|
assert result["success"] is False
|
|
assert "offline" in result["error"]
|
|
|
|
|
|
class TestDevicesCurrent:
|
|
async def test_no_device_set(self, server):
|
|
server.run_adb.return_value = ok(stdout="List of devices attached\n")
|
|
result = await server.devices_current()
|
|
assert result["device"] is None
|
|
|
|
async def test_auto_detect_single(self, server):
|
|
server.run_adb.return_value = ok(
|
|
stdout="List of devices attached\nABC123\tdevice\n"
|
|
)
|
|
result = await server.devices_current()
|
|
assert result.get("available") is not None
|
|
|
|
async def test_device_set(self, server):
|
|
# Pre-populate cache and set device
|
|
server.run_adb.return_value = ok(
|
|
stdout="List of devices attached\nABC123\tdevice\tmodel:Pixel\n"
|
|
)
|
|
await server.devices_list()
|
|
server.set_current_device("ABC123")
|
|
result = await server.devices_current()
|
|
assert result["device"]["device_id"] == "ABC123"
|
|
|
|
|
|
class TestDeviceInfo:
|
|
async def test_full_info(self, server):
|
|
battery = (
|
|
"Current Battery Service state:\n level: 85\n status: 2\n plugged: 2"
|
|
)
|
|
df_out = (
|
|
"Filesystem 1K-blocks Used Available\n"
|
|
"/data 64000000 32000000 32000000"
|
|
)
|
|
server.run_shell_args.side_effect = [
|
|
ok(stdout=battery),
|
|
ok(stdout="10: wlan0 inet 192.168.1.100/24"),
|
|
ok(stdout="mWifiInfo SSID: MyNetwork, BSSID: ..."),
|
|
ok(stdout=df_out),
|
|
]
|
|
server.get_device_property.side_effect = lambda p, d=None: {
|
|
"ro.build.version.release": "14",
|
|
"ro.build.version.sdk": "34",
|
|
"ro.product.model": "Pixel 6",
|
|
"ro.product.manufacturer": "Google",
|
|
"ro.product.device": "oriole",
|
|
}.get(p)
|
|
|
|
result = await server.device_info()
|
|
assert result["success"] is True
|
|
assert result["battery"]["level"] == 85
|
|
assert result["ip_address"] == "192.168.1.100"
|
|
assert result["wifi_ssid"] == "MyNetwork"
|
|
assert result["model"] == "Pixel 6"
|
|
|
|
async def test_device_offline(self, server):
|
|
server.run_shell_args.return_value = fail("device offline")
|
|
result = await server.device_info()
|
|
assert result["success"] is False
|
|
|
|
|
|
class TestDeviceReboot:
|
|
@pytest.mark.usefixtures("_dev_mode")
|
|
async def test_reboot(self, server, ctx):
|
|
ctx.set_elicit("accept", "Yes, reboot now")
|
|
server.run_adb.return_value = ok()
|
|
result = await server.device_reboot(ctx)
|
|
assert result["success"] is True
|
|
assert result["mode"] == "normal"
|
|
|
|
@pytest.mark.usefixtures("_dev_mode")
|
|
async def test_reboot_recovery(self, server, ctx):
|
|
ctx.set_elicit("accept", "Yes, reboot now")
|
|
server.run_adb.return_value = ok()
|
|
result = await server.device_reboot(ctx, mode="recovery")
|
|
assert result["mode"] == "recovery"
|
|
|
|
@pytest.mark.usefixtures("_dev_mode")
|
|
async def test_cancelled(self, server, ctx):
|
|
ctx.set_elicit("accept", "Cancel")
|
|
result = await server.device_reboot(ctx)
|
|
assert result["success"] is False
|
|
assert result.get("cancelled") is True
|
|
|
|
@pytest.mark.usefixtures("_no_dev_mode")
|
|
async def test_requires_dev_mode(self, server, ctx):
|
|
result = await server.device_reboot(ctx)
|
|
assert result["success"] is False
|
|
|
|
|
|
class TestLogcat:
|
|
@pytest.mark.usefixtures("_dev_mode")
|
|
async def test_capture(self, server):
|
|
logline = "01-01 00:00:00.000 I/TAG: message"
|
|
server.run_shell_args.return_value = ok(stdout=logline)
|
|
result = await server.logcat_capture()
|
|
assert result["success"] is True
|
|
assert result["output"].startswith("01-01")
|
|
|
|
@pytest.mark.usefixtures("_dev_mode")
|
|
async def test_with_filter(self, server):
|
|
server.run_shell_args.return_value = ok(stdout="filtered output")
|
|
result = await server.logcat_capture(filter_spec="MyApp:D *:S")
|
|
assert result["filter"] == "MyApp:D *:S"
|
|
|
|
@pytest.mark.usefixtures("_dev_mode")
|
|
async def test_clear_first(self, server):
|
|
server.run_shell_args.side_effect = [ok(), ok(stdout="fresh logs")]
|
|
result = await server.logcat_capture(clear_first=True)
|
|
assert result["success"] is True
|
|
assert server.run_shell_args.call_count == 2
|
|
|
|
@pytest.mark.usefixtures("_no_dev_mode")
|
|
async def test_requires_dev_mode(self, server):
|
|
result = await server.logcat_capture()
|
|
assert result["success"] is False
|
|
|
|
@pytest.mark.usefixtures("_dev_mode")
|
|
async def test_logcat_clear(self, server):
|
|
server.run_shell_args.return_value = ok()
|
|
result = await server.logcat_clear()
|
|
assert result["success"] is True
|
|
assert result["action"] == "logcat_clear"
|