205 lines
6.9 KiB
Python
205 lines
6.9 KiB
Python
"""
|
|
Unit tests for authentication service
|
|
"""
|
|
|
|
import pytest
|
|
from unittest.mock import Mock
|
|
from src.auth.service import AuthService
|
|
from src.database.models import User
|
|
from src.database.repositories import UserRepository
|
|
|
|
|
|
class TestAuthService:
|
|
"""Test suite for AuthService"""
|
|
|
|
@pytest.fixture
|
|
def mock_user_repository(self):
|
|
"""Create a mock user repository"""
|
|
return Mock(spec=UserRepository)
|
|
|
|
@pytest.fixture
|
|
def auth_service(self, mock_user_repository):
|
|
"""Create an auth service instance with mock repository"""
|
|
return AuthService(mock_user_repository)
|
|
|
|
def test_hash_password_generates_hash(self, auth_service):
|
|
"""Test that password hashing generates a hash string"""
|
|
password = "test_password_123"
|
|
hashed = auth_service.hash_password(password)
|
|
|
|
# Hash should be a string and different from plain password
|
|
assert isinstance(hashed, str)
|
|
assert hashed != password
|
|
assert len(hashed) > 0
|
|
|
|
def test_hash_password_generates_different_hashes(self, auth_service):
|
|
"""Test that same password generates different hashes (salt)"""
|
|
password = "test_password_123"
|
|
hash1 = auth_service.hash_password(password)
|
|
hash2 = auth_service.hash_password(password)
|
|
|
|
# Different hashes due to salt
|
|
assert hash1 != hash2
|
|
|
|
def test_verify_password_succeeds_with_correct_password(self, auth_service):
|
|
"""Test that password verification succeeds with correct password"""
|
|
password = "correct_password"
|
|
hashed = auth_service.hash_password(password)
|
|
|
|
assert auth_service.verify_password(password, hashed) is True
|
|
|
|
def test_verify_password_fails_with_incorrect_password(self, auth_service):
|
|
"""Test that password verification fails with incorrect password"""
|
|
password = "correct_password"
|
|
wrong_password = "wrong_password"
|
|
hashed = auth_service.hash_password(password)
|
|
|
|
assert auth_service.verify_password(wrong_password, hashed) is False
|
|
|
|
def test_authenticate_user_succeeds_with_valid_credentials(
|
|
self, auth_service, mock_user_repository
|
|
):
|
|
"""Test that authentication succeeds with valid username and password"""
|
|
# Setup
|
|
username = "test_user"
|
|
password = "test_password"
|
|
hashed_password = auth_service.hash_password(password)
|
|
|
|
mock_user = User(
|
|
id=1,
|
|
username=username,
|
|
hashed_password=hashed_password,
|
|
role="User"
|
|
)
|
|
mock_user_repository.get_by_username.return_value = mock_user
|
|
|
|
# Execute
|
|
result = auth_service.authenticate_user(username, password)
|
|
|
|
# Assert
|
|
assert result is not None
|
|
assert result.username == username
|
|
assert result.role == "User"
|
|
mock_user_repository.get_by_username.assert_called_once_with(username)
|
|
|
|
def test_authenticate_user_fails_with_invalid_username(
|
|
self, auth_service, mock_user_repository
|
|
):
|
|
"""Test that authentication fails when username doesn't exist"""
|
|
# Setup
|
|
mock_user_repository.get_by_username.return_value = None
|
|
|
|
# Execute
|
|
result = auth_service.authenticate_user("nonexistent", "password")
|
|
|
|
# Assert
|
|
assert result is None
|
|
mock_user_repository.get_by_username.assert_called_once_with("nonexistent")
|
|
|
|
def test_authenticate_user_fails_with_invalid_password(
|
|
self, auth_service, mock_user_repository
|
|
):
|
|
"""Test that authentication fails with incorrect password"""
|
|
# Setup
|
|
username = "test_user"
|
|
correct_password = "correct_password"
|
|
wrong_password = "wrong_password"
|
|
hashed_password = auth_service.hash_password(correct_password)
|
|
|
|
mock_user = User(
|
|
id=1,
|
|
username=username,
|
|
hashed_password=hashed_password,
|
|
role="User"
|
|
)
|
|
mock_user_repository.get_by_username.return_value = mock_user
|
|
|
|
# Execute
|
|
result = auth_service.authenticate_user(username, wrong_password)
|
|
|
|
# Assert
|
|
assert result is None
|
|
mock_user_repository.get_by_username.assert_called_once_with(username)
|
|
|
|
def test_authenticate_user_identifies_admin_role(
|
|
self, auth_service, mock_user_repository
|
|
):
|
|
"""Test that authenticated admin user can be identified by role"""
|
|
# Setup
|
|
username = "admin_user"
|
|
password = "admin_password"
|
|
hashed_password = auth_service.hash_password(password)
|
|
|
|
mock_user = User(
|
|
id=1,
|
|
username=username,
|
|
hashed_password=hashed_password,
|
|
role="Admin"
|
|
)
|
|
mock_user_repository.get_by_username.return_value = mock_user
|
|
|
|
# Execute
|
|
result = auth_service.authenticate_user(username, password)
|
|
|
|
# Assert
|
|
assert result is not None
|
|
assert result.role == "Admin"
|
|
assert result.is_admin() is True
|
|
|
|
def test_authenticate_user_identifies_regular_user_role(
|
|
self, auth_service, mock_user_repository
|
|
):
|
|
"""Test that authenticated regular user can be identified by role"""
|
|
# Setup
|
|
username = "regular_user"
|
|
password = "user_password"
|
|
hashed_password = auth_service.hash_password(password)
|
|
|
|
mock_user = User(
|
|
id=1,
|
|
username=username,
|
|
hashed_password=hashed_password,
|
|
role="User"
|
|
)
|
|
mock_user_repository.get_by_username.return_value = mock_user
|
|
|
|
# Execute
|
|
result = auth_service.authenticate_user(username, password)
|
|
|
|
# Assert
|
|
assert result is not None
|
|
assert result.role == "User"
|
|
assert result.is_admin() is False
|
|
|
|
def test_create_user_with_hashed_password(
|
|
self, auth_service, mock_user_repository
|
|
):
|
|
"""Test that creating a user hashes the password"""
|
|
# Setup
|
|
username = "new_user"
|
|
password = "plain_password"
|
|
role = "User"
|
|
|
|
mock_user = User(
|
|
id=1,
|
|
username=username,
|
|
hashed_password="hashed_value",
|
|
role=role
|
|
)
|
|
mock_user_repository.create.return_value = mock_user
|
|
|
|
# Execute
|
|
result = auth_service.create_user_with_hashed_password(
|
|
username, password, role
|
|
)
|
|
|
|
# Assert
|
|
assert result is not None
|
|
assert result.username == username
|
|
# Verify that create was called with a hashed password (not plain text)
|
|
call_args = mock_user_repository.create.call_args
|
|
assert call_args[0][0] == username # username
|
|
assert call_args[0][1] != password # hashed_password should not equal plain password
|
|
assert call_args[0][2] == role # role
|
|
|