Files
xiaoxia-saas/tests/unit/test_password_handler.py
xiaoxia 7e505a04c7
CI/CD Pipeline / Check if frontend-only change (push) Has been cancelled
CI/CD Pipeline / Validate - Code Quality (push) Has been cancelled
CI/CD Pipeline / Validate - Type Check (mypy) (push) Has been cancelled
CI/CD Pipeline / Validate - Migration (alembic) (push) Has been cancelled
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Frontend Lint (push) Has been cancelled
CI/CD Pipeline / Frontend Unit Tests (push) Has been cancelled
CI/CD Pipeline / PR Build API Image (push) Has been cancelled
CI/CD Pipeline / PR Build Web Image (push) Has been cancelled
CI/CD Pipeline / PR Build Worker Image (push) Has been cancelled
CI/CD Pipeline / Build Staging API Image (push) Has been cancelled
CI/CD Pipeline / Build Staging Web Image (push) Has been cancelled
CI/CD Pipeline / Build Staging Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (push) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (push) Has been cancelled
test: P3-1 第40波单元测试(wechat_oauth + wechat_sync) (#821)
2026-07-24 16:44:35 +08:00

176 lines
6.1 KiB
Python
Executable File
Raw Permalink 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