- Implemented unit tests for Object model including folder and file creation, properties, and path retrieval. - Added unit tests for Setting model covering creation, unique constraints, and type enumeration. - Created unit tests for User model focusing on user creation, uniqueness, and group relationships. - Developed unit tests for Login service to validate login functionality, including 2FA and token generation. - Added utility tests for JWT creation and verification, ensuring token integrity and expiration handling. - Implemented password utility tests for password generation, hashing, and TOTP verification.
139 lines
3.7 KiB
Python
139 lines
3.7 KiB
Python
"""
|
||
Password 工具类的单元测试
|
||
"""
|
||
import pytest
|
||
|
||
from utils.password.pwd import Password, PasswordStatus
|
||
|
||
|
||
def test_password_generate_default_length():
|
||
"""测试默认长度生成密码"""
|
||
password = Password.generate()
|
||
|
||
# 默认长度为 8,token_hex 生成的是16进制字符串,长度是原始长度的2倍
|
||
assert len(password) == 16
|
||
assert isinstance(password, str)
|
||
|
||
|
||
def test_password_generate_custom_length():
|
||
"""测试自定义长度生成密码"""
|
||
length = 12
|
||
password = Password.generate(length=length)
|
||
|
||
assert len(password) == length * 2
|
||
assert isinstance(password, str)
|
||
|
||
|
||
def test_password_hash():
|
||
"""测试密码哈希"""
|
||
plain_password = "my_secure_password_123"
|
||
hashed = Password.hash(plain_password)
|
||
|
||
assert hashed != plain_password
|
||
assert isinstance(hashed, str)
|
||
# Argon2 哈希以 $argon2 开头
|
||
assert hashed.startswith("$argon2")
|
||
|
||
|
||
def test_password_verify_valid():
|
||
"""测试正确密码验证"""
|
||
plain_password = "correct_password"
|
||
hashed = Password.hash(plain_password)
|
||
|
||
status = Password.verify(hashed, plain_password)
|
||
|
||
assert status == PasswordStatus.VALID
|
||
|
||
|
||
def test_password_verify_invalid():
|
||
"""测试错误密码验证"""
|
||
plain_password = "correct_password"
|
||
wrong_password = "wrong_password"
|
||
hashed = Password.hash(plain_password)
|
||
|
||
status = Password.verify(hashed, wrong_password)
|
||
|
||
assert status == PasswordStatus.INVALID
|
||
|
||
|
||
def test_password_verify_expired():
|
||
"""测试密码哈希过期检测"""
|
||
# 注意: 实际检测需要修改 Argon2 参数,这里只是测试接口
|
||
# 在真实场景中,当哈希参数过时时会返回 EXPIRED
|
||
plain_password = "password"
|
||
hashed = Password.hash(plain_password)
|
||
|
||
status = Password.verify(hashed, plain_password)
|
||
|
||
# 新生成的哈希应该是 VALID
|
||
assert status in [PasswordStatus.VALID, PasswordStatus.EXPIRED]
|
||
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_totp_generate():
|
||
"""测试 TOTP 密钥生成"""
|
||
username = "testuser"
|
||
|
||
response = await Password.generate_totp(username)
|
||
|
||
assert response.setup_token is not None
|
||
assert response.uri is not None
|
||
assert isinstance(response.setup_token, str)
|
||
assert isinstance(response.uri, str)
|
||
# TOTP URI 格式: otpauth://totp/...
|
||
assert response.uri.startswith("otpauth://totp/")
|
||
assert username in response.uri
|
||
|
||
|
||
def test_totp_verify_valid():
|
||
"""测试 TOTP 验证正确"""
|
||
import pyotp
|
||
|
||
# 生成密钥
|
||
secret = pyotp.random_base32()
|
||
|
||
# 生成当前有效的验证码
|
||
totp = pyotp.TOTP(secret)
|
||
valid_code = totp.now()
|
||
|
||
# 验证
|
||
status = Password.verify_totp(secret, valid_code)
|
||
|
||
assert status == PasswordStatus.VALID
|
||
|
||
|
||
def test_totp_verify_invalid():
|
||
"""测试 TOTP 验证错误"""
|
||
import pyotp
|
||
|
||
secret = pyotp.random_base32()
|
||
invalid_code = "000000" # 几乎不可能是当前有效码
|
||
|
||
status = Password.verify_totp(secret, invalid_code)
|
||
|
||
# 注意: 极小概率 000000 恰好是有效码,但实际测试中基本不会发生
|
||
assert status == PasswordStatus.INVALID
|
||
|
||
|
||
def test_password_hash_consistency():
|
||
"""测试相同密码多次哈希结果不同(盐随机)"""
|
||
password = "test_password"
|
||
|
||
hash1 = Password.hash(password)
|
||
hash2 = Password.hash(password)
|
||
|
||
# 由于盐是随机的,两次哈希结果应该不同
|
||
assert hash1 != hash2
|
||
|
||
# 但都应该能通过验证
|
||
assert Password.verify(hash1, password) == PasswordStatus.VALID
|
||
assert Password.verify(hash2, password) == PasswordStatus.VALID
|
||
|
||
|
||
def test_password_generate_uniqueness():
|
||
"""测试生成的密码唯一性"""
|
||
passwords = [Password.generate() for _ in range(100)]
|
||
|
||
# 100个密码应该都不相同
|
||
assert len(set(passwords)) == 100
|