refactor(device): remove single-device state and test branches

This commit is contained in:
somew1nd committed 2026-09-01 11:50:14 -07:00
1 parent cbe8f4f0c6
commit 33c4a0d112
12 files changed
+175 -88

No files matched your search

@@ -78,8 +78,8 @@ async def test_run_task_enqueues_when_device_is_unlocked(monkeypatch):
@pytest.mark.asyncio
async def test_run_task_switches_to_unlocked_device_and_syncs_engine(monkeypatch):
"""When default device is locked, run_task should enqueue on verified fallback and update engine."""
async def test_run_task_binds_probe_verified_device_when_no_serial_requested(monkeypatch):
"""Without an explicit serial, run_task enqueues on the probe-verified live device."""
unlocked_probe = ProbeResult(
id="android_adb",
category=ProbeCategory.DEVICE,
@@ -100,9 +100,6 @@ async def test_run_task_switches_to_unlocked_device_and_syncs_engine(monkeypatch
tasks.readiness_engine, "run_device_submission_probe", run_probe
)
monkeypatch.setattr(tasks.task_queue_service, "enqueue_tasks", enqueue_tasks)
monkeypatch.setattr(tasks.readiness_engine, "get_active_device_serial", lambda: "device-locked-1")
set_active_mock = AsyncMock()
monkeypatch.setattr(tasks.readiness_engine, "set_active_device_serial", set_active_mock)
result = await tasks.run_task(RunRequest(goal="Run on any ready device"))
@@ -111,7 +108,6 @@ async def test_run_task_switches_to_unlocked_device_and_syncs_engine(monkeypatch
# Check that device_serial passed to enqueue_tasks is the verified unlocked device
_, kwargs = enqueue_tasks.call_args
assert kwargs.get("device_serial") == "emulator-5556"
set_active_mock.assert_called_once_with("emulator-5556")
@pytest.mark.asyncio
@@ -222,10 +222,6 @@ async def test_queue_worker_execution_lifecycle():
patch("asyncio.create_subprocess_exec", side_effect=fake_subprocess_exec),
patch("apps.admin_console.services.task_queue_service.session_repo") as mock_repo,
patch("apps.admin_console.services.task_queue_service.media_service"),
patch(
"artemis.core.diagnostics.readiness_engine.get_active_device_serial",
return_value=None,
),
patch(
"artemis.runtime.device_pool.device_pool.select_device",
return_value="emulator-5554",
@@ -272,10 +268,6 @@ async def test_queue_worker_cmd_construction():
patch("asyncio.create_subprocess_exec", side_effect=fake_subprocess_exec),
patch("apps.admin_console.services.task_queue_service.session_repo") as mock_repo,
patch("apps.admin_console.services.task_queue_service.media_service"),
patch(
"artemis.core.diagnostics.readiness_engine.get_active_device_serial",
return_value=None,
),
patch(
"artemis.runtime.device_pool.device_pool.select_device",
return_value="emulator-5554",
@@ -489,6 +481,48 @@ def test_stop_tasks_does_not_kill_stale_reused_pid():
terminate_verified.assert_not_called()
def test_stop_tasks_session_target_never_adopts_mismatched_fallback_owner():
"""No live owners is a legal state: a session-targeted stop must not
terminate a fallback owner that belongs to a different session."""
other_owner = DeviceLockOwner(
pid=24680,
process_created_at=1234.5,
token="other-owner-token",
device_id="emulator-5554",
description="Task for another session",
acquired_at="2026-08-24T00:00:00+00:00",
session_id="other-session",
ingress="cli",
)
with (
patch(
"apps.admin_console.services.task_queue_service.DeviceExecutionLock.get_active_owners",
return_value={},
),
patch(
"apps.admin_console.services.task_queue_service.DeviceExecutionLock.get_active_owner",
return_value=other_owner,
),
patch(
"apps.admin_console.services.task_queue_service.DeviceExecutionLock.is_active_owner",
return_value=True,
),
patch(
"apps.admin_console.services.task_queue_service.process_supervisor.terminate_tree_verified"
) as terminate_verified,
patch(
"apps.admin_console.services.task_queue_service.session_repo.update_session_status"
),
patch(
"apps.admin_console.services.task_queue_service.session_repo.get_session_by_id",
return_value=None,
),
):
task_queue_service.stop_tasks(clear_all=False, session_id="wanted-session")
terminate_verified.assert_not_called()
@pytest.mark.asyncio
async def test_status_reports_external_global_owner_without_ipc_connection():
external_owner = DeviceLockOwner(
@@ -548,10 +582,6 @@ async def test_cancel_task_triggers_next_pending_task():
patch("asyncio.create_subprocess_exec", side_effect=fake_subprocess_exec),
patch("apps.admin_console.services.task_queue_service.session_repo") as mock_repo,
patch("apps.admin_console.services.task_queue_service.media_service"),
patch(
"artemis.core.diagnostics.readiness_engine.get_active_device_serial",
return_value=None,
),
patch(
"artemis.runtime.device_pool.device_pool.select_device",
return_value="emulator-5554",
@@ -603,10 +633,6 @@ async def test_immediate_cancel_ignores_stale_ipc_and_runs_next_task():
patch("asyncio.create_subprocess_exec", side_effect=fake_subprocess_exec),
patch("apps.admin_console.services.task_queue_service.session_repo") as mock_repo,
patch("apps.admin_console.services.task_queue_service.media_service"),
patch(
"artemis.core.diagnostics.readiness_engine.get_active_device_serial",
return_value=None,
),
patch(
"artemis.runtime.device_pool.device_pool.select_device",
return_value="emulator-5554",
+6 -4
View File
@@ -392,11 +392,13 @@ async def test_toolchain_probe_structure():
@pytest.mark.asyncio
async def test_active_device_selection():
"""Verify selecting a device updates engine state."""
async def test_probe_target_serial_forwards_to_adb_probe():
"""Verify the probe target preference reaches the ADB probe and can be cleared."""
engine = ReadinessEngine()
engine.set_active_device_serial("test-emulator-1234")
assert engine.get_active_device_serial() == "test-emulator-1234"
engine.set_probe_target_serial("test-emulator-1234")
assert engine._adb_probe._target_serial == "test-emulator-1234"
engine.set_probe_target_serial(None)
assert engine._adb_probe._target_serial is None
@pytest.mark.asyncio
+21 -2
View File
@@ -156,11 +156,30 @@ def test_disconnect_reconciliation_stops_heartbeat_and_allows_reenrollment(
assert configure.call_count == 2
@patch("artemis.runtime.device_pool.device_pool.get_claimed_serials")
@patch("artemis.runtime.awake_service.AdbClient")
def test_discovery_honors_single_device_policy(adb_client):
def test_discovery_keeps_only_pool_claimed_devices(adb_client, claimed):
"""The pool manages two devices while the ADB server lists three: only the
two claimed devices are kept awake; the unrelated one is left untouched."""
adb_client.return_value.device_list.return_value = [
MagicMock(serial="device-1"),
MagicMock(serial="device-2"),
MagicMock(serial="device-3"),
]
claimed.return_value = {"device-1", "device-2"}
assert _discover_connected_device_ids() == ["device-1", "device-2"]
@patch(
"artemis.runtime.device_pool.device_pool.get_claimed_serials",
return_value=set(),
)
@patch("artemis.runtime.awake_service.AdbClient")
def test_discovery_returns_nothing_when_pool_claims_no_device(adb_client, _claimed):
adb_client.return_value.device_list.return_value = [
MagicMock(serial="device-1"),
MagicMock(serial="device-2"),
]
assert _discover_connected_device_ids() == ["device-1"]
assert _discover_connected_device_ids() == []
+27
View File
@@ -91,6 +91,33 @@ def test_device_pool_list_devices_and_busy_status(monkeypatch):
lock.release()
def test_get_claimed_serials_reflects_locks_and_reservations():
pool = DevicePool()
assert pool.get_claimed_serials() == set()
lock = DeviceExecutionLock("emulator-5554", "claimed by test")
lock.acquire()
bound_ticket = DeviceExecutionLock.reserve(
description="queued task",
device_id="pixel-8-pro",
session_id="queued-session",
)
unbound_ticket = DeviceExecutionLock.reserve(
description="unbound task",
device_id="pending",
session_id="pending-session",
)
try:
# Locked and reserved serials are claimed; the unbound placeholder is not.
assert pool.get_claimed_serials() == {"emulator-5554", "pixel-8-pro"}
finally:
DeviceExecutionLock.cancel_reservation(bound_ticket)
DeviceExecutionLock.cancel_reservation(unbound_ticket)
lock.release()
assert pool.get_claimed_serials() == set()
RAW_DEVICE = ("emulator-5554", "device", "Emulator", "sdk")