from types import SimpleNamespace from unittest.mock import AsyncMock from uuid import uuid4 import pytest from fastapi import HTTPException from app.api.v1.endpoints import agent_messages from app.auth.project_dependencies import ProjectContext from app.domain.domain_errors import DomainError from app.domain.schemas.agent_messages import AgentMessageCreate from app.main import app @pytest.fixture def anyio_backend(): return "asyncio" def test_private_message_and_exact_run_routes_are_in_contract(): paths = app.openapi()["paths"] assert "post" in paths["/api/v1/agent-messages"] assert "get" in paths["/api/v1/agent-messages/pending"] assert "post" in paths["/api/v1/agent-messages/{message_id}/reply"] assert "post" in paths["/api/v1/agent-messages/{message_id}/delivery"] assert "get" in paths["/api/v1/operational-tasks/{task_id}/runs/{run_id}"] parameters = paths["/api/v1/agent-messages"]["get"]["parameters"] assert {"session_id", "cursor", "pending_only"} <= {param["name"] for param in parameters} @pytest.mark.anyio async def test_message_route_preserves_structured_terminal_rejection(monkeypatch): service = SimpleNamespace(create=AsyncMock(side_effect=DomainError( "RUN_TERMINAL", "Run no longer accepts messages", status=409))) monkeypatch.setattr(agent_messages, "_service", lambda ctx, conn: service) context = ProjectContext(uuid4(), "test", uuid4(), "member") with pytest.raises(HTTPException) as error: await agent_messages.create_agent_message(AgentMessageCreate( request_id=uuid4(), task_id=uuid4(), run_id=uuid4(), source_session_id="main", text="当前情况?"), ctx=context, conn=object()) assert error.value.status_code == 409 and error.value.detail["code"] == "RUN_TERMINAL"