mirror of
https://github.com/rennf93/roboco.git
synced 2026-08-03 07:23:24 +02:00
test(grok): mypy-clean the reaper watchdog + interactive spawn tests
The CI mypy scope (roboco/ tests/) flagged test-only typing issues my per-file runs missed: direct method assignment (orch._remove_container = AsyncMock()) trips [method-assign], and a module-level dict[str,str] is invariant against the dict[str, str|None] the run-spec expects. - Use monkeypatch.setattr for _remove_container in the watchdog tests. - Annotate the shared _HOSTS as dict[str, str | None]. Production code unchanged; mypy roboco/ tests/ is green.
This commit is contained in:
@@ -15,7 +15,7 @@ from roboco.runtime.orchestrator import (
|
|||||||
_SecretaryRunSpec,
|
_SecretaryRunSpec,
|
||||||
)
|
)
|
||||||
|
|
||||||
_HOSTS = {
|
_HOSTS: dict[str, str | None] = {
|
||||||
"claude": "/h/.claude",
|
"claude": "/h/.claude",
|
||||||
"prompt": "/h/p.md",
|
"prompt": "/h/p.md",
|
||||||
"workspaces": "/h/ws",
|
"workspaces": "/h/ws",
|
||||||
|
|||||||
@@ -148,7 +148,9 @@ def _grok_instance() -> AgentInstance:
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_reaper_kills_and_releases_wedged_grok_container() -> None:
|
async def test_reaper_kills_and_releases_wedged_grok_container(
|
||||||
|
monkeypatch: pytest.MonkeyPatch,
|
||||||
|
) -> None:
|
||||||
"""A GROK container idle past the kill TTL is killed, evicted, and released.
|
"""A GROK container idle past the kill TTL is killed, evicted, and released.
|
||||||
|
|
||||||
Unlike a Claude agent, a wedged opencode container is ACTIVE yet fires no
|
Unlike a Claude agent, a wedged opencode container is ACTIVE yet fires no
|
||||||
@@ -173,20 +175,23 @@ async def test_reaper_kills_and_releases_wedged_grok_container() -> None:
|
|||||||
orch._claim_heartbeat_ttl = 300
|
orch._claim_heartbeat_ttl = 300
|
||||||
orch._grok_idle_kill_ttl = 900
|
orch._grok_idle_kill_ttl = 900
|
||||||
orch._instances = {"be-dev-1": _grok_instance()}
|
orch._instances = {"be-dev-1": _grok_instance()}
|
||||||
orch._remove_container = AsyncMock()
|
remove_mock = AsyncMock()
|
||||||
|
monkeypatch.setattr(orch, "_remove_container", remove_mock)
|
||||||
svc = AsyncMock()
|
svc = AsyncMock()
|
||||||
svc.list_in_progress_or_claimed.return_value = [wedged]
|
svc.list_in_progress_or_claimed.return_value = [wedged]
|
||||||
svc.unclaim_for_reaper = AsyncMock()
|
svc.unclaim_for_reaper = AsyncMock()
|
||||||
|
|
||||||
await orch._reap_with_service(svc)
|
await orch._reap_with_service(svc)
|
||||||
|
|
||||||
orch._remove_container.assert_awaited_once_with("roboco-agent-be-dev-1")
|
remove_mock.assert_awaited_once_with("roboco-agent-be-dev-1")
|
||||||
assert "be-dev-1" not in orch._instances # evicted
|
assert "be-dev-1" not in orch._instances # evicted
|
||||||
svc.unclaim_for_reaper.assert_awaited_once_with(task_id) # released
|
svc.unclaim_for_reaper.assert_awaited_once_with(task_id) # released
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_reaper_spares_grok_container_within_kill_ttl() -> None:
|
async def test_reaper_spares_grok_container_within_kill_ttl(
|
||||||
|
monkeypatch: pytest.MonkeyPatch,
|
||||||
|
) -> None:
|
||||||
"""A GROK container stale past the claim TTL but within the kill TTL lives.
|
"""A GROK container stale past the claim TTL but within the kill TTL lives.
|
||||||
|
|
||||||
Only a truly-dead run (idle past the longer grok-idle TTL) is killed — a
|
Only a truly-dead run (idle past the longer grok-idle TTL) is killed — a
|
||||||
@@ -208,20 +213,23 @@ async def test_reaper_spares_grok_container_within_kill_ttl() -> None:
|
|||||||
orch._claim_heartbeat_ttl = 300
|
orch._claim_heartbeat_ttl = 300
|
||||||
orch._grok_idle_kill_ttl = 900
|
orch._grok_idle_kill_ttl = 900
|
||||||
orch._instances = {"be-dev-1": _grok_instance()}
|
orch._instances = {"be-dev-1": _grok_instance()}
|
||||||
orch._remove_container = AsyncMock()
|
remove_mock = AsyncMock()
|
||||||
|
monkeypatch.setattr(orch, "_remove_container", remove_mock)
|
||||||
svc = AsyncMock()
|
svc = AsyncMock()
|
||||||
svc.list_in_progress_or_claimed.return_value = [recent]
|
svc.list_in_progress_or_claimed.return_value = [recent]
|
||||||
svc.unclaim_for_reaper = AsyncMock()
|
svc.unclaim_for_reaper = AsyncMock()
|
||||||
|
|
||||||
await orch._reap_with_service(svc)
|
await orch._reap_with_service(svc)
|
||||||
|
|
||||||
orch._remove_container.assert_not_awaited()
|
remove_mock.assert_not_awaited()
|
||||||
assert "be-dev-1" in orch._instances
|
assert "be-dev-1" in orch._instances
|
||||||
svc.unclaim_for_reaper.assert_not_awaited()
|
svc.unclaim_for_reaper.assert_not_awaited()
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_reaper_never_kills_non_grok_container() -> None:
|
async def test_reaper_never_kills_non_grok_container(
|
||||||
|
monkeypatch: pytest.MonkeyPatch,
|
||||||
|
) -> None:
|
||||||
"""A non-GROK (Claude) container idle past the kill TTL is still spared.
|
"""A non-GROK (Claude) container idle past the kill TTL is still spared.
|
||||||
|
|
||||||
The watchdog only kills GROK runtimes; a quiet Claude agent keeps the
|
The watchdog only kills GROK runtimes; a quiet Claude agent keeps the
|
||||||
@@ -248,13 +256,14 @@ async def test_reaper_never_kills_non_grok_container() -> None:
|
|||||||
agent_id="be-dev-1", state=AgentState.ACTIVE, config=claude_cfg
|
agent_id="be-dev-1", state=AgentState.ACTIVE, config=claude_cfg
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
orch._remove_container = AsyncMock()
|
remove_mock = AsyncMock()
|
||||||
|
monkeypatch.setattr(orch, "_remove_container", remove_mock)
|
||||||
svc = AsyncMock()
|
svc = AsyncMock()
|
||||||
svc.list_in_progress_or_claimed.return_value = [claude_task]
|
svc.list_in_progress_or_claimed.return_value = [claude_task]
|
||||||
svc.unclaim_for_reaper = AsyncMock()
|
svc.unclaim_for_reaper = AsyncMock()
|
||||||
|
|
||||||
await orch._reap_with_service(svc)
|
await orch._reap_with_service(svc)
|
||||||
|
|
||||||
orch._remove_container.assert_not_awaited()
|
remove_mock.assert_not_awaited()
|
||||||
assert "be-dev-1" in orch._instances
|
assert "be-dev-1" in orch._instances
|
||||||
svc.unclaim_for_reaper.assert_not_awaited()
|
svc.unclaim_for_reaper.assert_not_awaited()
|
||||||
|
|||||||
Reference in New Issue
Block a user