!/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)