e1fd5243bb
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 31s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 1m27s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 1m36s
CI/CD Pipeline / Validate - Code Quality (pull_request) Failing after 1m58s
CI/CD Pipeline / Frontend Lint (pull_request) Successful in 42s
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 / PR Build Web Image (pull_request) Successful in 42s
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 39s
Preview Deploy / Deploy Preview Environment (pull_request) Failing after 18s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m24s
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 / PR Build API Image (pull_request) Successful in 6m9s
AI Code Review / AI Code Review (pull_request) Successful in 7m0s
CI/CD Pipeline / Unit Tests (pull_request) Successful in 5m9s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 12m46s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 3m41s
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 5s
新增4个领域模块单测: - test_tag.py: Tag领域实体(4个) - test_verification_code.py: VerificationCode验证码实体(10个) - test_subtitle.py: 字幕时间轴模型(28个)- 合并/拆分/标点断句 - test_voice_presets.py: 音色预设查询(17个) 合计 +59 个测试用例,全部通过。
70 lines
2.7 KiB
Python
Executable File
70 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
|