Files
pablan/backend/tests/test_auth.py
T
ProfessorNovaandClaude Opus 5 784b76baf7 Pablan, as it stands
Self-hosted knowledge management for SMEs: a split-screen Markdown editor
whose sections an LLM refines while you write, and RAG question answering
over the documents that result. FastAPI + Postgres/pgvector on the back,
SvelteKit on the front, everything OpenAI-compatible and self-hostable.

Squashed into a single commit; the development history stays local.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CA43ZJda8Rbp2hKXNy8f6b
2026-09-04 09:21:37 +02:00

126 lines
3.9 KiB
Python

import uuid
from datetime import UTC, datetime, timedelta
from httpx import AsyncClient
from sqlalchemy import func, select
from sqlalchemy.ext.asyncio import AsyncSession
from app.auth.passwords import hash_password, verify_password
from app.auth.sessions import COOKIE_NAME
from app.models import AuthSession, User
def test_password_hash_roundtrip() -> None:
hashed = hash_password("secret123")
assert hashed != "secret123"
assert verify_password(hashed, "secret123")
assert not verify_password(hashed, "wrong")
assert not verify_password("not-a-hash", "secret123")
async def _session_count(db: AsyncSession) -> int:
return (await db.execute(select(func.count(AuthSession.id)))).scalar_one()
async def test_login_success_sets_cookie_and_session(
client: AsyncClient, db: AsyncSession, seeded_user: User
) -> None:
response = await client.post(
"/api/auth/login",
json={"email": "pablo@test.dev", "password": "secret123"},
)
assert response.status_code == 200
body = response.json()
assert body["email"] == "pablo@test.dev"
assert body["role"] == "member"
assert COOKIE_NAME in response.cookies
assert await _session_count(db) == 1
async def test_login_normalizes_email(client: AsyncClient, seeded_user: User) -> None:
response = await client.post(
"/api/auth/login",
json={"email": " PABLO@test.dev ", "password": "secret123"},
)
assert response.status_code == 200
async def test_login_wrong_password(
client: AsyncClient, db: AsyncSession, seeded_user: User
) -> None:
response = await client.post(
"/api/auth/login",
json={"email": "pablo@test.dev", "password": "wrong"},
)
assert response.status_code == 401
assert response.json() == {
"detail": "Invalid email or password.",
"code": "invalid_credentials",
}
assert await _session_count(db) == 0
async def test_login_unknown_email_same_error(client: AsyncClient) -> None:
response = await client.post(
"/api/auth/login",
json={"email": "ghost@test.dev", "password": "secret123"},
)
assert response.status_code == 401
assert response.json()["code"] == "invalid_credentials"
async def test_me_without_cookie(client: AsyncClient) -> None:
response = await client.get("/api/auth/me")
assert response.status_code == 401
assert response.json()["code"] == "not_authenticated"
async def test_me_with_garbage_cookie(client: AsyncClient) -> None:
client.cookies.set(COOKIE_NAME, "not-a-uuid")
response = await client.get("/api/auth/me")
assert response.status_code == 401
async def test_me_after_login(client: AsyncClient, seeded_user: User) -> None:
await client.post(
"/api/auth/login",
json={"email": "pablo@test.dev", "password": "secret123"},
)
response = await client.get("/api/auth/me")
assert response.status_code == 200
assert response.json()["id"] == str(seeded_user.id)
async def test_logout_deletes_session(
client: AsyncClient, db: AsyncSession, seeded_user: User
) -> None:
await client.post(
"/api/auth/login",
json={"email": "pablo@test.dev", "password": "secret123"},
)
assert await _session_count(db) == 1
response = await client.post("/api/auth/logout")
assert response.status_code == 204
assert await _session_count(db) == 0
response = await client.get("/api/auth/me")
assert response.status_code == 401
async def test_expired_session_rejected(
client: AsyncClient, db: AsyncSession, seeded_user: User
) -> None:
session = AuthSession(
id=uuid.uuid4(),
user_id=seeded_user.id,
expires_at=datetime.now(UTC) - timedelta(minutes=1),
)
db.add(session)
await db.commit()
client.cookies.set(COOKIE_NAME, str(session.id))
response = await client.get("/api/auth/me")
assert response.status_code == 401
assert response.json()["code"] == "not_authenticated"