# tests/test_auth_service.py import pytest from fastapi import HTTPException from app.services.auth_service import AuthService from models.database_models import User from models.api_models import UserRegister, UserLogin class TestAuthService: """Test suite for AuthService following the application's testing patterns""" def setup_method(self): """Setup method following the same pattern as admin service tests""" self.service = AuthService() def test_register_user_success(self, db): """Test successful user registration""" user_data = UserRegister( email="newuser@example.com", username="newuser123", password="securepass123" ) user = self.service.register_user(db, user_data) assert user is not None assert user.email == "newuser@example.com" assert user.username == "newuser123" assert user.role == "user" assert user.is_active is True assert user.hashed_password != "securepass123" # Should be hashed def test_register_user_email_already_exists(self, db, test_user): """Test registration fails when email already exists""" user_data = UserRegister( email=test_user.email, # Use existing email username="differentuser", password="securepass123" ) with pytest.raises(HTTPException) as exc_info: self.service.register_user(db, user_data) assert exc_info.value.status_code == 400 assert "Email already registered" in str(exc_info.value.detail) def test_register_user_username_already_exists(self, db, test_user): """Test registration fails when username already exists""" user_data = UserRegister( email="different@example.com", username=test_user.username, # Use existing username password="securepass123" ) with pytest.raises(HTTPException) as exc_info: self.service.register_user(db, user_data) assert exc_info.value.status_code == 400 assert "Username already taken" in str(exc_info.value.detail) def test_login_user_success(self, db, test_user): """Test successful user login""" user_credentials = UserLogin( username=test_user.username, password="testpass123" ) result = self.service.login_user(db, user_credentials) assert "token_data" in result assert "user" in result assert result["user"].id == test_user.id assert result["user"].username == test_user.username assert "access_token" in result["token_data"] assert "token_type" in result["token_data"] assert "expires_in" in result["token_data"] def test_login_user_wrong_username(self, db): """Test login fails with wrong username""" user_credentials = UserLogin( username="nonexistentuser", password="testpass123" ) with pytest.raises(HTTPException) as exc_info: self.service.login_user(db, user_credentials) assert exc_info.value.status_code == 401 assert "Incorrect username or password" in str(exc_info.value.detail) def test_login_user_wrong_password(self, db, test_user): """Test login fails with wrong password""" user_credentials = UserLogin( username=test_user.username, password="wrongpassword" ) with pytest.raises(HTTPException) as exc_info: self.service.login_user(db, user_credentials) assert exc_info.value.status_code == 401 assert "Incorrect username or password" in str(exc_info.value.detail) def test_login_user_inactive_user(self, db, test_user): """Test login fails for inactive user""" # Deactivate user test_user.is_active = False db.commit() user_credentials = UserLogin( username=test_user.username, password="testpass123" ) with pytest.raises(HTTPException) as exc_info: self.service.login_user(db, user_credentials) assert exc_info.value.status_code == 401 assert "Incorrect username or password" in str(exc_info.value.detail) def test_get_user_by_email(self, db, test_user): """Test getting user by email""" user = self.service.get_user_by_email(db, test_user.email) assert user is not None assert user.id == test_user.id assert user.email == test_user.email def test_get_user_by_email_not_found(self, db): """Test getting user by email when user doesn't exist""" user = self.service.get_user_by_email(db, "nonexistent@example.com") assert user is None def test_get_user_by_username(self, db, test_user): """Test getting user by username""" user = self.service.get_user_by_username(db, test_user.username) assert user is not None assert user.id == test_user.id assert user.username == test_user.username def test_get_user_by_username_not_found(self, db): """Test getting user by username when user doesn't exist""" user = self.service.get_user_by_username(db, "nonexistentuser") assert user is None def test_email_exists_true(self, db, test_user): """Test email_exists returns True when email exists""" exists = self.service.email_exists(db, test_user.email) assert exists is True def test_email_exists_false(self, db): """Test email_exists returns False when email doesn't exist""" exists = self.service.email_exists(db, "nonexistent@example.com") assert exists is False def test_username_exists_true(self, db, test_user): """Test username_exists returns True when username exists""" exists = self.service.username_exists(db, test_user.username) assert exists is True def test_username_exists_false(self, db): """Test username_exists returns False when username doesn't exist""" exists = self.service.username_exists(db, "nonexistentuser") assert exists is False def test_authenticate_user_success(self, db, test_user): """Test successful user authentication""" user = self.service.authenticate_user(db, test_user.username, "testpass123") assert user is not None assert user.id == test_user.id assert user.username == test_user.username def test_authenticate_user_wrong_password(self, db, test_user): """Test authentication fails with wrong password""" user = self.service.authenticate_user(db, test_user.username, "wrongpassword") assert user is None def test_authenticate_user_nonexistent(self, db): """Test authentication fails with nonexistent user""" user = self.service.authenticate_user(db, "nonexistentuser", "password") assert user is None def test_create_access_token(self, test_user): """Test creating access token for user""" token_data = self.service.create_access_token(test_user) assert "access_token" in token_data assert "token_type" in token_data assert "expires_in" in token_data assert token_data["token_type"] == "bearer" assert isinstance(token_data["expires_in"], int) assert token_data["expires_in"] > 0 def test_hash_password(self): """Test password hashing""" password = "testpassword123" hashed = self.service.hash_password(password) assert hashed != password assert len(hashed) > len(password) assert hashed.startswith("$") # bcrypt hash format def test_hash_password_different_results(self): """Test that hashing same password produces different hashes (salt)""" password = "testpassword123" hash1 = self.service.hash_password(password) hash2 = self.service.hash_password(password) assert hash1 != hash2 # Should be different due to salt