mirror of
https://github.com/Sea-Haven-Industries/open-swe.git
synced 2026-09-30 11:33:14 +00:00
Applies the plan's C5 step: git mv every test per the domain-reorg
move-map (movemap-m50.txt) into tests/{agent,analyzer,auth,dashboard,
github,middleware,models,reviewer,sandbox,slack,tools,webhooks}/, plus
the 13 fork-only placements from the scoping report §2c (Atlassian
webhook tests -> tests/webhooks/, test_atlassian_connect.py and
test_auth_error_leak.py -> tests/auth/, jira/confluence util tests ->
tests/tools/, test_repo_binding_isolation.py -> tests/sandbox/,
bot-identity/autofix tests -> tests/github/).
Path-only move: the only content edits are parents[1] -> parents[2]
fixes in test_e2b_integration.py and test_daytona_integration.py,
required because their __file__-relative ROOT path gained one more
directory level in the move.
Monkeypatch retargets for these files were already completed in C4;
none remained outstanding here.
68 lines
2.7 KiB
Python
68 lines
2.7 KiB
Python
from __future__ import annotations
|
|
|
|
from datetime import UTC, datetime, timedelta
|
|
from unittest.mock import AsyncMock, patch
|
|
|
|
import pytest
|
|
|
|
from agent.dashboard import eval_jobs
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_get_status_returns_idle_when_no_record() -> None:
|
|
with patch.object(eval_jobs, "_get_record", new=AsyncMock(return_value=None)):
|
|
status = await eval_jobs.get_reviewer_eval_status()
|
|
assert status["status"] == "idle"
|
|
assert status["name"] == eval_jobs.REVIEWER_EVAL_KEY
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_get_status_returns_terminal_record_unchanged() -> None:
|
|
record = {"name": "reviewer", "status": "completed", "experiment_url": "https://x"}
|
|
with (
|
|
patch.object(eval_jobs, "_get_record", new=AsyncMock(return_value=record)),
|
|
patch.object(eval_jobs, "_put_record", new=AsyncMock(side_effect=lambda r: r)) as put,
|
|
):
|
|
status = await eval_jobs.get_reviewer_eval_status()
|
|
assert status is record
|
|
put.assert_not_awaited()
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_get_status_reconciles_stale_running() -> None:
|
|
stale = (datetime.now(UTC) - timedelta(seconds=300)).isoformat()
|
|
record = {"name": "reviewer", "status": "running", "heartbeat": stale}
|
|
with (
|
|
patch.object(eval_jobs, "_get_record", new=AsyncMock(return_value=record)),
|
|
patch.object(eval_jobs, "_put_record", new=AsyncMock(side_effect=lambda r: r)) as put,
|
|
):
|
|
status = await eval_jobs.get_reviewer_eval_status()
|
|
assert status["status"] == "failed"
|
|
assert "no longer tracked" in status["error"]
|
|
put.assert_awaited_once()
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_get_status_keeps_running_with_fresh_heartbeat() -> None:
|
|
"""A poll must not kill a run whose Action is still heartbeating."""
|
|
fresh = datetime.now(UTC).isoformat()
|
|
record = {"name": "reviewer", "status": "running", "heartbeat": fresh}
|
|
with (
|
|
patch.object(eval_jobs, "_get_record", new=AsyncMock(return_value=record)),
|
|
patch.object(eval_jobs, "_put_record", new=AsyncMock(side_effect=lambda r: r)) as put,
|
|
):
|
|
status = await eval_jobs.get_reviewer_eval_status()
|
|
assert status["status"] == "running"
|
|
put.assert_not_awaited()
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_get_status_fails_running_without_heartbeat() -> None:
|
|
"""A running record with no heartbeat at all is treated as stale."""
|
|
record = {"name": "reviewer", "status": "running"}
|
|
with (
|
|
patch.object(eval_jobs, "_get_record", new=AsyncMock(return_value=record)),
|
|
patch.object(eval_jobs, "_put_record", new=AsyncMock(side_effect=lambda r: r)),
|
|
):
|
|
status = await eval_jobs.get_reviewer_eval_status()
|
|
assert status["status"] == "failed"
|