mirror of
https://github.com/rennf93/roboco.git
synced 2026-08-03 07:23:24 +02:00
93 lines
3.0 KiB
Python
93 lines
3.0 KiB
Python
"""roboco-intake MCP server — propose_draft delivers the draft to the relay."""
|
|||
|
|
|
||
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
from typing import Any
|
||
|
|
|
||
|
|
import httpx
|
||
|
|
import pytest
|
||
|
|
from roboco.mcp import intake_server
|
||
|
|
|
||
|
|
|
||
|
|
def _client(handler: Any) -> httpx.AsyncClient:
|
||
|
|
return httpx.AsyncClient(transport=httpx.MockTransport(handler))
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.mark.asyncio
|
||
|
|
async def test_post_draft_posts_to_the_relay(monkeypatch: pytest.MonkeyPatch) -> None:
|
||
|
|
monkeypatch.setenv("ROBOCO_API_URL", "http://orch:8000")
|
||
|
|
seen: dict[str, Any] = {}
|
||
|
|
|
||
|
|
def handler(request: httpx.Request) -> httpx.Response:
|
||
|
|
seen["url"] = str(request.url)
|
||
|
|
seen["json"] = __import__("json").loads(request.content)
|
||
|
|
return httpx.Response(200, json={"ok": True})
|
||
|
|
|
||
|
|
async with _client(handler) as client:
|
||
|
|
result = await intake_server.post_draft(
|
||
|
|
"sess-1", {"title": "Build X"}, client=client
|
||
|
|
)
|
||
|
|
|
||
|
|
assert result == {"ok": True}
|
||
|
|
assert seen["url"] == "http://orch:8000/api/prompter/live/sess-1/events"
|
||
|
|
assert seen["json"]["kind"] == "draft"
|
||
|
|
assert seen["json"]["tool"] == "propose_draft"
|
||
|
|
assert seen["json"]["data"] == {"title": "Build X"}
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.mark.asyncio
|
||
|
|
async def test_post_draft_reports_http_error() -> None:
|
||
|
|
def handler(_request: httpx.Request) -> httpx.Response:
|
||
|
|
return httpx.Response(503)
|
||
|
|
|
||
|
|
async with _client(handler) as client:
|
||
|
|
result = await intake_server.post_draft("s", {}, client=client)
|
||
|
|
assert result == {"error": "http_503"}
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.mark.asyncio
|
||
|
|
async def test_post_draft_reports_request_failure() -> None:
|
||
|
|
def handler(_request: httpx.Request) -> httpx.Response:
|
||
|
|
raise httpx.ConnectError("boom")
|
||
|
|
|
||
|
|
async with _client(handler) as client:
|
||
|
|
result = await intake_server.post_draft("s", {}, client=client)
|
||
|
|
assert result["error"] == "request_failed"
|
||
|
|
assert "boom" in result["detail"]
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.mark.asyncio
|
||
|
|
async def test_propose_draft_requires_a_live_session(
|
||
|
|
monkeypatch: pytest.MonkeyPatch,
|
||
|
|
) -> None:
|
||
|
|
monkeypatch.delenv("ROBOCO_PROMPTER_SESSION_ID", raising=False)
|
||
|
|
msg = await intake_server.propose_draft({"title": "X"})
|
||
|
|
assert "No live session id" in msg
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.mark.asyncio
|
||
|
|
async def test_propose_draft_acks_on_success(monkeypatch: pytest.MonkeyPatch) -> None:
|
||
|
|
monkeypatch.setenv("ROBOCO_PROMPTER_SESSION_ID", "sess-1")
|
||
|
|
|
||
|
|
async def _ok(_sid: str, _draft: dict[str, Any]) -> dict[str, Any]:
|
||
|
|
return {"ok": True}
|
||
|
|
|
||
|
|
monkeypatch.setattr(intake_server, "post_draft", _ok)
|
||
|
|
msg = await intake_server.propose_draft({"title": "X"})
|
||
|
|
assert "Draft submitted" in msg
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.mark.asyncio
|
||
|
|
async def test_propose_draft_reports_relay_failure(
|
||
|
|
monkeypatch: pytest.MonkeyPatch,
|
||
|
|
) -> None:
|
||
|
|
monkeypatch.setenv("ROBOCO_PROMPTER_SESSION_ID", "sess-1")
|
||
|
|
|
||
|
|
async def _fail(_sid: str, _draft: dict[str, Any]) -> dict[str, Any]:
|
||
|
|
return {"error": "http_503"}
|
||
|
|
|
||
|
|
monkeypatch.setattr(intake_server, "post_draft", _fail)
|
||
|
|
msg = await intake_server.propose_draft({"title": "X"})
|
||
|
|
assert "Could not submit the draft" in msg
|
||
|
|
assert "http_503" in msg
|