Complete Flask → FastAPI migration with: - FastAPI app with session auth, Azure AD SSO, rate limiting - SQLite-backed session store (survives restarts) - Bulk AI metadata generation with SSE progress - Admin panel (user management, audit log, AI usage) - Subpath deployment support (ROOT_PATH config) - Docker + deploy.sh for production deployment - Test suite (auth, upload, templates, imports, admin, sessions) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
68 lines
2.5 KiB
Python
68 lines
2.5 KiB
Python
"""Tests for authentication endpoints."""
|
|
|
|
|
|
class TestLoginPage:
|
|
def test_login_page_renders(self, client):
|
|
"""GET /login returns login form."""
|
|
response = client.get("/login")
|
|
assert response.status_code == 200
|
|
assert "login" in response.text.lower()
|
|
|
|
def test_unauthenticated_redirect(self, client):
|
|
"""Unauthenticated access to / redirects to /login."""
|
|
response = client.get("/", follow_redirects=False)
|
|
assert response.status_code == 302
|
|
assert "/login" in response.headers.get("location", "")
|
|
|
|
|
|
class TestLogin:
|
|
def test_login_success(self, client):
|
|
"""POST /login with valid credentials redirects to /."""
|
|
response = client.post(
|
|
"/login",
|
|
data={"username": "tester", "password": "oliveradmin"},
|
|
follow_redirects=False,
|
|
)
|
|
assert response.status_code == 302
|
|
assert response.headers.get("location") == "/"
|
|
|
|
def test_login_wrong_password(self, client):
|
|
"""POST /login with wrong password shows error."""
|
|
response = client.post(
|
|
"/login",
|
|
data={"username": "tester", "password": "wrongpass"},
|
|
)
|
|
assert response.status_code == 200
|
|
# Should show error message on the login page
|
|
assert "error" in response.text.lower() or "invalid" in response.text.lower() or "incorrect" in response.text.lower()
|
|
|
|
def test_login_empty_fields(self, client):
|
|
"""POST /login with empty fields shows error."""
|
|
response = client.post(
|
|
"/login",
|
|
data={"username": "", "password": ""},
|
|
)
|
|
assert response.status_code == 200
|
|
|
|
|
|
class TestLogout:
|
|
def test_logout_redirects(self, auth_client):
|
|
"""GET /logout redirects to /login."""
|
|
response = auth_client.get("/logout", follow_redirects=False)
|
|
assert response.status_code == 302
|
|
assert "/login" in response.headers.get("location", "")
|
|
|
|
|
|
class TestProtectedRoutes:
|
|
def test_index_requires_auth(self, client):
|
|
"""/ requires authentication."""
|
|
# Clear any existing session
|
|
client.cookies.clear()
|
|
response = client.get("/", follow_redirects=False)
|
|
assert response.status_code == 302
|
|
|
|
def test_index_accessible_when_authenticated(self, auth_client):
|
|
"""/ is accessible after login."""
|
|
response = auth_client.get("/")
|
|
assert response.status_code == 200
|
|
assert "Oliver Metadata Tool" in response.text
|