e1efbdaf6e
CI/CD Pipeline / Validate Code Quality And Tests (push) Has been cancelled
CI/CD Pipeline / Frontend Lint (push) Has been cancelled
Deploy / Deploy Staging (push) Has been cancelled
Deploy / Build Production Runtime Images (push) Has been cancelled
Deploy / Deploy Production (push) Has been cancelled
Deploy / Production Browser E2E (push) Has been cancelled
200 lines
5.6 KiB
Python
200 lines
5.6 KiB
Python
"""
|
|
用户登录 Use Case 测试
|
|
"""
|
|
|
|
from datetime import datetime, timezone
|
|
from unittest.mock import Mock
|
|
|
|
import pytest
|
|
|
|
from packages.application.auth import (
|
|
LoginRequest,
|
|
LoginUseCase,
|
|
LogoutRequest,
|
|
LogoutUseCase,
|
|
)
|
|
from packages.application.auth.password_hasher import password_hasher
|
|
from packages.domain.entities import User
|
|
|
|
|
|
class TestLoginUseCase:
|
|
"""登录用例测试"""
|
|
|
|
@pytest.fixture
|
|
def mock_user_repo(self):
|
|
repo = Mock()
|
|
repo.find_by_email = Mock(return_value=None)
|
|
repo.save = Mock()
|
|
return repo
|
|
|
|
@pytest.fixture
|
|
def use_case(self, mock_user_repo):
|
|
session_store = Mock()
|
|
session_store.save_session.return_value = True
|
|
return LoginUseCase(user_repository=mock_user_repo, session_store=session_store)
|
|
|
|
@pytest.fixture
|
|
def test_user(self):
|
|
"""创建测试用户"""
|
|
password_hash = password_hasher.hash_password("SecurePass123")
|
|
return User(
|
|
id="user-123",
|
|
email="test@example.com",
|
|
username="testuser",
|
|
display_name="Test User",
|
|
password_hash=password_hash,
|
|
email_verified=True,
|
|
)
|
|
|
|
def test_login_success(self, use_case, mock_user_repo, test_user):
|
|
"""测试登录成功"""
|
|
mock_user_repo.find_by_email.return_value = test_user
|
|
|
|
request = LoginRequest(
|
|
email="test@example.com",
|
|
password="SecurePass123",
|
|
device_info="Chrome/Windows",
|
|
ip_address="192.168.1.1",
|
|
)
|
|
|
|
response, error = use_case.execute(request)
|
|
|
|
assert error is None
|
|
assert response is not None
|
|
assert response.user_id == "user-123"
|
|
assert response.email == "test@example.com"
|
|
assert response.username == "testuser"
|
|
assert response.access_token != ""
|
|
assert response.refresh_token != ""
|
|
assert response.expires_in > 0
|
|
|
|
# 验证保存了 session
|
|
use_case.session_store.save_session.assert_called_once()
|
|
|
|
# 验证更新了最后登录信息
|
|
mock_user_repo.save.assert_called_once()
|
|
|
|
def test_login_invalid_email(self, use_case, mock_user_repo):
|
|
"""测试邮箱不存在"""
|
|
mock_user_repo.find_by_email.return_value = None
|
|
|
|
request = LoginRequest(
|
|
email="nonexistent@example.com",
|
|
password="SecurePass123",
|
|
)
|
|
|
|
response, error = use_case.execute(request)
|
|
|
|
assert response is None
|
|
assert error == "Invalid email or password"
|
|
|
|
def test_login_wrong_password(self, use_case, mock_user_repo, test_user):
|
|
"""测试密码错误"""
|
|
mock_user_repo.find_by_email.return_value = test_user
|
|
|
|
request = LoginRequest(
|
|
email="test@example.com",
|
|
password="WrongPassword123",
|
|
)
|
|
|
|
response, error = use_case.execute(request)
|
|
|
|
assert response is None
|
|
assert error == "Invalid email or password"
|
|
|
|
def test_login_missing_email(self, use_case):
|
|
"""测试缺少邮箱"""
|
|
request = LoginRequest(
|
|
email="",
|
|
password="SecurePass123",
|
|
)
|
|
|
|
response, error = use_case.execute(request)
|
|
|
|
assert response is None
|
|
assert error == "Email is required"
|
|
|
|
def test_login_missing_password(self, use_case, mock_user_repo, test_user):
|
|
"""测试缺少密码"""
|
|
mock_user_repo.find_by_email.return_value = test_user
|
|
|
|
request = LoginRequest(
|
|
email="test@example.com",
|
|
password="",
|
|
)
|
|
|
|
response, error = use_case.execute(request)
|
|
|
|
assert response is None
|
|
assert error == "Password is required"
|
|
|
|
|
|
class TestLogoutUseCase:
|
|
"""登出用例测试"""
|
|
|
|
@pytest.fixture
|
|
def use_case(self):
|
|
session_store = Mock()
|
|
return LogoutUseCase(session_store=session_store)
|
|
|
|
def test_logout_current_device(self, use_case):
|
|
"""测试登出当前设备"""
|
|
use_case.session_store.delete_session.return_value = True
|
|
|
|
request = LogoutRequest(
|
|
user_id="user-123",
|
|
session_id="session-abc",
|
|
logout_all_devices=False,
|
|
)
|
|
|
|
success, error = use_case.execute(request)
|
|
|
|
assert success is True
|
|
assert error is None
|
|
|
|
use_case.session_store.delete_session.assert_called_once_with("session-abc")
|
|
|
|
def test_logout_all_devices(self, use_case):
|
|
"""测试登出所有设备"""
|
|
use_case.session_store.delete_all_user_sessions.return_value = 3
|
|
|
|
request = LogoutRequest(
|
|
user_id="user-123",
|
|
logout_all_devices=True,
|
|
)
|
|
|
|
success, error = use_case.execute(request)
|
|
|
|
assert success is True
|
|
assert error is None
|
|
|
|
use_case.session_store.delete_all_user_sessions.assert_called_once_with("user-123")
|
|
|
|
def test_logout_session_not_found(self, use_case):
|
|
"""测试 session 不存在"""
|
|
use_case.session_store.delete_session.return_value = False
|
|
|
|
request = LogoutRequest(
|
|
user_id="user-123",
|
|
session_id="nonexistent",
|
|
logout_all_devices=False,
|
|
)
|
|
|
|
success, error = use_case.execute(request)
|
|
|
|
assert success is False
|
|
assert error == "Session not found"
|
|
|
|
def test_logout_missing_session_id(self, use_case):
|
|
"""测试缺少 session_id"""
|
|
request = LogoutRequest(
|
|
user_id="user-123",
|
|
session_id=None,
|
|
logout_all_devices=False,
|
|
)
|
|
|
|
success, error = use_case.execute(request)
|
|
|
|
assert success is False
|
|
assert error == "Session ID is required"
|