68e55df83b
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
71 lines
2.7 KiB
Python
Executable File
71 lines
2.7 KiB
Python
Executable File
"""VerificationCode 领域实体单测."""
|
|
|
|
from datetime import datetime, timedelta, timezone
|
|
|
|
import pytest
|
|
|
|
from packages.domain.verification_code import VerificationCode
|
|
|
|
|
|
class TestVerificationCodeCreate:
|
|
def test_create_default_ttl(self):
|
|
code = VerificationCode.create(recipient="test@example.com", code_type="email_bind")
|
|
assert code.id
|
|
assert code.recipient == "test@example.com"
|
|
assert code.code_type == "email_bind"
|
|
assert len(code.code) == 6
|
|
assert code.code.isdigit()
|
|
assert code.used_at is None
|
|
assert code.attempts == 0
|
|
# 默认5分钟过期
|
|
assert code.expires_at > code.created_at
|
|
assert (code.expires_at - code.created_at).total_seconds() == pytest.approx(300, abs=1)
|
|
|
|
def test_create_custom_ttl(self):
|
|
code = VerificationCode.create(recipient="13800138000", code_type="phone_login", ttl_seconds=60)
|
|
assert (code.expires_at - code.created_at).total_seconds() == pytest.approx(60, abs=1)
|
|
|
|
def test_create_custom_code(self):
|
|
code = VerificationCode.create(recipient="test@example.com", code_type="reset_password", custom_code="123456")
|
|
assert code.code == "123456"
|
|
|
|
def test_create_recipient_stripped(self):
|
|
code = VerificationCode.create(recipient=" test@example.com ", code_type="email_bind")
|
|
assert code.recipient == "test@example.com"
|
|
|
|
|
|
class TestVerificationCodeStatus:
|
|
def test_is_valid_initial(self):
|
|
code = VerificationCode.create(recipient="test@example.com", code_type="email_bind")
|
|
assert code.is_valid is True
|
|
assert code.is_expired is False
|
|
assert code.is_used is False
|
|
|
|
def test_mark_used(self):
|
|
code = VerificationCode.create(recipient="test@example.com", code_type="email_bind")
|
|
code.mark_used()
|
|
assert code.is_used is True
|
|
assert code.used_at is not None
|
|
assert code.is_valid is False
|
|
|
|
def test_is_expired_future(self):
|
|
code = VerificationCode.create(recipient="test@example.com", code_type="email_bind", ttl_seconds=3600)
|
|
assert code.is_expired is False
|
|
|
|
def test_increment_attempts(self):
|
|
code = VerificationCode.create(recipient="test@example.com", code_type="email_bind")
|
|
assert code.attempts == 0
|
|
code.increment_attempts()
|
|
assert code.attempts == 1
|
|
code.increment_attempts()
|
|
assert code.attempts == 2
|
|
|
|
def test_is_valid_after_expired(self):
|
|
code = VerificationCode.create(recipient="test@example.com", code_type="email_bind", ttl_seconds=0)
|
|
# 0秒TTL,立即可能过期(有极小概率因时间差没过)
|
|
import time
|
|
|
|
time.sleep(0.01)
|
|
assert code.is_expired is True
|
|
assert code.is_valid is False
|