fix(android): launch apps with checked activity manager commands

This commit is contained in:
chenmingxuan committed 2026-10-16 11:15:14 +08:00
1 parent ef7af9988e
commit f86db1ced6
8 files changed
+334 -15

No files matched your search

+54 -2
View File
@@ -15,6 +15,7 @@
from unittest.mock import AsyncMock, Mock, patch
from artemis.context import ArtemisContext
from artemis.drivers.errors import AppLaunchError
from artemis.utils.app_launch_utils import (
ForegroundTask,
_handle_initial_app_launch,
@@ -375,7 +376,7 @@ async def test_launch_timeout_message_names_foreground_package_and_task(
mock_get_task.return_value = parse_foreground_task(DUMP_SEARCH_IN_OWN_TASK)
with patch("artemis.utils.app_launch_utils.logger") as mock_logger:
success, _ = await launch_app_with_retries(
success, detail = await launch_app_with_retries(
mock_context, SETTINGS, max_retries=1, max_poll_seconds=1
)
@@ -383,7 +384,7 @@ async def test_launch_timeout_message_names_foreground_package_and_task(
timeout_messages = [
call.args[0]
for call in mock_logger.error.call_args_list
if "Timeout waiting" in call.args[0]
if call.args[0].startswith("Timeout waiting")
]
assert len(timeout_messages) == 1
message = timeout_messages[0]
@@ -391,6 +392,7 @@ async def test_launch_timeout_message_names_foreground_package_and_task(
assert "task #120" in message
assert f"base={SETTINGS_SEARCH}" in message
assert f"resumed={SETTINGS_SEARCH}/.modules.search.SearchActivity" in message
assert message in detail
@pytest.mark.asyncio
@@ -418,6 +420,56 @@ async def test_launch_app_null_focus_keeps_polling_without_reading_task(
# ---------------------------------------------------------------------------
@pytest.mark.asyncio
async def test_deterministic_launch_failure_skips_polling_and_retry(mock_context):
error = AppLaunchError("am 启动失败:Permission Denial(退出码 1)")
with (
patch("artemis.utils.app_launch_utils.UnifiedMobileController") as controller_cls,
patch("artemis.utils.app_launch_utils._poll_for_app_ready", new_callable=AsyncMock) as poll,
):
controller = _controller(controller_cls)
controller.launch_app.side_effect = error
result, detail = await launch_app_with_retries(mock_context, SETTINGS)
assert result is False
assert detail == str(error)
controller.launch_app.assert_awaited_once()
controller.terminate_app.assert_not_called()
poll.assert_not_called()
@pytest.mark.asyncio
async def test_start_acknowledgement_timeout_checks_foreground_before_relaunch(mock_context):
with (
patch("artemis.utils.app_launch_utils.UnifiedMobileController") as controller_cls,
patch("artemis.utils.app_launch_utils._poll_for_app_ready", new_callable=AsyncMock) as poll,
):
controller = _controller(controller_cls)
controller.launch_app.side_effect = AppLaunchError(
"ADB timeout", retryable=True, may_have_started=True
)
poll.return_value = (True, None)
assert await launch_app_with_retries(mock_context, SETTINGS) == (True, None)
controller.launch_app.assert_awaited_once()
controller.terminate_app.assert_not_called()
poll.assert_awaited_once()
@pytest.mark.asyncio
async def test_transient_launch_failure_is_bounded_and_keeps_cause(mock_context):
with (
patch("artemis.utils.app_launch_utils.UnifiedMobileController") as controller_cls,
patch("artemis.utils.app_launch_utils._poll_for_app_ready", new_callable=AsyncMock) as poll,
patch("artemis.utils.app_launch_utils.asyncio.sleep", new_callable=AsyncMock),
):
controller = _controller(controller_cls)
controller.launch_app.side_effect = AppLaunchError("device offline", retryable=True)
result, detail = await launch_app_with_retries(mock_context, SETTINGS)
assert result is False
assert detail == "device offline"
assert controller.launch_app.await_count == 3
poll.assert_not_called()
@pytest.mark.asyncio
@patch("artemis.utils.app_launch_utils.launch_app_with_retries")
@patch("artemis.utils.app_launch_utils.get_foreground_task")