Moved `auth` module from `dependencies.py` to `dependencies/auth.py` for better organization. Added extensive unit tests for authentication services and API dependencies to ensure robust verification of users, tokens, and permissions.
211 lines
8.1 KiB
Python
211 lines
8.1 KiB
Python
# tests/api/dependencies/test_auth_dependencies.py
|
|
import pytest
|
|
from unittest.mock import patch, MagicMock
|
|
from fastapi import HTTPException
|
|
|
|
from app.api.dependencies.auth import (
|
|
get_current_user,
|
|
get_current_active_user,
|
|
get_current_superuser,
|
|
get_optional_current_user
|
|
)
|
|
from app.core.auth import TokenExpiredError, TokenInvalidError
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_token():
|
|
return "mock.jwt.token"
|
|
|
|
|
|
class TestGetCurrentUser:
|
|
"""Tests for get_current_user dependency"""
|
|
|
|
def test_get_current_user_success(self, db_session, mock_user, mock_token):
|
|
"""Test successfully getting the current user"""
|
|
# Mock get_token_data to return user_id that matches our mock_user
|
|
with patch('app.api.dependencies.auth.get_token_data') as mock_get_data:
|
|
mock_get_data.return_value.user_id = mock_user.id
|
|
|
|
# Call the dependency
|
|
user = get_current_user(db=db_session, token=mock_token)
|
|
|
|
# Verify the correct user was returned
|
|
assert user.id == mock_user.id
|
|
assert user.email == mock_user.email
|
|
|
|
def test_get_current_user_nonexistent(self, db_session, mock_token):
|
|
"""Test when the token contains a user ID that doesn't exist"""
|
|
# Mock get_token_data to return a non-existent user ID
|
|
# Use a real UUID object instead of a string
|
|
import uuid
|
|
nonexistent_id = uuid.UUID("11111111-1111-1111-1111-111111111111")
|
|
|
|
with patch('app.api.dependencies.auth.get_token_data') as mock_get_data:
|
|
mock_get_data.return_value.user_id = nonexistent_id # Using UUID object, not string
|
|
|
|
# Should raise HTTPException with 404 status
|
|
with pytest.raises(HTTPException) as exc_info:
|
|
get_current_user(db=db_session, token=mock_token)
|
|
|
|
assert exc_info.value.status_code == 404
|
|
|
|
def test_get_current_user_inactive(self, db_session, mock_user, mock_token):
|
|
"""Test when the user is inactive"""
|
|
# Make the user inactive
|
|
mock_user.is_active = False
|
|
db_session.commit()
|
|
|
|
# Mock get_token_data
|
|
with patch('app.api.dependencies.auth.get_token_data') as mock_get_data:
|
|
mock_get_data.return_value.user_id = mock_user.id
|
|
|
|
# Should raise HTTPException with 403 status
|
|
with pytest.raises(HTTPException) as exc_info:
|
|
get_current_user(db=db_session, token=mock_token)
|
|
|
|
assert exc_info.value.status_code == 403
|
|
|
|
def test_get_current_user_expired_token(self, db_session, mock_token):
|
|
"""Test with an expired token"""
|
|
# Mock get_token_data to raise TokenExpiredError
|
|
with patch('app.api.dependencies.auth.get_token_data') as mock_get_data:
|
|
mock_get_data.side_effect = TokenExpiredError("Token expired")
|
|
|
|
# Should raise HTTPException with 401 status
|
|
with pytest.raises(HTTPException) as exc_info:
|
|
get_current_user(db=db_session, token=mock_token)
|
|
|
|
assert exc_info.value.status_code == 401
|
|
assert "Token expired" in exc_info.value.detail
|
|
|
|
def test_get_current_user_invalid_token(self, db_session, mock_token):
|
|
"""Test with an invalid token"""
|
|
# Mock get_token_data to raise TokenInvalidError
|
|
with patch('app.api.dependencies.auth.get_token_data') as mock_get_data:
|
|
mock_get_data.side_effect = TokenInvalidError("Invalid token")
|
|
|
|
# Should raise HTTPException with 401 status
|
|
with pytest.raises(HTTPException) as exc_info:
|
|
get_current_user(db=db_session, token=mock_token)
|
|
|
|
assert exc_info.value.status_code == 401
|
|
assert "Could not validate credentials" in exc_info.value.detail
|
|
|
|
|
|
class TestGetCurrentActiveUser:
|
|
"""Tests for get_current_active_user dependency"""
|
|
|
|
def test_get_current_active_user(self, mock_user):
|
|
"""Test getting an active user"""
|
|
# Ensure user is active
|
|
mock_user.is_active = True
|
|
|
|
# Call the dependency with mocked current_user
|
|
user = get_current_active_user(current_user=mock_user)
|
|
|
|
# Should return the same user
|
|
assert user == mock_user
|
|
|
|
def test_get_current_inactive_user(self, mock_user):
|
|
"""Test getting an inactive user"""
|
|
# Make user inactive
|
|
mock_user.is_active = False
|
|
|
|
# Should raise HTTPException with 403 status
|
|
with pytest.raises(HTTPException) as exc_info:
|
|
get_current_active_user(current_user=mock_user)
|
|
|
|
assert exc_info.value.status_code == 403
|
|
assert "Inactive user" in exc_info.value.detail
|
|
|
|
|
|
class TestGetCurrentSuperuser:
|
|
"""Tests for get_current_superuser dependency"""
|
|
|
|
def test_get_current_superuser(self, mock_user):
|
|
"""Test getting a superuser"""
|
|
# Make user a superuser
|
|
mock_user.is_superuser = True
|
|
|
|
# Call the dependency with mocked current_user
|
|
user = get_current_superuser(current_user=mock_user)
|
|
|
|
# Should return the same user
|
|
assert user == mock_user
|
|
|
|
def test_get_current_non_superuser(self, mock_user):
|
|
"""Test getting a non-superuser"""
|
|
# Ensure user is not a superuser
|
|
mock_user.is_superuser = False
|
|
|
|
# Should raise HTTPException with 403 status
|
|
with pytest.raises(HTTPException) as exc_info:
|
|
get_current_superuser(current_user=mock_user)
|
|
|
|
assert exc_info.value.status_code == 403
|
|
assert "Not enough permissions" in exc_info.value.detail
|
|
|
|
|
|
class TestGetOptionalCurrentUser:
|
|
"""Tests for get_optional_current_user dependency"""
|
|
|
|
def test_get_optional_current_user_with_token(self, db_session, mock_user, mock_token):
|
|
"""Test getting optional user with a valid token"""
|
|
# Mock get_token_data
|
|
with patch('app.api.dependencies.auth.get_token_data') as mock_get_data:
|
|
mock_get_data.return_value.user_id = mock_user.id
|
|
|
|
# Call the dependency
|
|
user = get_optional_current_user(db=db_session, token=mock_token)
|
|
|
|
# Should return the correct user
|
|
assert user is not None
|
|
assert user.id == mock_user.id
|
|
|
|
def test_get_optional_current_user_no_token(self, db_session):
|
|
"""Test getting optional user with no token"""
|
|
# Call the dependency with no token
|
|
user = get_optional_current_user(db=db_session, token=None)
|
|
|
|
# Should return None
|
|
assert user is None
|
|
|
|
def test_get_optional_current_user_invalid_token(self, db_session, mock_token):
|
|
"""Test getting optional user with an invalid token"""
|
|
# Mock get_token_data to raise TokenInvalidError
|
|
with patch('app.api.dependencies.auth.get_token_data') as mock_get_data:
|
|
mock_get_data.side_effect = TokenInvalidError("Invalid token")
|
|
|
|
# Call the dependency
|
|
user = get_optional_current_user(db=db_session, token=mock_token)
|
|
|
|
# Should return None, not raise an exception
|
|
assert user is None
|
|
|
|
def test_get_optional_current_user_expired_token(self, db_session, mock_token):
|
|
"""Test getting optional user with an expired token"""
|
|
# Mock get_token_data to raise TokenExpiredError
|
|
with patch('app.api.dependencies.auth.get_token_data') as mock_get_data:
|
|
mock_get_data.side_effect = TokenExpiredError("Token expired")
|
|
|
|
# Call the dependency
|
|
user = get_optional_current_user(db=db_session, token=mock_token)
|
|
|
|
# Should return None, not raise an exception
|
|
assert user is None
|
|
|
|
def test_get_optional_current_user_inactive(self, db_session, mock_user, mock_token):
|
|
"""Test getting optional user when user is inactive"""
|
|
# Make the user inactive
|
|
mock_user.is_active = False
|
|
db_session.commit()
|
|
|
|
# Mock get_token_data
|
|
with patch('app.api.dependencies.auth.get_token_data') as mock_get_data:
|
|
mock_get_data.return_value.user_id = mock_user.id
|
|
|
|
# Call the dependency
|
|
user = get_optional_current_user(db=db_session, token=mock_token)
|
|
|
|
# Should return None for inactive users
|
|
assert user is None |