"""End-to-end HTTP smoke test against a running server (mock LLM mode). Usage: python tests/smoke_http.py [base_url] """ import sys import requests BASE = sys.argv[1] if len(sys.argv) > 1 else "http://localhost:7860" def post(path, body=None): r = requests.post(f"{BASE}{path}", json=body or {}, timeout=30) assert r.status_code == 200, f"{path} -> {r.status_code}: {r.text[:200]}" return r.json() def main(): # shell pages for path in ("/healthz", "/game", "/static/js/main.js", "/static/css/game.css", "/static/js/chibi.js"): r = requests.get(f"{BASE}{path}", timeout=10) assert r.status_code == 200, f"GET {path} -> {r.status_code}" print("OK shell + static assets") data = post("/api/new_game") sid = data["session_id"] state = data["state"] assert state["revenue"] == 150_000 and state["pocket_money"] == 3000 assert "morale" not in state, "snapshot leaked morale!" print(f"OK new_game (session {sid[:8]})") presentations, specials, gifts_done = 0, 0, False while True: data = post("/api/next_event", {"session_id": sid}) event, state = data["event"], data["state"] if event["kind"] == "review": break n = event["crisis_number"] if event["kind"] == "presentation": presentations += 1 rd = post("/api/presentation_round", {"session_id": sid, "response_type": "", "text": ""})["round_data"] rounds = 1 while rd["kind"] == "round": body = {"session_id": sid, "response_type": "custom", "text": "We owned the situation, called the client, " "and turned it into a pilot program."} rd = post("/api/presentation_round", body)["round_data"] if rd["kind"] == "round": rounds += 1 print(f"OK event {n}: presentation, {rounds} rounds, " f"score {rd['score']}, swing {rd['revenue_delta']:+,}") if rd["final"]: break else: if event.get("special"): specials += 1 out = post("/api/respond", { "session_id": sid, "response_type": "custom", "text": "Here is what we do: full honesty with the client, " "and Brad presents the apology as a roadmap.", }) o, state = out["outcome"], out["state"] assert o["animation"], "outcome missing animation" print(f"OK event {n}: {event.get('special') or 'crisis'} " f"[{event['arrival']}] -> {o['revenue_delta']:+,}") # idle activities in the first roam gap if n == 1 and state["phase"] == "free_roam": r = post("/api/idle", {"session_id": sid}) print(f"OK idle roll: {r['idle']['kind']}") if r["idle"]["kind"] == "email_waiting": e = post("/api/read_email", {"session_id": sid})["email"] print(f"OK email read: {e['subject'][:50]}") c = post("/api/chat", {"session_id": sid, "npc_id": "stacey"}) assert c["chat"]["npc_line"] c = post("/api/chat", {"session_id": sid, "npc_id": "stacey", "text": "Hang in there, you do good work."}) assert "relationship_delta" in c["chat"] print("OK chat open+reply with stacey") c2 = post("/api/chat", {"session_id": sid, "npc_id": "derek"}) assert c2["chat"]["npc_line"] r3 = requests.post(f"{BASE}/api/chat", json={"session_id": sid, "npc_id": "janet"}, timeout=30) assert r3.status_code == 409, "third chat must hit the gap cap" print("OK chat caps enforced (3rd chat -> 409)") # one gift along the way if not gifts_done and state["phase"] == "free_roam" \ and state["gift_available"]: g = post("/api/gift", {"session_id": sid, "npc_id": "stacey", "tier": "small"}) assert g["result"]["relationship_delta"] > 0 print(f"OK gift -> stacey +{g['result']['relationship_delta']}") gifts_done = True review = post("/api/review", {"session_id": sid})["review"] print(f"OK review: tier={review['tier']}, revenue " f"${review['final_revenue']:,}, verdict: {review['verdict'][:70]}...") assert presentations >= 1 and review["crises_survived"] == 15 print(f"\nPASS — full quarter: {presentations} presentations, " f"{specials} specials, paper trail {len(review['highlights'])} highlights") if __name__ == "__main__": main()