test(sofiia-console): cover idempotency and cursor pagination contracts
Add focused API contract tests for chat idempotency, cursor pagination, and node routing behavior using isolated local fixtures and mocked upstream inference. Made-with: Cursor
This commit is contained in:
95
tests/test_sofiia_chat_idempotency.py
Normal file
95
tests/test_sofiia_chat_idempotency.py
Normal file
@@ -0,0 +1,95 @@
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
def _create_chat(client, agent_id: str, node_id: str, ref: str) -> str:
|
||||
r = client.post(
|
||||
"/api/chats",
|
||||
json={
|
||||
"agent_id": agent_id,
|
||||
"node_id": node_id,
|
||||
"source": "web",
|
||||
"external_chat_ref": ref,
|
||||
},
|
||||
)
|
||||
assert r.status_code == 200, r.text
|
||||
return r.json()["chat"]["chat_id"]
|
||||
|
||||
|
||||
def test_send_idempotency_header_replays_same_message_id(sofiia_client, sofiia_module, monkeypatch):
|
||||
async def _fake_infer(base_url, agent_id, text, **kwargs):
|
||||
return {"response": f"ok:{agent_id}:{text}", "backend": "fake", "model": "fake-model"}
|
||||
|
||||
monkeypatch.setattr(sofiia_module, "infer", _fake_infer)
|
||||
chat_id = _create_chat(sofiia_client, "sofiia", "NODA2", "idem-header")
|
||||
headers = {"Idempotency-Key": "idem-header-1"}
|
||||
|
||||
r1 = sofiia_client.post(f"/api/chats/{chat_id}/send", json={"text": "ping"}, headers=headers)
|
||||
r2 = sofiia_client.post(f"/api/chats/{chat_id}/send", json={"text": "ping"}, headers=headers)
|
||||
assert r1.status_code == 200 and r2.status_code == 200
|
||||
|
||||
j1, j2 = r1.json(), r2.json()
|
||||
assert j1["message"]["message_id"] == j2["message"]["message_id"]
|
||||
assert j1["idempotency"]["replayed"] is False
|
||||
assert j2["idempotency"]["replayed"] is True
|
||||
|
||||
|
||||
def test_send_idempotency_body_replays_same_message_id(sofiia_client, sofiia_module, monkeypatch):
|
||||
async def _fake_infer(base_url, agent_id, text, **kwargs):
|
||||
return {"response": f"ok:{agent_id}:{text}", "backend": "fake", "model": "fake-model"}
|
||||
|
||||
monkeypatch.setattr(sofiia_module, "infer", _fake_infer)
|
||||
chat_id = _create_chat(sofiia_client, "sofiia", "NODA2", "idem-body")
|
||||
payload = {"text": "ping", "idempotency_key": "idem-body-1"}
|
||||
|
||||
r1 = sofiia_client.post(f"/api/chats/{chat_id}/send", json=payload)
|
||||
r2 = sofiia_client.post(f"/api/chats/{chat_id}/send", json=payload)
|
||||
assert r1.status_code == 200 and r2.status_code == 200
|
||||
|
||||
j1, j2 = r1.json(), r2.json()
|
||||
assert j1["message"]["message_id"] == j2["message"]["message_id"]
|
||||
assert j1["idempotency"]["replayed"] is False
|
||||
assert j2["idempotency"]["replayed"] is True
|
||||
|
||||
|
||||
def test_send_idempotency_header_overrides_body(sofiia_client, sofiia_module, monkeypatch):
|
||||
async def _fake_infer(base_url, agent_id, text, **kwargs):
|
||||
return {"response": f"ok:{agent_id}:{text}", "backend": "fake", "model": "fake-model"}
|
||||
|
||||
monkeypatch.setattr(sofiia_module, "infer", _fake_infer)
|
||||
chat_id = _create_chat(sofiia_client, "sofiia", "NODA2", "idem-override")
|
||||
|
||||
r1 = sofiia_client.post(
|
||||
f"/api/chats/{chat_id}/send",
|
||||
json={"text": "ping-a", "idempotency_key": "body-a"},
|
||||
headers={"Idempotency-Key": "header-wins"},
|
||||
)
|
||||
r2 = sofiia_client.post(
|
||||
f"/api/chats/{chat_id}/send",
|
||||
json={"text": "ping-b", "idempotency_key": "body-b"},
|
||||
headers={"Idempotency-Key": "header-wins"},
|
||||
)
|
||||
assert r1.status_code == 200 and r2.status_code == 200
|
||||
j1, j2 = r1.json(), r2.json()
|
||||
assert j1["message"]["message_id"] == j2["message"]["message_id"]
|
||||
assert j2["idempotency"]["replayed"] is True
|
||||
assert j2["idempotency"]["key"] == "header-wins"
|
||||
|
||||
|
||||
def test_send_idempotency_different_keys_create_different_message_ids(sofiia_client, sofiia_module, monkeypatch):
|
||||
async def _fake_infer(base_url, agent_id, text, **kwargs):
|
||||
return {"response": f"ok:{agent_id}:{text}", "backend": "fake", "model": "fake-model"}
|
||||
|
||||
monkeypatch.setattr(sofiia_module, "infer", _fake_infer)
|
||||
chat_id = _create_chat(sofiia_client, "sofiia", "NODA2", "idem-different")
|
||||
|
||||
r1 = sofiia_client.post(
|
||||
f"/api/chats/{chat_id}/send",
|
||||
json={"text": "ping", "idempotency_key": "k1"},
|
||||
)
|
||||
r2 = sofiia_client.post(
|
||||
f"/api/chats/{chat_id}/send",
|
||||
json={"text": "ping", "idempotency_key": "k2"},
|
||||
)
|
||||
assert r1.status_code == 200 and r2.status_code == 200
|
||||
assert r1.json()["message"]["message_id"] != r2.json()["message"]["message_id"]
|
||||
|
||||
Reference in New Issue
Block a user