πŸ“„ test_integration.py 8,331 bytes Apr 28, 2026 πŸ“‹ Raw

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