Big-Link-Man/tests/unit/test_auth_service.py

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