feat: extend operational investigation workflows
Generic Container CI/CD / test-build-publish (push) Successful in 3m53s
Server CI/CD v2 / build-test-publish-and-deploy (push) Successful in 3m52s

This commit is contained in:
2026-10-30 17:30:19 +08:00
parent 63af998045
commit 05183aff93
82 changed files with 4644 additions and 330 deletions
@@ -17,12 +17,19 @@ def anyio_backend():
@pytest.mark.anyio
@pytest.mark.parametrize("available", [False, True])
async def test_execution_requires_message_storage(available):
cursor = SimpleNamespace(fetchone=AsyncMock(return_value={"available": available}))
@pytest.mark.parametrize("available,agent_ownership_available,ready", [
(False, False, False), (True, False, False), (True, True, True),
])
async def test_execution_requires_message_and_agent_ownership_storage(
available, agent_ownership_available, ready,
):
cursor = SimpleNamespace(fetchone=AsyncMock(return_value={
"available": available,
"agent_ownership_available": agent_ownership_available,
}))
connection = SimpleNamespace(execute=AsyncMock(return_value=cursor))
repository = OperationalTaskRepository(connection, uuid4())
if available:
if ready:
await repository.require_execution_storage()
else:
with pytest.raises(DomainError) as failure:
@@ -30,9 +37,31 @@ async def test_execution_requires_message_storage(available):
assert failure.value.status == 503
assert failure.value.code == "DEPENDENCY_UNAVAILABLE"
assert "024_agent_messages.sql" in failure.value.message
assert "030_operational_run_agent_ownership.sql" in failure.value.message
assert "to_regclass('workbench.agent_messages')" in connection.execute.call_args.args[0]
@pytest.mark.anyio
@pytest.mark.parametrize("available", [False, True])
async def test_run_update_uses_agent_owner_column_only_after_migration(available):
availability = SimpleNamespace(fetchone=AsyncMock(return_value={"available": available}))
updated = SimpleNamespace(rowcount=1)
connection = SimpleNamespace(execute=AsyncMock(side_effect=[availability, updated]))
repository = OperationalTaskRepository(connection, uuid4())
run_id = str(uuid4())
await repository.update_run({
"run_id": run_id, "status": "running", "revision": 2,
"agent_session_id": "session-1", "agent_instance_id": "agent-a",
"lease_expires_at": None, "heartbeat_at": None, "started_at": None,
"finished_at": None, "failure_code": None, "failure_detail": None,
"dispatch_attempts": 0, "next_dispatch_at": None, "updated_at": None,
}, 1)
query, params = connection.execute.call_args.args
assert ("agent_instance_id=%s" in query) is available
assert ("agent-a" in params) is available
@pytest.mark.anyio
async def test_missing_message_storage_rejects_claim_before_state_changes():
@asynccontextmanager
@@ -56,3 +85,16 @@ async def test_missing_message_storage_rejects_claim_before_state_changes():
repository.lock.assert_not_awaited()
repository.update_run.assert_not_awaited()
repository.update_task.assert_not_awaited()
@pytest.mark.anyio
async def test_presentation_history_storage_filters_project_task_and_committed_cursor():
project_id, task_id = uuid4(), uuid4()
connection = SimpleNamespace(execute=AsyncMock(return_value=SimpleNamespace(fetchall=AsyncMock(return_value=[]))))
repository = OperationalTaskRepository(connection, project_id)
assert await repository.list_presentation_events(str(task_id), 7, 30, 21) == []
query, params = connection.execute.call_args.args
assert params == (str(project_id), str(task_id), 7, 30, 21)
assert "project_id=%s" in query and "aggregate_id=%s" in query
assert "operational.presentation.requested" in query and "event_seq<=%s" in query
assert "ORDER BY event_seq LIMIT %s" in query