import json from pathlib import Path from fastapi.testclient import TestClient import app.main as main import app.narrate as narrate from app.ollama_client import ModelError client = TestClient(main.app) VALID = json.loads((Path(__file__).parent / "fixtures" / "canon_log_valid.json").read_text()) def test_valid_log_returns_prose(monkeypatch): monkeypatch.setattr(narrate.ollama_client, "chat", lambda *a, **k: "You stand on the wharf.") monkeypatch.setattr(narrate.call_log, "record", lambda **kw: None) # keep test output pristine r = client.post("/dm/narrate", json={"canon_log": VALID}) assert r.status_code == 200 assert r.json() == {"prose": "You stand on the wharf."} def test_model_error_maps_to_502(monkeypatch): def boom(*a, **k): raise ModelError("upstream down") monkeypatch.setattr(narrate.ollama_client, "chat", boom) monkeypatch.setattr(narrate.call_log, "record", lambda **kw: None) r = client.post("/dm/narrate", json={"canon_log": VALID}) assert r.status_code == 502 assert "model_error" in r.json()["detail"] def test_invalid_log_still_422(monkeypatch): monkeypatch.setattr(narrate.ollama_client, "chat", lambda *a, **k: "x") bad = json.loads(json.dumps(VALID)) bad["player"]["luck"] = 5 # §7 leak — schema rejects r = client.post("/dm/narrate", json={"canon_log": bad}) assert r.status_code == 422 assert "canon_log_errors" in r.json()["detail"]