d66046aa4b
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Build Staging Web Image (push) Successful in 57s
CI/CD Pipeline / Build Staging API Image (push) Successful in 1m30s
CI/CD Pipeline / Frontend Lint (push) Successful in 1m41s
CI/CD Pipeline / Validate Code Quality And Tests (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 Unit Tests (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 / ACR Image Cleanup (push) Has been cancelled
Co-authored-by: xiaoxia <dev@xiaoxiajianji.com> Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
238 lines
8.5 KiB
Python
Executable File
238 lines
8.5 KiB
Python
Executable File
"""剪辑计划领域模型单元测试."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from datetime import datetime, timezone
|
|
|
|
import pytest
|
|
|
|
from packages.domain.edit_plan import EditPlan, EditPlanStatus
|
|
|
|
|
|
class TestEditPlanStatus:
|
|
"""EditPlanStatus 枚举测试."""
|
|
|
|
def test_status_values(self):
|
|
assert EditPlanStatus.DRAFT.value == "draft"
|
|
assert EditPlanStatus.EDITING.value == "editing"
|
|
assert EditPlanStatus.RENDERING.value == "rendering"
|
|
assert EditPlanStatus.COMPLETED.value == "completed"
|
|
assert EditPlanStatus.FAILED.value == "failed"
|
|
|
|
def test_status_is_str(self):
|
|
assert isinstance(EditPlanStatus.DRAFT, str)
|
|
assert EditPlanStatus.DRAFT == "draft"
|
|
|
|
|
|
class TestEditPlanCreate:
|
|
"""创建剪辑计划测试."""
|
|
|
|
def test_create_basic(self):
|
|
plan = EditPlan.create(template_id="tpl_001", name="测试计划")
|
|
assert plan.id
|
|
assert len(plan.id) == 32 # uuid4 hex
|
|
assert plan.template_id == "tpl_001"
|
|
assert plan.name == "测试计划"
|
|
assert plan.status == EditPlanStatus.DRAFT
|
|
assert plan.total_duration == 0.0
|
|
assert plan.config == {}
|
|
assert plan.source_edit_plan_id == ""
|
|
assert plan.project_id == ""
|
|
assert plan.created_by_user_id == ""
|
|
|
|
def test_create_with_all_fields(self):
|
|
plan = EditPlan.create(
|
|
template_id="tpl_001",
|
|
name="完整测试计划",
|
|
config={"key": "value"},
|
|
total_duration=60.5,
|
|
source_edit_plan_id="src_001",
|
|
project_id="proj_001",
|
|
created_by_user_id="user_001",
|
|
)
|
|
assert plan.name == "完整测试计划"
|
|
assert plan.total_duration == 60.5
|
|
assert plan.config == {"key": "value"}
|
|
assert plan.source_edit_plan_id == "src_001"
|
|
assert plan.project_id == "proj_001"
|
|
assert plan.created_by_user_id == "user_001"
|
|
|
|
def test_create_empty_name_raises(self):
|
|
with pytest.raises(ValueError, match="名称不能为空"):
|
|
EditPlan.create(template_id="tpl_001", name="")
|
|
|
|
def test_create_whitespace_name_raises(self):
|
|
with pytest.raises(ValueError, match="名称不能为空"):
|
|
EditPlan.create(template_id="tpl_001", name=" ")
|
|
|
|
def test_create_empty_template_id_raises(self):
|
|
with pytest.raises(ValueError, match="template_id 不能为空"):
|
|
EditPlan.create(template_id="", name="测试")
|
|
|
|
def test_create_whitespace_template_id_raises(self):
|
|
with pytest.raises(ValueError, match="template_id 不能为空"):
|
|
EditPlan.create(template_id=" ", name="测试")
|
|
|
|
def test_create_name_stripped(self):
|
|
plan = EditPlan.create(template_id="tpl_001", name=" 我的计划 ")
|
|
assert plan.name == "我的计划"
|
|
|
|
def test_create_template_id_stripped(self):
|
|
plan = EditPlan.create(template_id=" tpl_001 ", name="测试")
|
|
assert plan.template_id == "tpl_001"
|
|
|
|
def test_create_timestamps_set(self):
|
|
before = datetime.now(timezone.utc)
|
|
plan = EditPlan.create(template_id="tpl_001", name="测试")
|
|
after = datetime.now(timezone.utc)
|
|
assert before <= plan.created_at <= after
|
|
assert before <= plan.updated_at <= after
|
|
|
|
def test_create_config_none_defaults_to_empty(self):
|
|
plan = EditPlan.create(template_id="tpl_001", name="测试", config=None)
|
|
assert plan.config == {}
|
|
|
|
|
|
class TestEditPlanStateMachine:
|
|
"""状态机流转测试."""
|
|
|
|
def _make_plan(self, status: EditPlanStatus) -> EditPlan:
|
|
return EditPlan(
|
|
id="test_id",
|
|
template_id="tpl_001",
|
|
name="测试计划",
|
|
status=status,
|
|
)
|
|
|
|
def test_draft_to_editing(self):
|
|
plan = self._make_plan(EditPlanStatus.DRAFT)
|
|
plan.start_editing()
|
|
assert plan.status == EditPlanStatus.EDITING
|
|
assert plan.updated_at > plan.created_at
|
|
|
|
def test_editing_to_rendering(self):
|
|
plan = self._make_plan(EditPlanStatus.EDITING)
|
|
plan.start_rendering()
|
|
assert plan.status == EditPlanStatus.RENDERING
|
|
|
|
def test_rendering_to_completed(self):
|
|
plan = self._make_plan(EditPlanStatus.RENDERING)
|
|
plan.mark_completed()
|
|
assert plan.status == EditPlanStatus.COMPLETED
|
|
|
|
def test_rendering_to_failed(self):
|
|
plan = self._make_plan(EditPlanStatus.RENDERING)
|
|
plan.mark_failed()
|
|
assert plan.status == EditPlanStatus.FAILED
|
|
|
|
def test_completed_to_editing_resume(self):
|
|
plan = self._make_plan(EditPlanStatus.COMPLETED)
|
|
plan.resume_editing()
|
|
assert plan.status == EditPlanStatus.EDITING
|
|
|
|
def test_failed_to_editing_resume(self):
|
|
plan = self._make_plan(EditPlanStatus.FAILED)
|
|
plan.resume_editing()
|
|
assert plan.status == EditPlanStatus.EDITING
|
|
|
|
def test_failed_to_draft_reset(self):
|
|
plan = self._make_plan(EditPlanStatus.FAILED)
|
|
plan.reset_to_draft()
|
|
assert plan.status == EditPlanStatus.DRAFT
|
|
|
|
def test_invalid_start_editing_from_editing(self):
|
|
plan = self._make_plan(EditPlanStatus.EDITING)
|
|
with pytest.raises(ValueError, match="只有 draft 状态"):
|
|
plan.start_editing()
|
|
|
|
def test_invalid_start_editing_from_rendering(self):
|
|
plan = self._make_plan(EditPlanStatus.RENDERING)
|
|
with pytest.raises(ValueError):
|
|
plan.start_editing()
|
|
|
|
def test_invalid_start_rendering_from_draft(self):
|
|
plan = self._make_plan(EditPlanStatus.DRAFT)
|
|
with pytest.raises(ValueError, match="只有 editing 状态"):
|
|
plan.start_rendering()
|
|
|
|
def test_invalid_start_rendering_from_completed(self):
|
|
plan = self._make_plan(EditPlanStatus.COMPLETED)
|
|
with pytest.raises(ValueError):
|
|
plan.start_rendering()
|
|
|
|
def test_invalid_mark_completed_from_draft(self):
|
|
plan = self._make_plan(EditPlanStatus.DRAFT)
|
|
with pytest.raises(ValueError, match="只有 rendering 状态"):
|
|
plan.mark_completed()
|
|
|
|
def test_invalid_mark_failed_from_editing(self):
|
|
plan = self._make_plan(EditPlanStatus.EDITING)
|
|
with pytest.raises(ValueError):
|
|
plan.mark_failed()
|
|
|
|
def test_invalid_resume_editing_from_draft(self):
|
|
plan = self._make_plan(EditPlanStatus.DRAFT)
|
|
with pytest.raises(ValueError, match="只有 completed/failed 状态"):
|
|
plan.resume_editing()
|
|
|
|
def test_invalid_resume_editing_from_rendering(self):
|
|
plan = self._make_plan(EditPlanStatus.RENDERING)
|
|
with pytest.raises(ValueError):
|
|
plan.resume_editing()
|
|
|
|
def test_invalid_reset_to_draft_from_draft(self):
|
|
plan = self._make_plan(EditPlanStatus.DRAFT)
|
|
with pytest.raises(ValueError, match="只有 failed 状态"):
|
|
plan.reset_to_draft()
|
|
|
|
def test_invalid_reset_to_draft_from_completed(self):
|
|
plan = self._make_plan(EditPlanStatus.COMPLETED)
|
|
with pytest.raises(ValueError):
|
|
plan.reset_to_draft()
|
|
|
|
def test_state_transition_updates_updated_at(self):
|
|
plan = self._make_plan(EditPlanStatus.DRAFT)
|
|
old_updated = plan.updated_at
|
|
plan.start_editing()
|
|
assert plan.updated_at >= old_updated
|
|
|
|
|
|
class TestEditPlanDataclass:
|
|
"""数据类属性测试."""
|
|
|
|
def test_slots_prevents_dynamic_attributes(self):
|
|
plan = EditPlan(id="1", template_id="t1", name="test")
|
|
with pytest.raises(AttributeError):
|
|
plan.new_field = "value"
|
|
|
|
def test_full_flow_draft_editing_rendering_completed(self):
|
|
"""完整流程:草稿 → 编辑 → 渲染 → 完成."""
|
|
plan = EditPlan.create(template_id="tpl_001", name="完整流程")
|
|
assert plan.status == EditPlanStatus.DRAFT
|
|
|
|
plan.start_editing()
|
|
assert plan.status == EditPlanStatus.EDITING
|
|
|
|
plan.start_rendering()
|
|
assert plan.status == EditPlanStatus.RENDERING
|
|
|
|
plan.mark_completed()
|
|
assert plan.status == EditPlanStatus.COMPLETED
|
|
|
|
def test_full_flow_draft_editing_rendering_failed_reset(self):
|
|
"""完整流程:草稿 → 编辑 → 渲染 → 失败 → 重置 → 编辑 → 渲染 → 完成."""
|
|
plan = EditPlan.create(template_id="tpl_001", name="失败重试流程")
|
|
|
|
plan.start_editing()
|
|
plan.start_rendering()
|
|
plan.mark_failed()
|
|
assert plan.status == EditPlanStatus.FAILED
|
|
|
|
plan.reset_to_draft()
|
|
assert plan.status == EditPlanStatus.DRAFT
|
|
|
|
plan.start_editing()
|
|
plan.start_rendering()
|
|
plan.mark_completed()
|
|
assert plan.status == EditPlanStatus.COMPLETED
|