Files
cyclone/backend/tests/test_auth_routes.py
T

112 lines
3.3 KiB
Python

"""API tests for /api/auth/login, /api/auth/logout, /api/auth/me."""
from __future__ import annotations
import pytest
from fastapi.testclient import TestClient
from sqlalchemy import delete
from cyclone.api import app
from cyclone.auth import users
from cyclone.db import Session as DbSession
from cyclone.db import SessionLocal, User
@pytest.fixture(autouse=True)
def _clear():
with SessionLocal()() as db:
db.execute(delete(DbSession))
db.execute(delete(User))
db.commit()
yield
with SessionLocal()() as db:
db.execute(delete(DbSession))
db.execute(delete(User))
db.commit()
@pytest.fixture
def client():
return TestClient(app)
@pytest.fixture
def seeded_admin(client):
with SessionLocal()() as db:
users.create(db, username="admin", password="adminpassword1", role="admin")
return client
def test_login_success_returns_user_and_cookie(client):
with SessionLocal()() as db:
users.create(db, username="alice", password="hunter2hunter2", role="user")
resp = client.post(
"/api/auth/login",
json={"username": "alice", "password": "hunter2hunter2"},
)
assert resp.status_code == 200
body = resp.json()
assert body["username"] == "alice"
assert body["role"] == "user"
assert "password_hash" not in body
assert "cyclone_session" in resp.cookies
def test_login_bad_password_returns_401(client):
with SessionLocal()() as db:
users.create(db, username="bob", password="hunter2hunter2", role="user")
resp = client.post(
"/api/auth/login",
json={"username": "bob", "password": "WRONG"},
)
assert resp.status_code == 401
assert resp.json()["error"] == "invalid_credentials"
def test_login_unknown_user_returns_401(client):
resp = client.post(
"/api/auth/login",
json={"username": "ghost", "password": "whatever"},
)
assert resp.status_code == 401
assert resp.json()["error"] == "invalid_credentials"
def test_login_disabled_user_returns_403(client):
with SessionLocal()() as db:
u = users.create(db, username="carol", password="hunter2hunter2", role="user")
users.disable(db, u.id)
resp = client.post(
"/api/auth/login",
json={"username": "carol", "password": "hunter2hunter2"},
)
assert resp.status_code == 403
assert resp.json()["error"] == "account_disabled"
def test_logout_clears_session_and_cookie(seeded_admin):
login = seeded_admin.post(
"/api/auth/login",
json={"username": "admin", "password": "adminpassword1"},
)
cookie = login.cookies.get("cyclone_session")
assert cookie
resp = seeded_admin.post("/api/auth/logout", cookies={"cyclone_session": cookie})
assert resp.status_code == 204
def test_me_returns_current_user(seeded_admin):
login = seeded_admin.post(
"/api/auth/login",
json={"username": "admin", "password": "adminpassword1"},
)
cookie = login.cookies.get("cyclone_session")
resp = seeded_admin.get("/api/auth/me", cookies={"cyclone_session": cookie})
assert resp.status_code == 200
assert resp.json()["username"] == "admin"
def test_me_without_cookie_returns_401(seeded_admin):
resp = seeded_admin.get("/api/auth/me")
assert resp.status_code == 401