Files
xiaoxia-saas/tests/unit/test_password_handler.py
T
CI Bot 040237169d
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 6s
CI/CD Pipeline / Frontend Lint (pull_request) Successful in 35s
CI/CD Pipeline / Validate - Code Quality (pull_request) Failing after 1m26s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 1m3s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 1m9s
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Successful in 1m50s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 43s
Preview Deploy / Deploy Preview Environment (pull_request) Failing after 22s
AI Code Review / AI Code Review (pull_request) Successful in 2m35s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m20s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 6m4s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 14m19s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Successful in 2m21s
CI/CD Pipeline / Unit Tests (pull_request) Successful in 3m4s
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
Preview Cleanup / Cleanup Preview Environment (pull_request) Successful in 47s
test: P3-1 第36波单元测试(assets/jwt_handler/password_handler/video_share)
- test_assets_use_cases: 15个(ListAssetsUseCase + CreateAssetUseCase)
- test_jwt_handler: 18个(JWTHandler + 全局配置函数)
- test_password_handler: 22个(PasswordHandler + 全局配置函数)
- test_video_share_use_cases: 36个(8个UseCase全覆盖)
- 合计+77个测试,全量4554 passed
2026-07-24 11:31:53 +08:00

176 lines
6.1 KiB
Python
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Password Handler 单元测试."""
from __future__ import annotations
import pytest
from packages.application.auth.password_handler import (
PasswordHandler,
configure_password_handler,
get_password_handler,
)
@pytest.fixture
def password_handler():
return PasswordHandler(rounds=4) # 用低rounds加速测试
class TestPasswordHandler:
"""PasswordHandler 测试"""
def test_hash_password_returns_string(self, password_handler):
"""哈希密码返回非空字符串"""
hashed = password_handler.hash_password("MyP@ssw0rd!")
assert isinstance(hashed, str)
assert len(hashed) > 0
assert hashed != "MyP@ssw0rd!"
def test_hash_password_different_each_time(self, password_handler):
"""同一密码每次哈希结果不同(加盐)"""
h1 = password_handler.hash_password("TestPass123")
h2 = password_handler.hash_password("TestPass123")
assert h1 != h2
def test_verify_password_correct(self, password_handler):
"""正确密码验证通过"""
hashed = password_handler.hash_password("CorrectPass1!")
assert password_handler.verify_password("CorrectPass1!", hashed) is True
def test_verify_password_wrong(self, password_handler):
"""错误密码验证失败"""
hashed = password_handler.hash_password("RightPass1!")
assert password_handler.verify_password("WrongPass1!", hashed) is False
def test_verify_password_empty_string(self, password_handler):
"""空字符串密码也能正确验证(不匹配)"""
hashed = password_handler.hash_password("SomePass1!")
assert password_handler.verify_password("", hashed) is False
def test_hash_empty_password_raises(self, password_handler):
"""空密码哈希抛出 ValueError"""
with pytest.raises(ValueError):
password_handler.hash_password("")
def test_needs_rehash_with_different_rounds(self):
"""不同 rounds 的哈希需要重新计算"""
handler_low = PasswordHandler(rounds=4)
handler_high = PasswordHandler(rounds=5)
hashed = handler_low.hash_password("TestPass1!")
assert handler_low.needs_rehash(hashed) is False
assert handler_high.needs_rehash(hashed) is True
def test_validate_strength_strong_password(self, password_handler):
"""强密码通过强度验证"""
valid, error = password_handler.validate_strength("Str0ngP@ss!")
assert valid is True
assert error is None
def test_validate_strength_too_short(self, password_handler):
"""密码太短不通过"""
valid, error = password_handler.validate_strength("Sh0rt!")
assert valid is False
assert error is not None
assert "长度" in error or "length" in error.lower() or "8" in error
def test_validate_strength_no_uppercase(self, password_handler):
"""没有大写字母不通过"""
valid, error = password_handler.validate_strength("lowercase1!")
assert valid is False
assert error is not None
def test_validate_strength_no_lowercase(self, password_handler):
"""没有小写字母不通过"""
valid, error = password_handler.validate_strength("UPPERCASE1!")
assert valid is False
assert error is not None
def test_validate_strength_no_digit(self, password_handler):
"""没有数字不通过"""
valid, error = password_handler.validate_strength("NoDigitPass!")
assert valid is False
assert error is not None
def test_validate_strength_special_not_required(self, password_handler):
"""默认不要求特殊字符"""
valid, error = password_handler.validate_strength("NoSpecial1")
# 没有特殊字符也应该通过(require_special=False
assert valid is True
assert error is None
def test_validate_strength_empty_string(self, password_handler):
"""空字符串验证失败"""
valid, error = password_handler.validate_strength("")
assert valid is False
assert error is not None
def test_hash_and_verify_roundtrip(self, password_handler):
"""哈希-验证完整往返"""
passwords = [
"Simple12",
"C0mpl3x!Pass",
"12345678aA",
"user@example.com1",
]
for pwd in passwords:
hashed = password_handler.hash_password(pwd)
assert password_handler.verify_password(pwd, hashed)
assert not password_handler.verify_password(pwd + "x", hashed)
class TestGlobalPasswordHandler:
"""全局密码处理器配置测试"""
def test_get_password_handler_default(self):
"""未配置时 get_password_handler 返回默认实例"""
import packages.application.auth.password_handler as pw_module
pw_module._default_handler = None
handler = get_password_handler()
assert isinstance(handler, PasswordHandler)
def test_configure_creates_handler(self):
"""configure_password_handler 创建并返回 handler"""
import packages.application.auth.password_handler as pw_module
pw_module._default_handler = None
handler = configure_password_handler(rounds=4)
assert isinstance(handler, PasswordHandler)
assert get_password_handler() is handler
def test_configure_overwrites_existing(self):
"""重新配置会覆盖之前的 handler"""
import packages.application.auth.password_handler as pw_module
pw_module._default_handler = None
handler1 = configure_password_handler(rounds=4)
handler2 = configure_password_handler(rounds=5)
assert handler1 is not handler2
assert get_password_handler() is handler2
def test_get_password_handler_lazy_init(self):
"""未配置时首次调用 get_password_handler 会懒初始化"""
import packages.application.auth.password_handler as pw_module
pw_module._default_handler = None
assert pw_module._default_handler is None
handler = get_password_handler()
assert pw_module._default_handler is not None
assert pw_module._default_handler is handler