""" Test Milestone 14: Meet extension backend endpoints. Tests the /api/meet/start and /api/meet/ingest endpoints directly (no Chrome needed). """ import asyncio import os import sys import json sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..')) async def test_manifest_valid(): """Test extension manifest.json is valid.""" import json manifest_path = os.path.join( os.path.dirname(__file__), '..', 'meet_extension', 'manifest.json' ) assert os.path.exists(manifest_path), "manifest.json not found at meet_extension/manifest.json" with open(manifest_path) as f: manifest = json.load(f) assert manifest.get("manifest_version") == 3, "Must be Manifest V3" assert "meet.google.com" in str(manifest.get("host_permissions", [])), \ "Missing meet.google.com host permission" assert manifest.get("background", {}).get("service_worker"), "Missing service_worker" assert manifest.get("action", {}).get("default_popup"), "Missing popup" print(" ✅ manifest.json is valid MV3") async def test_extension_files_exist(): """Test all required extension files exist.""" base = os.path.join(os.path.dirname(__file__), '..', 'meet_extension') required = ["manifest.json", "content.js", "popup.html", "popup.js", "background.js"] for filename in required: path = os.path.join(base, filename) assert os.path.exists(path), f"Missing extension file: {filename}" print(f" ✅ {filename} exists") async def test_meet_start_endpoint(): """Test /api/meet/start returns 200 with correct secret.""" import httpx from backend.config import MEET_INGEST_SECRET async with httpx.AsyncClient(base_url="http://localhost:8000") as client: # Test with correct secret resp = await client.post( "/api/meet/start", json={ "meeting_id": "bje-xogw-kcv", "group_id": "bje_xogw_kcv", "started_at": "2026-03-21T10:00:00Z", "speaker": "Raj Bhattacharyya", }, headers={"X-ThirdEye-Secret": MEET_INGEST_SECRET}, ) assert resp.status_code == 200, f"Expected 200, got {resp.status_code}: {resp.text}" data = resp.json() assert data.get("ok") is True print(f" ✅ /api/meet/start returned ok=True for meeting bje-xogw-kcv") # Test with wrong secret → should get 403 resp_bad = await client.post( "/api/meet/start", json={"meeting_id": "fake", "group_id": "fake", "started_at": "2026-03-21T10:00:00Z"}, headers={"X-ThirdEye-Secret": "wrong_secret"}, ) assert resp_bad.status_code == 403, f"Expected 403 for bad secret, got {resp_bad.status_code}" print(" ✅ Bad secret correctly rejected with 403") async def test_meet_ingest_endpoint(): """Test /api/meet/ingest accepts a transcript chunk and queues processing.""" import httpx from backend.config import MEET_INGEST_SECRET async with httpx.AsyncClient(base_url="http://localhost:8000") as client: resp = await client.post( "/api/meet/ingest", json={ "meeting_id": "bje-xogw-kcv", "group_id": "bje_xogw_kcv", "chunk_index": 0, "text": "We decided to go with PostgreSQL for the primary database. " "Alex will set up the schema by Thursday. " "The migration scripts need to be reviewed before deployment.", "speaker": "Raj Bhattacharyya", "timestamp": "2026-03-21T10:01:00Z", "is_final": False, }, headers={"X-ThirdEye-Secret": MEET_INGEST_SECRET}, timeout=10.0, ) assert resp.status_code == 200, f"Expected 200, got {resp.status_code}: {resp.text}" data = resp.json() assert data.get("ok") is True assert data.get("queued") is True print(f" ✅ /api/meet/ingest chunk accepted and queued") # Wait briefly for background task to process await asyncio.sleep(5) # Verify the meeting appears in /api/meet/meetings async with httpx.AsyncClient(base_url="http://localhost:8000") as client: resp = await client.get("/api/meet/meetings") assert resp.status_code == 200 data = resp.json() meetings = data.get("meetings", []) ids = [m["meeting_id"] for m in meetings] assert "bje-xogw-kcv" in ids, f"Meeting bje-xogw-kcv not found in {ids}" print(f" ✅ Meeting bje-xogw-kcv visible in /api/meet/meetings") async def test_meet_skip_short_chunk(): """Test that very short chunks are gracefully skipped.""" import httpx from backend.config import MEET_INGEST_SECRET async with httpx.AsyncClient(base_url="http://localhost:8000") as client: resp = await client.post( "/api/meet/ingest", json={ "meeting_id": "bje-xogw-kcv", "group_id": "bje_xogw_kcv", "chunk_index": 99, "text": "Uh", # Too short "speaker": "Raj Bhattacharyya", "timestamp": "2026-03-21T10:02:00Z", "is_final": False, }, headers={"X-ThirdEye-Secret": MEET_INGEST_SECRET}, ) assert resp.status_code == 200 data = resp.json() assert data.get("skipped") is True, "Expected short chunk to be skipped" print(f" ✅ Short chunk correctly skipped") async def main(): print("Running Milestone 14 tests...\n") print("NOTE: The FastAPI server must be running: python run_api.py\n") await test_manifest_valid() await test_extension_files_exist() try: await test_meet_start_endpoint() await test_meet_ingest_endpoint() await test_meet_skip_short_chunk() print("\n🎉 MILESTONE 14 PASSED — Extension files valid, backend endpoints working") except Exception as e: print(f"\n💥 MILESTONE 14 FAILED: {e}") print(" Make sure: python run_api.py is running before running this test") raise asyncio.run(main())