80 lines
3.3 KiB
Python
80 lines
3.3 KiB
Python
from __future__ import annotations
|
|
|
|
import asyncio
|
|
|
|
from app.rate_limit import InMemoryRateLimiter # type: ignore
|
|
import app.db as db_mod # type: ignore
|
|
|
|
|
|
def _create_chat(client, agent_id: str, node_id: str, ref: str):
|
|
return client.post(
|
|
"/api/chats",
|
|
json={
|
|
"agent_id": agent_id,
|
|
"node_id": node_id,
|
|
"source": "web",
|
|
"external_chat_ref": ref,
|
|
},
|
|
)
|
|
|
|
|
|
def _audit_events(event: str, chat_id: str | None = None):
|
|
return asyncio.run(db_mod.list_audit_events(event=event, chat_id=chat_id, limit=200))
|
|
|
|
|
|
def test_audit_trail_records_create_and_send(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)
|
|
monkeypatch.setattr(sofiia_module, "_rate_limiter", InMemoryRateLimiter())
|
|
monkeypatch.setattr(sofiia_module, "_RL_CHAT_RPS", 100.0)
|
|
monkeypatch.setattr(sofiia_module, "_RL_CHAT_BURST", 100)
|
|
monkeypatch.setattr(sofiia_module, "_RL_OP_RPS", 100.0)
|
|
monkeypatch.setattr(sofiia_module, "_RL_OP_BURST", 100)
|
|
|
|
r_create = _create_chat(sofiia_client, "sofiia", "NODA2", "audit-create-send")
|
|
assert r_create.status_code == 200, r_create.text
|
|
chat_id = r_create.json()["chat"]["chat_id"]
|
|
|
|
r_send = sofiia_client.post(
|
|
f"/api/chats/{chat_id}/send",
|
|
json={"text": "ping", "user_id": "operator-1"},
|
|
)
|
|
assert r_send.status_code == 200, r_send.text
|
|
|
|
ev_create = _audit_events("chat.create", chat_id=chat_id)
|
|
ev_req = _audit_events("chat.send.requested", chat_id=chat_id)
|
|
ev_res = _audit_events("chat.send.result", chat_id=chat_id)
|
|
|
|
assert ev_create, "Expected chat.create audit event"
|
|
assert ev_req, "Expected chat.send.requested audit event"
|
|
assert ev_res, "Expected chat.send.result audit event"
|
|
assert ev_res[0]["status"] == "ok"
|
|
assert "message_id" in (ev_res[0].get("data_json") or {})
|
|
|
|
|
|
def test_audit_trail_records_rate_limited_send(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)
|
|
monkeypatch.setattr(sofiia_module, "_rate_limiter", InMemoryRateLimiter())
|
|
monkeypatch.setattr(sofiia_module, "_RL_CHAT_RPS", 0.001)
|
|
monkeypatch.setattr(sofiia_module, "_RL_CHAT_BURST", 1)
|
|
monkeypatch.setattr(sofiia_module, "_RL_OP_RPS", 100.0)
|
|
monkeypatch.setattr(sofiia_module, "_RL_OP_BURST", 100)
|
|
|
|
r_create = _create_chat(sofiia_client, "sofiia", "NODA2", "audit-rl")
|
|
assert r_create.status_code == 200, r_create.text
|
|
chat_id = r_create.json()["chat"]["chat_id"]
|
|
|
|
r1 = sofiia_client.post(f"/api/chats/{chat_id}/send", json={"text": "one", "user_id": "operator-rl"})
|
|
r2 = sofiia_client.post(f"/api/chats/{chat_id}/send", json={"text": "two", "user_id": "operator-rl"})
|
|
assert r1.status_code == 200, r1.text
|
|
assert r2.status_code == 429, r2.text
|
|
|
|
ev_rl = _audit_events("chat.send.rate_limited", chat_id=chat_id)
|
|
assert ev_rl, "Expected chat.send.rate_limited audit event"
|
|
assert ev_rl[0]["error_code"] == "rate_limited"
|