test fixes

This commit is contained in:
2025-10-19 19:57:42 +02:00
parent d698ae50a2
commit d87ec398bb
10 changed files with 943 additions and 153 deletions

View File

@@ -8,20 +8,6 @@ import pytest
from httpx import ASGITransport, AsyncClient
from src.server.fastapi_app import app
from src.server.services.auth_service import auth_service
@pytest.fixture(autouse=True)
def reset_auth():
"""Reset authentication state before each test."""
# Reset auth service state
original_hash = auth_service._hash
auth_service._hash = None
auth_service._failed.clear()
yield
# Restore
auth_service._hash = original_hash
auth_service._failed.clear()
@pytest.fixture
@@ -49,10 +35,10 @@ class TestFrontendAuthIntegration:
async def test_login_returns_access_token(self, client):
"""Test login flow and verify JWT token is returned."""
# Setup master password first
client.post("/api/auth/setup", json={"master_password": "StrongP@ss123"})
await client.post("/api/auth/setup", json={"master_password": "StrongP@ss123"})
# Login with correct password
response = client.post(
response = await client.post(
"/api/auth/login",
json={"password": "StrongP@ss123"}
)
@@ -67,18 +53,18 @@ class TestFrontendAuthIntegration:
# Verify token can be used for authenticated requests
token = data["access_token"]
headers = {"Authorization": f"Bearer {token}"}
response = client.get("/api/auth/status", headers=headers)
response = await client.get("/api/auth/status", headers=headers)
assert response.status_code == 200
data = response.json()
assert data["authenticated"] is True
def test_login_with_wrong_password(self, client):
async def test_login_with_wrong_password(self, client):
"""Test login with incorrect password."""
# Setup master password first
client.post("/api/auth/setup", json={"master_password": "StrongP@ss123"})
await client.post("/api/auth/setup", json={"master_password": "StrongP@ss123"})
# Login with wrong password
response = client.post(
response = await client.post(
"/api/auth/login",
json={"password": "WrongPassword"}
)
@@ -86,11 +72,11 @@ class TestFrontendAuthIntegration:
data = response.json()
assert "detail" in data
def test_logout_clears_session(self, client):
async def test_logout_clears_session(self, client):
"""Test logout functionality."""
# Setup and login
client.post("/api/auth/setup", json={"master_password": "StrongP@ss123"})
login_response = client.post(
await client.post("/api/auth/setup", json={"master_password": "StrongP@ss123"})
login_response = await client.post(
"/api/auth/login",
json={"password": "StrongP@ss123"}
)
@@ -98,43 +84,49 @@ class TestFrontendAuthIntegration:
headers = {"Authorization": f"Bearer {token}"}
# Logout
response = client.post("/api/auth/logout", headers=headers)
response = await client.post("/api/auth/logout", headers=headers)
assert response.status_code == 200
assert response.json()["status"] == "ok"
def test_authenticated_request_without_token_returns_401(self, client):
async def test_authenticated_request_without_token_returns_401(self, client):
"""Test that authenticated endpoints reject requests without tokens."""
# Setup master password
client.post("/api/auth/setup", json={"master_password": "StrongP@ss123"})
await client.post("/api/auth/setup", json={"master_password": "StrongP@ss123"})
# Try to access authenticated endpoint without token
response = client.get("/api/v1/anime")
response = await client.get("/api/v1/anime")
assert response.status_code == 401
def test_authenticated_request_with_invalid_token_returns_401(self, client):
async def test_authenticated_request_with_invalid_token_returns_401(
self, client
):
"""Test that authenticated endpoints reject invalid tokens."""
# Setup master password
client.post("/api/auth/setup", json={"master_password": "StrongP@ss123"})
await client.post(
"/api/auth/setup", json={"master_password": "StrongP@ss123"}
)
# Try to access authenticated endpoint with invalid token
headers = {"Authorization": "Bearer invalid_token_here"}
response = client.get("/api/v1/anime", headers=headers)
response = await client.get("/api/v1/anime", headers=headers)
assert response.status_code == 401
def test_remember_me_extends_token_expiry(self, client):
async def test_remember_me_extends_token_expiry(self, client):
"""Test that remember_me flag affects token expiry."""
# Setup master password
client.post("/api/auth/setup", json={"master_password": "StrongP@ss123"})
await client.post(
"/api/auth/setup", json={"master_password": "StrongP@ss123"}
)
# Login without remember me
response1 = client.post(
response1 = await client.post(
"/api/auth/login",
json={"password": "StrongP@ss123", "remember": False}
)
data1 = response1.json()
# Login with remember me
response2 = client.post(
response2 = await client.post(
"/api/auth/login",
json={"password": "StrongP@ss123", "remember": True}
)
@@ -144,37 +136,41 @@ class TestFrontendAuthIntegration:
assert "expires_at" in data1
assert "expires_at" in data2
def test_setup_fails_if_already_configured(self, client):
async def test_setup_fails_if_already_configured(self, client):
"""Test that setup fails if master password is already set."""
# Setup once
client.post("/api/auth/setup", json={"master_password": "StrongP@ss123"})
await client.post(
"/api/auth/setup", json={"master_password": "StrongP@ss123"}
)
# Try to setup again
response = client.post(
response = await client.post(
"/api/auth/setup",
json={"master_password": "AnotherPassword123!"}
)
assert response.status_code == 400
assert "already configured" in response.json()["detail"].lower()
assert (
"already configured" in response.json()["detail"].lower()
)
def test_weak_password_validation_in_setup(self, client):
async def test_weak_password_validation_in_setup(self, client):
"""Test that setup rejects weak passwords."""
# Try with short password
response = client.post(
response = await client.post(
"/api/auth/setup",
json={"master_password": "short"}
)
assert response.status_code == 400
# Try with all lowercase
response = client.post(
response = await client.post(
"/api/auth/setup",
json={"master_password": "alllowercase"}
)
assert response.status_code == 400
# Try without special characters
response = client.post(
response = await client.post(
"/api/auth/setup",
json={"master_password": "NoSpecialChars123"}
)
@@ -184,17 +180,19 @@ class TestFrontendAuthIntegration:
class TestTokenAuthenticationFlow:
"""Test JWT token-based authentication workflow."""
def test_full_authentication_workflow(self, client):
async def test_full_authentication_workflow(self, client):
"""Test complete authentication workflow with token management."""
# 1. Check initial status
response = client.get("/api/auth/status")
response = await client.get("/api/auth/status")
assert not response.json()["configured"]
# 2. Setup master password
client.post("/api/auth/setup", json={"master_password": "StrongP@ss123"})
await client.post(
"/api/auth/setup", json={"master_password": "StrongP@ss123"}
)
# 3. Login and get token
response = client.post(
response = await client.post(
"/api/auth/login",
json={"password": "StrongP@ss123"}
)
@@ -202,18 +200,22 @@ class TestTokenAuthenticationFlow:
headers = {"Authorization": f"Bearer {token}"}
# 4. Access authenticated endpoint
response = client.get("/api/auth/status", headers=headers)
response = await client.get("/api/auth/status", headers=headers)
assert response.json()["authenticated"] is True
# 5. Logout
response = client.post("/api/auth/logout", headers=headers)
response = await client.post("/api/auth/logout", headers=headers)
assert response.json()["status"] == "ok"
def test_token_included_in_all_authenticated_requests(self, client):
async def test_token_included_in_all_authenticated_requests(
self, client
):
"""Test that token must be included in authenticated API requests."""
# Setup and login
client.post("/api/auth/setup", json={"master_password": "StrongP@ss123"})
response = client.post(
await client.post(
"/api/auth/setup", json={"master_password": "StrongP@ss123"}
)
response = await client.post(
"/api/auth/login",
json={"password": "StrongP@ss123"}
)
@@ -229,10 +231,14 @@ class TestTokenAuthenticationFlow:
for endpoint in endpoints:
# Without token - should fail
response = client.get(endpoint)
assert response.status_code == 401, f"Endpoint {endpoint} should require auth"
response = await client.get(endpoint)
assert response.status_code == 401, (
f"Endpoint {endpoint} should require auth"
)
# With token - should work or return expected response
response = client.get(endpoint, headers=headers)
# Some endpoints may return 503 if services not configured, that's ok
assert response.status_code in [200, 503], f"Endpoint {endpoint} failed with token"
response = await client.get(endpoint, headers=headers)
# Some endpoints may return 503 if services not configured
assert response.status_code in [200, 503], (
f"Endpoint {endpoint} failed with token"
)