from datetime import datetime, timezone from fastapi.testclient import TestClient from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker from sqlalchemy.pool import StaticPool from app.config import Settings, get_settings from app.db import Base, get_db from app.main import app from app.models import CrawlRun, Employee from app.security import SESSION_COOKIE, sign_session def test_health_returns_versions(): client = TestClient(app) response = client.get("/api/health") assert response.status_code == 200 assert response.json()["backend_version"] == "0.2.3" def test_mcp_requires_token_and_lists_tools(): engine = create_engine( "sqlite:///:memory:", connect_args={"check_same_thread": False}, poolclass=StaticPool, ) Base.metadata.create_all(engine) Session = sessionmaker(bind=engine) def override_db(): session = Session() try: yield session finally: session.close() app.dependency_overrides[get_db] = override_db app.dependency_overrides[get_settings] = lambda: Settings(mcp_token="secret", session_secret="session-secret") client = TestClient(app) unauthorized = client.post("/mcp", json={"jsonrpc": "2.0", "id": 1, "method": "tools/list", "params": {}}) authorized = client.post( "/mcp", headers={"Authorization": "Bearer secret"}, json={"jsonrpc": "2.0", "id": 1, "method": "tools/list", "params": {}}, ) assert unauthorized.status_code == 401 assert authorized.status_code == 200 assert authorized.json()["result"]["tools"][0]["name"] == "search_employees" app.dependency_overrides.clear() def test_mcp_search_employees_returns_matching_employee(): engine = create_engine( "sqlite:///:memory:", connect_args={"check_same_thread": False}, poolclass=StaticPool, ) Base.metadata.create_all(engine) Session = sessionmaker(bind=engine) session = Session() session.add( Employee( profile_key="staff:avsergeev", profile_type="staff", profile_id="avsergeev", canonical_url="https://www.hse.ru/staff/avsergeev", full_name="Сергеев Алексей Викторович", status="active", first_seen_at=datetime.now(timezone.utc), last_seen_at=datetime.now(timezone.utc), current_data={"sections": []}, ) ) session.commit() session.close() def override_db(): db = Session() try: yield db finally: db.close() app.dependency_overrides[get_db] = override_db app.dependency_overrides[get_settings] = lambda: Settings(mcp_token="secret", session_secret="session-secret") client = TestClient(app) response = client.post( "/mcp", headers={"Authorization": "Bearer secret"}, json={ "jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": {"name": "search_employees", "arguments": {"query": "Сергеев"}}, }, ) assert response.status_code == 200 assert "Сергеев Алексей Викторович" in response.json()["result"]["content"][0]["text"] app.dependency_overrides.clear() def test_api_employees_and_stats_require_admin_session(): engine = create_engine( "sqlite:///:memory:", connect_args={"check_same_thread": False}, poolclass=StaticPool, ) Base.metadata.create_all(engine) Session = sessionmaker(bind=engine) db = Session() db.add( Employee( profile_key="staff:alpha", profile_type="staff", profile_id="alpha", canonical_url="https://www.hse.ru/staff/alpha", full_name="Alpha Person", status="active", first_seen_at=datetime.now(timezone.utc), last_seen_at=datetime.now(timezone.utc), current_data={"contacts": {"emails": ["alpha@hse.ru"]}, "sections": []}, ) ) db.add(CrawlRun(source_url="https://miem.hse.ru/persons", status="completed", new_count=1)) db.commit() db.close() settings = Settings(admin_username="admin", admin_password="password", session_secret="session-secret") def override_db(): session = Session() try: yield session finally: session.close() app.dependency_overrides[get_db] = override_db app.dependency_overrides[get_settings] = lambda: settings client = TestClient(app) client.cookies.set(SESSION_COOKIE, sign_session("admin", settings)) employees = client.get("/api/employees", params={"q": "Alpha", "has_email": True}) stats = client.get("/api/stats") assert employees.status_code == 200 assert employees.json()["total"] == 1 assert stats.status_code == 200 assert stats.json()["new_in_last_run"] == 1 app.dependency_overrides.clear()