auth email/password

This commit is contained in:
JSC
2025-06-28 18:30:30 +02:00
parent 8e2dbd8723
commit ceafed9108
25 changed files with 1694 additions and 314 deletions

View File

@@ -1,4 +1,4 @@
"""Tests for authentication routes."""
"""Tests for authentication routes with Flask-JWT-Extended."""
from unittest.mock import Mock, patch
@@ -12,12 +12,13 @@ def client():
"""Create a test client for the Flask application."""
app = create_app()
app.config["TESTING"] = True
app.config["JWT_COOKIE_SECURE"] = False # Allow cookies in testing
with app.test_client() as client:
yield client
class TestAuthRoutes:
"""Test cases for authentication routes."""
class TestAuthRoutesJWTExtended:
"""Test cases for authentication routes with Flask-JWT-Extended."""
@patch("app.routes.auth.auth_service.get_login_url")
def test_login_route(self, mock_get_login_url: Mock, client) -> None:
@@ -30,33 +31,18 @@ class TestAuthRoutes:
assert "login_url" in data
assert data["login_url"] == "https://accounts.google.com/oauth/authorize?..."
def test_callback_route_no_code(self, client) -> None:
"""Test callback route without authorization code."""
response = client.get("/api/auth/callback")
assert response.status_code == 400
data = response.get_json()
assert data["error"] == "Authorization code not found"
@patch("app.routes.auth.auth_service.handle_callback")
def test_callback_route_success(self, mock_handle_callback: Mock, client) -> None:
"""Test successful callback route."""
user_data = {
"id": "123",
"email": "test@example.com",
"name": "Test User"
}
mock_response = Mock()
mock_response.get_json.return_value = {
"message": "Login successful",
"user": user_data
"user": {"id": "123", "email": "test@example.com", "name": "Test User"}
}
mock_handle_callback.return_value = (user_data, mock_response)
mock_handle_callback.return_value = mock_response
with patch("app.routes.auth.client.get") as mock_get:
mock_get.return_value = mock_response
response = client.get("/api/auth/callback?code=test_code")
# Since we're returning the mock response directly, we need to verify differently
mock_handle_callback.assert_called_once()
response = client.get("/api/auth/callback?code=test_code")
mock_handle_callback.assert_called_once()
@patch("app.routes.auth.auth_service.handle_callback")
def test_callback_route_error(self, mock_handle_callback: Mock, client) -> None:
@@ -75,32 +61,19 @@ class TestAuthRoutes:
mock_response.get_json.return_value = {"message": "Logged out successfully"}
mock_logout.return_value = mock_response
with patch("app.routes.auth.client.get") as mock_get:
mock_get.return_value = mock_response
response = client.get("/api/auth/logout")
mock_logout.assert_called_once()
response = client.get("/api/auth/logout")
mock_logout.assert_called_once()
@patch("app.routes.auth.auth_service.get_current_user")
def test_me_route_authenticated(self, mock_get_current_user: Mock, client) -> None:
"""Test /me route when authenticated."""
user_data = {
"id": "123",
"email": "test@example.com",
"name": "Test User"
}
mock_get_current_user.return_value = user_data
response = client.get("/api/auth/me")
assert response.status_code == 200
data = response.get_json()
assert data["user"] == user_data
@patch("app.routes.auth.auth_service.get_current_user")
def test_me_route_not_authenticated(self, mock_get_current_user: Mock, client) -> None:
def test_me_route_not_authenticated(self, client) -> None:
"""Test /me route when not authenticated."""
mock_get_current_user.return_value = None
response = client.get("/api/auth/me")
assert response.status_code == 401
data = response.get_json()
assert data["error"] == "Not authenticated"
assert "msg" in data # Flask-JWT-Extended error format
def test_refresh_route_not_authenticated(self, client) -> None:
"""Test /refresh route when not authenticated."""
response = client.post("/api/auth/refresh")
assert response.status_code == 401
data = response.get_json()
assert "msg" in data # Flask-JWT-Extended error format

View File

