""" War Room Constraints — Orsync Scenarist v7.0 PRD ========================================== WebRTC handshake latency must be strictly < 400ms. Tests the simulation service and measures handshake round-trip. """ from __future__ import annotations import time from uuid import uuid4 from unittest.mock import MagicMock, patch import pytest from fastapi.testclient import TestClient from backend.app.main import app from backend.app.services.webrtc_simulation import _get_persona_cluster_traits HANDSHAKE_BUDGET_MS = 400 def test_simulation_prompt_traits_use_dynamic_strategy_segments() -> None: cluster_one = _get_persona_cluster_traits("HCP-01-001") cluster_nine = _get_persona_cluster_traits("HCP-09-001") assert cluster_one["name"] == "Digital Oncology Adopters" assert cluster_nine["name"] == "Precision-Medicine Champions" assert "Commercial Adopter" not in cluster_one["name"] class TestWebRTCHandshakeLatency: """PRD §10: WebRTC handshake must complete within 400ms budget.""" @pytest.fixture(autouse=True) def _patch_redis(self): """Isolate tests from real Redis.""" import fakeredis from backend.app.db.chroma_client import _NoOpChromaClient fake = fakeredis.FakeRedis(decode_responses=True) with patch("backend.app.db.redis_client.get_redis_client", return_value=fake): with patch("backend.app.services.webrtc_simulation.get_redis_client", return_value=fake): with patch("backend.app.db.chroma_client.get_chroma_client", return_value=_NoOpChromaClient()): yield fake @pytest.fixture() def client(self): return TestClient(app) def test_mock_handshake_under_budget(self, client): start_resp = client.post( "/api/simulation/start", json={"persona_id": "persona_001", "campaign_id": "camp_001"}, ) assert start_resp.status_code == 200 session = start_resp.json() session_id = session["session_id"] assert session["target_handshake_ms"] == HANDSHAKE_BUDGET_MS t0 = time.perf_counter_ns() handshake_resp = client.post( "/api/simulation/handshake", json={ "session_id": session_id, "answer": {"type": "answer", "sdp": "v=0\r\n"}, }, ) elapsed_ms = (time.perf_counter_ns() - t0) / 1_000_000 assert handshake_resp.status_code == 200 assert elapsed_ms < HANDSHAKE_BUDGET_MS, ( f"Handshake took {elapsed_ms:.1f}ms — exceeds {HANDSHAKE_BUDGET_MS}ms budget" ) def test_ice_candidate_accepted(self, client): start_resp = client.post( "/api/simulation/start", json={"persona_id": "persona_002"}, ) session_id = start_resp.json()["session_id"] ice_resp = client.post( "/api/simulation/ice-candidate", json={ "session_id": session_id, "candidate": { "candidate": "candidate:0 1 UDP 2122252543 192.168.1.1 50000 typ host", "sdpMLineIndex": 0, }, }, ) assert ice_resp.status_code == 200 def test_simulation_turn_semantic_cache(self, client): prompt = f"What about drug efficacy? {uuid4().hex}" start_resp = client.post( "/api/simulation/start", json={"persona_id": "persona_003", "campaign_id": "camp_002"}, ) session_id = start_resp.json()["session_id"] turn1 = client.post( "/api/simulation/turn", json={"session_id": session_id, "input_text": prompt}, ) assert turn1.status_code == 200 assert turn1.json()["cache_hit"] is False turn2 = client.post( "/api/simulation/turn", json={"session_id": session_id, "input_text": prompt}, ) assert turn2.status_code == 200 assert turn2.json()["cache_hit"] is True assert turn2.json()["cache_similarity"] == 1.0 def test_invalid_session_returns_error(self, client): resp = client.post( "/api/simulation/handshake", json={"session_id": "nonexistent", "answer": {}}, ) assert resp.status_code in (400, 404, 422, 500)