theo-agent-dashboard

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

test_auth_routes.py (4144B)


      1 """T015 — Tests for auth routes."""
      2 import os
      3 import tempfile
      4 
      5 import pytest
      6 from httpx import ASGITransport, AsyncClient
      7 from app.main import app
      8 
      9 @pytest.fixture(autouse=True)
     10 def _isolate_auth_config(tmp_path):
     11     """Each test gets a clean config file."""
     12     config_path = str(tmp_path / "config.json")
     13     os.environ["THEO_CONFIG_PATH"] = config_path
     14     # Patch the module-level config path in routes/auth
     15     import app.routes.auth as auth_module
     16     old = auth_module._CONFIG_PATH
     17     auth_module._CONFIG_PATH = config_path
     18     yield
     19     auth_module._CONFIG_PATH = old
     20     os.environ.pop("THEO_CONFIG_PATH", None)
     21 
     22 
     23 @pytest.fixture
     24 async def client() -> AsyncClient:
     25     """Fresh async client for each test."""
     26     async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as c:
     27         yield c
     28 
     29 
     30 class TestAuthStatus:
     31     """GET /api/auth/status"""
     32 
     33     async def test_status_unconfigured(self, client: AsyncClient) -> None:
     34         """Returns configured: false when no auth config exists."""
     35         resp = await client.get("/api/auth/status")
     36         assert resp.status_code == 200
     37         body = resp.json()
     38         assert "configured" in body
     39         assert body["configured"] is False
     40         assert isinstance(body["configured"], bool)
     41 
     42 
     43 class TestAuthSetup:
     44     """POST /api/auth/setup"""
     45 
     46     async def test_setup_creates_password_and_returns_jwt(self, client: AsyncClient) -> None:
     47         """First-run setup creates credentials and returns a JWT."""
     48         resp = await client.post("/api/auth/setup", json={
     49             "password": "testpass123",
     50             "api_key": "sk-test-key",
     51         })
     52         assert resp.status_code == 200
     53         body = resp.json()
     54         assert "token" in body
     55         assert isinstance(body["token"], str)
     56         assert len(body["token"]) > 0
     57 
     58     async def test_setup_returns_400_if_already_configured(self, client: AsyncClient) -> None:
     59         """Cannot setup twice."""
     60         await client.post("/api/auth/setup", json={
     61             "password": "pass1",
     62             "api_key": "key1",
     63         })
     64         resp = await client.post("/api/auth/setup", json={
     65             "password": "pass2",
     66             "api_key": "key2",
     67         })
     68         assert resp.status_code == 400
     69         body = resp.json()
     70         assert "detail" in body
     71         assert "Already configured" in body["detail"]
     72 
     73 
     74 class TestAuthLogin:
     75     """POST /api/auth/login"""
     76 
     77     async def test_login_correct_password_returns_jwt(self, client: AsyncClient) -> None:
     78         """Valid login returns a JWT."""
     79         await client.post("/api/auth/setup", json={
     80             "password": "mypassword",
     81             "api_key": "sk-key",
     82         })
     83         resp = await client.post("/api/auth/login", json={"password": "mypassword"})
     84         assert resp.status_code == 200
     85         body = resp.json()
     86         assert "token" in body
     87         assert isinstance(body["token"], str)
     88         assert len(body["token"]) > 0
     89 
     90     async def test_login_wrong_password_returns_401(self, client: AsyncClient) -> None:
     91         """Invalid password returns 401."""
     92         await client.post("/api/auth/setup", json={
     93             "password": "correct",
     94             "api_key": "sk-key",
     95         })
     96         resp = await client.post("/api/auth/login", json={"password": "wrong"})
     97         assert resp.status_code == 401
     98         body = resp.json()
     99         assert "detail" in body
    100         assert "Invalid password" in body["detail"]
    101 
    102     async def test_login_not_configured_returns_401(self, client: AsyncClient) -> None:
    103         """Login before setup returns 401."""
    104         resp = await client.post("/api/auth/login", json={"password": "anything"})
    105         assert resp.status_code == 401
    106         body = resp.json()
    107         assert "detail" in body
    108         assert "Not configured" in body["detail"]
    109 
    110 
    111 class TestAuthLogout:
    112     """POST /api/auth/logout"""
    113 
    114     async def test_logout_clears_cookie(self, client: AsyncClient) -> None:
    115         """Logout clears the JWT cookie."""
    116         resp = await client.post("/api/auth/logout")
    117         assert resp.status_code == 200
    118         body = resp.json()
    119         assert body == {"ok": True}