#!/usr/bin/env python3 """ Integration Test Suite β€” Phase 6/7 Bridge Tests Event Graph API ↔ Dashboard wire-up """ import requests import json import sys from datetime import datetime, timedelta # API endpoints API_BASE = "http://localhost:8002/api/v1" DASHBOARD_URL = "http://localhost:3001" class TestRunner: def __init__(self): self.passed = 0 self.failed = 0 self.tests = [] def test(self, name, fn): """Run a single test.""" try: fn() self.passed += 1 self.tests.append(("PASS", name, None)) print(f" βœ… {name}") except AssertionError as e: self.failed += 1 self.tests.append(("FAIL", name, str(e))) print(f" ❌ {name}: {e}") except Exception as e: self.failed += 1 self.tests.append(("ERR", name, str(e))) print(f" πŸ’₯ {name}: {e}") def summary(self): total = self.passed + self.failed print(f"\n{'='*50}") print(f"Results: {self.passed}/{total} passed") if self.failed == 0: print("πŸŽ‰ All tests passed!") else: print(f"⚠️ {self.failed} test(s) failed") for status, name, err in self.tests: if status != "PASS": print(f" {status}: {name} β€” {err}") return self.failed == 0 runner = TestRunner() # ── TEST 1: Server Health ────────────────────────────────────── def test_health(): resp = requests.get(f"{API_BASE}/../health") assert resp.status_code == 200 data = resp.json() assert data["status"] == "healthy" assert data["service"] == "event-graph-api" runner.test("Server health endpoint", test_health) # ── TEST 2: Members API ──────────────────────────────────────── def test_members(): resp = requests.get(f"{API_BASE}/members") assert resp.status_code == 200 members = resp.json() assert len(members) >= 4, f"Expected 4+ members, got {len(members)}" names = [m["name"] for m in members] assert "Matt" in names assert "Sullivan" in names assert "Harper" in names assert "Aundrea" in names runner.test("Members API returns family", test_members) # ── TEST 3: Events CRUD ────────────────────────────────────── def test_events_crud(): # Create resp = requests.get(f"{API_BASE}/members") members = {m["name"]: m["id"] for m in resp.json()} new_event = { "title": "Integration Test Event", "start_date": "2026-05-01T10:00:00", "event_type": "calendar", "family_member": members["Matt"], "location": "Test Location", "status": "confirmed", "confidence": 0.95 } resp = requests.post(f"{API_BASE}/events", json=new_event) assert resp.status_code == 200 created = resp.json() event_id = created["id"] assert created["title"] == "Integration Test Event" # Read resp = requests.get(f"{API_BASE}/events/{event_id}") assert resp.status_code == 200 fetched = resp.json() assert fetched["title"] == "Integration Test Event" # Update resp = requests.put(f"{API_BASE}/events/{event_id}", json={"title": "Updated Test Event"}) assert resp.status_code == 200 updated = resp.json() assert updated["title"] == "Updated Test Event" # Delete resp = requests.delete(f"{API_BASE}/events/{event_id}") assert resp.status_code == 200 # Verify deleted resp = requests.get(f"{API_BASE}/events/{event_id}") assert resp.status_code == 404 runner.test("Events full CRUD", test_events_crud) # ── TEST 4: Briefing Endpoint ───────────────────────────────── def test_briefing(): resp = requests.get(f"{API_BASE}/briefing", params={"date": "2026-04-28", "scope": "day"}) assert resp.status_code == 200 briefing = resp.json() assert "sections" in briefing assert "stats" in briefing assert "urgent" in briefing["sections"] assert "today" in briefing["sections"] assert "coordination" in briefing["sections"] assert "maintenance" in briefing["sections"] assert "upcoming" in briefing["sections"] # Should have events we seeded total_events = sum(len(s.get("events", [])) for s in briefing["sections"].values()) assert total_events > 0, "Briefing should contain events" runner.test("Hierarchical briefing generation", test_briefing) # ── TEST 5: Dashboard Static Files ───────────────────────────── def test_dashboard_serves(): resp = requests.get(f"{DASHBOARD_URL}/index.html") assert resp.status_code == 200 assert "HoffDesk" in resp.text or "Family" in resp.text or "dashboard" in resp.text.lower() runner.test("Dashboard serves static files", test_dashboard_serves) # ── TEST 6: Dashboard API Connectivity (CORS) ──────────────── def test_dashboard_api_connectivity(): # Dashboard running on :3001 should be able to reach API on :8002 # This simulates what the browser would do resp = requests.get(f"{API_BASE}/health", headers={"Origin": DASHBOARD_URL}) assert resp.status_code == 200 # FastAPI with CORS should return Access-Control-Allow-Origin # (We'll check this manually) runner.test("Dashboardβ†’API connectivity", test_dashboard_api_connectivity) # ── TEST 7: Event Filtering ────────────────────────────────── def test_event_filtering(): resp = requests.get(f"{API_BASE}/events") all_events = resp.json() # Filter by member resp = requests.get(f"{API_BASE}/members") members = {m["name"]: m["id"] for m in resp.json()} resp = requests.get(f"{API_BASE}/events", params={"member": members.get("Sullivan")}) sullivan_events = resp.json() # Should be subset of all events assert len(sullivan_events) <= len(all_events) # All should be Sullivan's for evt in sullivan_events: assert evt["family_member"] == members["Sullivan"], \ f"Expected Sullivan's event, got {evt.get('family_member')}" runner.test("Event filtering by member", test_event_filtering) # ── TEST 8: Conflict Detection ─────────────────────────────── def test_conflict_api(): resp = requests.get(f"{API_BASE}/conflicts") assert resp.status_code == 200 conflicts = resp.json() # May be empty, but endpoint should work assert isinstance(conflicts, list) runner.test("Conflict API endpoint", test_conflict_api) # ── TEST 9: WebSocket Endpoint (connectivity) ──────────────── def test_websocket_endpoint(): # Just verify the endpoint exists (we can't easily test WebSocket in pure requests) resp = requests.get(f"{API_BASE}/../health") assert resp.status_code == 200 # WebSocket would be at ws://localhost:8002/ws # For now, verify the server is up that would handle it runner.test("WebSocket endpoint exists (server up)", test_websocket_endpoint) # ── TEST 10: Data Persistence ───────────────────────────────── def test_data_persistence(): # Events we created earlier should still exist resp = requests.get(f"{API_BASE}/events") events = resp.json() assert len(events) >= 6, f"Expected 6+ events (seeded data), got {len(events)}" titles = [e["title"] for e in events] assert "Sullivan Soccer Practice" in titles assert "Family Dinner" in titles runner.test("Data persists across requests", test_data_persistence) # ── SUMMARY ────────────────────────────────────────────────── success = runner.summary() # Exit with appropriate code sys.exit(0 if success else 1)