@@ -1,12 +1,13 @@
"""Tests for AuthService."""
"""Tests for AuthService with Flask-JWT-Extended."""
from unittest.mock import Mock, patch
from app import create_app
from app.services.auth_service import AuthService
class TestAuthService:
"""Test cases for AuthService."""
class TestAuthServiceJWTExtended:
"""Test cases for AuthService with Flask-JWT-Extended."""
def test_init_without_app(self) -> None:
"""Test initializing AuthService without Flask app."""
@@ -23,59 +24,25 @@ class TestAuthService:
"GOOGLE_CLIENT_SECRET": "test_client_secret"
}.get(key)
mock_app = Mock()
app = create_app()
auth_service = AuthService()
auth_service.init_app(mock_app)
auth_service.init_app(app)
auth_service.oauth.init_app.assert_called_once_with(mock_app)
# Verify OAuth was initialized
assert auth_service.google is not None
@patch("app.services.auth_service.request")
def test_get_current_user_no_token(self, mock_request: Mock) -> None:
"""Test getting current user when no token exists."""
mock_request.cookies.get.return_value = None
auth_service = AuthService()
user = auth_service.get_current_user()
assert user is None
@patch("app.services.auth_service.request")
def test_get_current_user_with_token(self, mock_request: Mock) -> None:
"""Test getting current user when valid token exists."""
mock_request.cookies.get.return_value = "valid.access.token"
auth_service = AuthService()
user_data = {"id": "123", "email": "test@example.com", "name": "Test User"}
with patch.object(auth_service.token_service, 'get_user_from_access_token', return_value=user_data):
user = auth_service.get_current_user()
assert user == user_data
@patch("app.services.auth_service.request")
def test_is_authenticated_false(self, mock_request: Mock) -> None:
"""Test authentication check when not authenticated."""
mock_request.cookies.get.return_value = None
auth_service = AuthService()
assert not auth_service.is_authenticated()
@patch("app.services.auth_service.request")
def test_is_authenticated_true(self, mock_request: Mock) -> None:
"""Test authentication check when authenticated."""
mock_request.cookies.get.return_value = "valid.access.token"
auth_service = AuthService()
user_data = {"id": "123", "email": "test@example.com", "name": "Test User"}
with patch.object(auth_service.token_service, 'get_user_from_access_token', return_value=user_data):
assert auth_service.is_authenticated()
@patch("app.services.auth_service.make_response")
def test_logout(self, mock_make_response: Mock) -> None:
@patch("app.services.auth_service.unset_jwt_cookies")
@patch("app.services.auth_service.jsonify")
def test_logout(self, mock_jsonify: Mock, mock_unset: Mock) -> None:
"""Test logout functionality."""
mock_response = Mock()
mock_make_response.return_value = mock_response
auth_service = AuthService()
result = auth_service.logout()
assert result == mock_response
mock_response.set_cookie.assert_any_call("access_token", "", expires=0)
mock_response.set_cookie.assert_any_call("refresh_token", "", expires=0)
app = create_app()
with app.app_context():
mock_response = Mock()
mock_jsonify.return_value = mock_response
auth_service = AuthService()
result = auth_service.logout()
assert result == mock_response
mock_unset.assert_called_once_with(mock_response)
mock_jsonify.assert_called_once_with({"message": "Logged out successfully"})

View File

@@ -0,0 +1,57 @@
"""Tests for TokenService using Flask-JWT-Extended."""
from unittest.mock import patch
from app import create_app
from app.services.token_service import TokenService
class TestTokenServiceJWTExtended:
"""Test cases for TokenService with Flask-JWT-Extended."""
def test_generate_access_token(self) -> None:
"""Test access token generation."""
app = create_app()
with app.app_context():
token_service = TokenService()
user_data = {
"id": "123",
"email": "test@example.com",
"name": "Test User",
"picture": "https://example.com/pic.jpg"
}
token = token_service.generate_access_token(user_data)
assert isinstance(token, str)
assert len(token) > 0
def test_generate_refresh_token(self) -> None:
"""Test refresh token generation."""
app = create_app()
with app.app_context():
token_service = TokenService()
user_data = {
"id": "123",
"email": "test@example.com",
"name": "Test User"
}
token = token_service.generate_refresh_token(user_data)
assert isinstance(token, str)
assert len(token) > 0
def test_generate_tokens_different(self) -> None:
"""Test that access and refresh tokens are different."""
app = create_app()
with app.app_context():
token_service = TokenService()
user_data = {
"id": "123",
"email": "test@example.com",
"name": "Test User"
}
access_token = token_service.generate_access_token(user_data)
refresh_token = token_service.generate_refresh_token(user_data)
assert access_token != refresh_token