Split integration tests into logical admin/ and vendor/ subdirectories for better organization. Updated fixture imports and test structure. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
170 lines
5.9 KiB
Python
170 lines
5.9 KiB
Python
# tests/integration/api/v1/admin/test_auth.py
|
|
"""Integration tests for admin authentication endpoints.
|
|
|
|
Tests the /api/v1/admin/auth/* endpoints.
|
|
"""
|
|
from datetime import UTC, datetime, timedelta
|
|
|
|
import pytest
|
|
from jose import jwt
|
|
|
|
|
|
@pytest.mark.integration
|
|
@pytest.mark.api
|
|
@pytest.mark.auth
|
|
class TestAdminAuthAPI:
|
|
"""Test admin authentication endpoints at /api/v1/admin/auth/*."""
|
|
|
|
def test_login_success(self, client, test_admin):
|
|
"""Test successful admin login."""
|
|
response = client.post(
|
|
"/api/v1/admin/auth/login",
|
|
json={"email_or_username": test_admin.username, "password": "adminpass123"},
|
|
)
|
|
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert "access_token" in data
|
|
assert data["token_type"] == "bearer"
|
|
assert "expires_in" in data
|
|
assert data["user"]["username"] == test_admin.username
|
|
assert data["user"]["email"] == test_admin.email
|
|
|
|
def test_login_with_email(self, client, test_admin):
|
|
"""Test admin login with email instead of username."""
|
|
response = client.post(
|
|
"/api/v1/admin/auth/login",
|
|
json={"email_or_username": test_admin.email, "password": "adminpass123"},
|
|
)
|
|
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert "access_token" in data
|
|
assert data["user"]["email"] == test_admin.email
|
|
|
|
def test_login_wrong_password(self, client, test_admin):
|
|
"""Test login with wrong password."""
|
|
response = client.post(
|
|
"/api/v1/admin/auth/login",
|
|
json={"email_or_username": test_admin.username, "password": "wrongpassword"},
|
|
)
|
|
|
|
assert response.status_code == 401
|
|
data = response.json()
|
|
assert data["error_code"] == "INVALID_CREDENTIALS"
|
|
|
|
def test_login_nonexistent_user(self, client):
|
|
"""Test login with nonexistent user."""
|
|
response = client.post(
|
|
"/api/v1/admin/auth/login",
|
|
json={"email_or_username": "nonexistent", "password": "password123"},
|
|
)
|
|
|
|
assert response.status_code == 401
|
|
data = response.json()
|
|
assert data["error_code"] == "INVALID_CREDENTIALS"
|
|
|
|
def test_login_inactive_user(self, client, db, test_admin):
|
|
"""Test login with inactive admin account."""
|
|
original_status = test_admin.is_active
|
|
test_admin.is_active = False
|
|
db.commit()
|
|
|
|
try:
|
|
response = client.post(
|
|
"/api/v1/admin/auth/login",
|
|
json={"email_or_username": test_admin.username, "password": "adminpass123"},
|
|
)
|
|
|
|
assert response.status_code == 403
|
|
data = response.json()
|
|
assert data["error_code"] == "USER_NOT_ACTIVE"
|
|
|
|
finally:
|
|
test_admin.is_active = original_status
|
|
db.commit()
|
|
|
|
def test_login_non_admin_user_rejected(self, client, test_user):
|
|
"""Test that non-admin users cannot use admin login."""
|
|
response = client.post(
|
|
"/api/v1/admin/auth/login",
|
|
json={"email_or_username": test_user.username, "password": "testpass123"},
|
|
)
|
|
|
|
assert response.status_code == 401
|
|
data = response.json()
|
|
assert data["error_code"] == "INVALID_CREDENTIALS"
|
|
|
|
def test_login_validation_error(self, client):
|
|
"""Test login with invalid request format."""
|
|
response = client.post(
|
|
"/api/v1/admin/auth/login",
|
|
json={
|
|
"email_or_username": "", # Empty
|
|
},
|
|
)
|
|
|
|
assert response.status_code == 422
|
|
data = response.json()
|
|
assert data["error_code"] == "VALIDATION_ERROR"
|
|
|
|
def test_get_current_admin_info(self, client, admin_headers, test_admin):
|
|
"""Test getting current admin user info."""
|
|
response = client.get("/api/v1/admin/auth/me", headers=admin_headers)
|
|
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["username"] == test_admin.username
|
|
assert data["email"] == test_admin.email
|
|
assert data["role"] == "admin"
|
|
assert data["is_active"] is True
|
|
|
|
def test_get_current_admin_without_auth(self, client):
|
|
"""Test getting current admin without authentication."""
|
|
response = client.get("/api/v1/admin/auth/me")
|
|
|
|
assert response.status_code == 401
|
|
data = response.json()
|
|
assert data["error_code"] == "INVALID_TOKEN"
|
|
|
|
def test_get_current_admin_invalid_token(self, client):
|
|
"""Test getting current admin with invalid token."""
|
|
response = client.get(
|
|
"/api/v1/admin/auth/me", headers={"Authorization": "Bearer invalid_token"}
|
|
)
|
|
|
|
assert response.status_code == 401
|
|
data = response.json()
|
|
assert data["error_code"] == "INVALID_TOKEN"
|
|
|
|
def test_get_current_admin_expired_token(self, client, test_admin, auth_manager):
|
|
"""Test getting current admin with expired token."""
|
|
expired_payload = {
|
|
"sub": str(test_admin.id),
|
|
"username": test_admin.username,
|
|
"email": test_admin.email,
|
|
"role": test_admin.role,
|
|
"exp": datetime.now(UTC) - timedelta(hours=1),
|
|
"iat": datetime.now(UTC) - timedelta(hours=2),
|
|
}
|
|
|
|
expired_token = jwt.encode(
|
|
expired_payload, auth_manager.secret_key, algorithm=auth_manager.algorithm
|
|
)
|
|
|
|
response = client.get(
|
|
"/api/v1/admin/auth/me", headers={"Authorization": f"Bearer {expired_token}"}
|
|
)
|
|
|
|
assert response.status_code == 401
|
|
data = response.json()
|
|
assert data["error_code"] == "TOKEN_EXPIRED"
|
|
|
|
def test_logout(self, client, admin_headers):
|
|
"""Test admin logout."""
|
|
response = client.post("/api/v1/admin/auth/logout", headers=admin_headers)
|
|
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["message"] == "Logged out successfully"
|