Files
meeting-room/tests/test_server.py
vitya 1dffaae822 feat: Phase 2 — web server, REST API, WebSocket/SSE, UI [v0.2.0]
AsyncEventBridge bridges sync EventEmitter to asyncio consumers.
FastAPI app with session management, discussion control, roles/providers.
WebSocket for real-time events + inject, SSE for read-only streaming.
Minimal dark-theme HTML/JS UI. `meeting-room serve` CLI subcommand.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-04 08:50:04 +03:00

163 lines
5.2 KiB
Python

"""Tests for meeting_room.server — FastAPI app, REST API, WebSocket/SSE."""
from __future__ import annotations
import asyncio
import pytest
from fastapi.testclient import TestClient
from meeting_room.events import AsyncEventBridge, EventEmitter
from meeting_room.server import Session, SessionStore, app, store
@pytest.fixture(autouse=True)
def _reset_store():
"""Clear the global session store before each test."""
store._sessions.clear()
yield
@pytest.fixture
def client():
"""FastAPI test client."""
return TestClient(app)
# ---------------------------------------------------------------------------
# SessionStore
# ---------------------------------------------------------------------------
class TestSessionStore:
def test_create_session(self) -> None:
store = SessionStore()
session = store.create({"providers": {}, "roles": {}, "defaults": {}}, _minimal_discussion_config())
assert session.id
assert session.status == "created"
def test_get_session(self) -> None:
store = SessionStore()
session = store.create({"providers": {}, "roles": {}, "defaults": {}}, _minimal_discussion_config())
found = store.get(session.id)
assert found is session
def test_get_nonexistent_session(self) -> None:
store = SessionStore()
assert store.get("nonexistent") is None
def test_list_sessions(self) -> None:
store = SessionStore()
store.create({"providers": {}, "roles": {}, "defaults": {}}, _minimal_discussion_config())
store.create({"providers": {}, "roles": {}, "defaults": {}}, _minimal_discussion_config())
assert len(store.list_sessions()) == 2
# ---------------------------------------------------------------------------
# REST API endpoints
# ---------------------------------------------------------------------------
class TestCreateSession:
def test_create_session_returns_id_and_status(self, client) -> None:
response = client.post("/api/sessions")
assert response.status_code == 200
data = response.json()
assert "id" in data
assert data["status"] == "created"
class TestListSessions:
def test_list_empty(self, client) -> None:
response = client.get("/api/sessions")
assert response.status_code == 200
assert response.json() == []
def test_list_after_create(self, client) -> None:
client.post("/api/sessions")
client.post("/api/sessions")
response = client.get("/api/sessions")
assert response.status_code == 200
assert len(response.json()) == 2
class TestGetSession:
def test_get_existing_session(self, client) -> None:
create_resp = client.post("/api/sessions")
session_id = create_resp.json()["id"]
response = client.get(f"/api/sessions/{session_id}")
assert response.status_code == 200
assert response.json()["id"] == session_id
def test_get_nonexistent_session(self, client) -> None:
response = client.get("/api/sessions/nonexistent")
assert response.status_code == 404
class TestRolesAndProviders:
def test_list_roles(self, client) -> None:
response = client.get("/api/roles")
assert response.status_code == 200
data = response.json()
assert "moderator" in data or isinstance(data, dict)
def test_list_providers(self, client) -> None:
response = client.get("/api/providers")
assert response.status_code == 200
data = response.json()
assert isinstance(data, dict)
# ---------------------------------------------------------------------------
# Session model
# ---------------------------------------------------------------------------
class TestSession:
def test_build_engine(self) -> None:
config = _minimal_config()
session = Session("test-id", config, _minimal_discussion_config())
engine = session.build_engine()
assert engine is not None
# ---------------------------------------------------------------------------
# Helper
# ---------------------------------------------------------------------------
def _minimal_config() -> dict:
return {
"providers": {
"test_provider": {
"base_url": "https://api.example.com/v1",
"api_key": "test-key",
}
},
"roles": {
"moderator": {
"name": "Moderator",
"provider": "test_provider",
"model": "gpt-4o-mini",
"temperature": 0.7,
"tools": "none",
"system_prompt": "You are a moderator.",
}
},
"defaults": {
"max_rounds": 3,
"language": "en",
"framework": "custom",
"workdir": ".",
},
}
def _minimal_discussion_config():
from meeting_room.models import DefaultsConfig, DiscussionConfig
return DiscussionConfig(
providers={"test_provider": {"base_url": "https://api.example.com/v1", "api_key": "test-key"}},
roles={"moderator": {"name": "Moderator", "provider": "test_provider", "model": "gpt-4o-mini"}},
defaults=DefaultsConfig(max_rounds=3),
)