c539095a33
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 1m51s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 2m1s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 3m39s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 5m46s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 7m0s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 7m30s
CI/CD Pipeline / Integration Tests (push) Successful in 2m15s
CI/CD Pipeline / Unit Tests (push) Failing after 11m20s
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 / CI Gate (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 API Image (push) Successful in 23m0s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m0s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 41s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 2m13s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 2m57s
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
143 lines
5.3 KiB
Python
143 lines
5.3 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""测试 Step6 封面生成 400 修复:
|
|
1. Worker 渲染完成后提取封面帧写入 cover_url
|
|
2. API 创建预览任务时自动关联 source_edit_plan_id
|
|
"""
|
|
|
|
import pytest
|
|
|
|
from packages.application.generation_tasks import CreateGenerationTaskCommand
|
|
from packages.domain.generation_task import GenerationTask, GenerationTaskStatus
|
|
|
|
|
|
def _make_task(**kwargs):
|
|
return GenerationTask(
|
|
id=kwargs.get("id", "task-001"),
|
|
project_id=kwargs.get("project_id", ""),
|
|
asset_library_id=kwargs.get("asset_library_id", ""),
|
|
template_id=kwargs.get("template_id", "tpl-001"),
|
|
created_by_user_id=kwargs.get("user_id", "user-001"),
|
|
asset_ids=kwargs.get("asset_ids", ["asset-1"]),
|
|
status=kwargs.get("status", GenerationTaskStatus.RUNNING),
|
|
source_edit_plan_id=kwargs.get("source_edit_plan_id", ""),
|
|
cover_url=kwargs.get("cover_url", ""),
|
|
is_preview=kwargs.get("is_preview", True),
|
|
)
|
|
|
|
|
|
class TestWorkerCoverFrameExtraction:
|
|
"""Worker 端:渲染完成后提取封面帧写入 cover_url"""
|
|
|
|
def test_cover_url_set_after_frame_extraction(self):
|
|
"""extract_frames 返回结果时,cover_url 应被设置"""
|
|
task = _make_task()
|
|
assert task.cover_url == ""
|
|
mock_frame_url = "https://oss.example.com/frames/frame_001.jpg"
|
|
task.cover_url = mock_frame_url
|
|
assert task.cover_url == mock_frame_url
|
|
|
|
def test_cover_url_empty_when_no_frames(self):
|
|
"""extract_frames 返回空时,cover_url 应保持为空"""
|
|
task = _make_task()
|
|
assert task.cover_url == ""
|
|
|
|
def test_cover_url_preserved_on_extraction_failure(self):
|
|
"""extract_frames 异常时,cover_url 保持原值"""
|
|
task = _make_task(cover_url="")
|
|
try:
|
|
raise RuntimeError("MediaKit timeout")
|
|
except RuntimeError:
|
|
pass
|
|
assert task.cover_url == ""
|
|
|
|
def test_cover_url_first_frame_used(self):
|
|
"""多帧结果应使用第一帧"""
|
|
frames = [
|
|
{"image_url": "https://oss.example.com/frame_001.jpg", "timestamp": 0.0},
|
|
{"image_url": "https://oss.example.com/frame_002.jpg", "timestamp": 1.5},
|
|
]
|
|
task = _make_task()
|
|
task.cover_url = frames[0]["image_url"]
|
|
assert task.cover_url == "https://oss.example.com/frame_001.jpg"
|
|
|
|
def test_cover_url_not_set_when_empty_image_url(self):
|
|
"""帧的 image_url 为空时不应设置 cover_url"""
|
|
frames = [{"image_url": "", "timestamp": 0.0}]
|
|
task = _make_task()
|
|
frame_url = frames[0].get("image_url", "")
|
|
if frame_url:
|
|
task.cover_url = frame_url
|
|
assert task.cover_url == ""
|
|
|
|
|
|
class TestPreviewSourceEditPlanId:
|
|
"""API 端:预览任务自动关联 source_edit_plan_id"""
|
|
|
|
def test_source_edit_plan_id_set_when_provided(self):
|
|
"""前端传入 source_edit_plan_id 时应直接使用"""
|
|
cmd = CreateGenerationTaskCommand(
|
|
project_id="",
|
|
asset_library_id="",
|
|
strategy_id="one-take",
|
|
template_id="tpl-001",
|
|
asset_ids=["asset-1"],
|
|
created_by_user_id="user-001",
|
|
source_edit_plan_id="plan-xyz",
|
|
)
|
|
assert cmd.source_edit_plan_id == "plan-xyz"
|
|
|
|
def test_source_edit_plan_id_empty_when_not_provided(self):
|
|
"""前端未传入时 source_edit_plan_id 默认为空"""
|
|
cmd = CreateGenerationTaskCommand(
|
|
project_id="",
|
|
asset_library_id="",
|
|
strategy_id="one-take",
|
|
template_id="tpl-001",
|
|
asset_ids=["asset-1"],
|
|
created_by_user_id="user-001",
|
|
)
|
|
assert cmd.source_edit_plan_id == ""
|
|
|
|
def test_task_preserves_source_edit_plan_id(self):
|
|
"""GenerationTask 应保持 source_edit_plan_id"""
|
|
task = _make_task(source_edit_plan_id="plan-abc")
|
|
assert task.source_edit_plan_id == "plan-abc"
|
|
|
|
|
|
class TestCoverRouteStepB:
|
|
"""封面路由步骤 B:通过 source_edit_plan_id 查找"""
|
|
|
|
def test_step_b_finds_preview_task_by_source_plan(self):
|
|
"""步骤 B 应找到 source_edit_plan_id 匹配的已完成预览任务"""
|
|
task = _make_task(
|
|
source_edit_plan_id="plan-abc",
|
|
cover_url="https://oss.example.com/cover.jpg",
|
|
status=GenerationTaskStatus.COMPLETED,
|
|
)
|
|
is_valid = (
|
|
task.source_edit_plan_id == "plan-abc"
|
|
and task.status == GenerationTaskStatus.COMPLETED
|
|
and bool(task.cover_url)
|
|
)
|
|
assert is_valid is True
|
|
|
|
def test_step_b_skips_non_completed_tasks(self):
|
|
"""步骤 B 应跳过非 completed 状态的任务"""
|
|
task = _make_task(
|
|
source_edit_plan_id="plan-abc",
|
|
cover_url="https://oss.example.com/cover.jpg",
|
|
status=GenerationTaskStatus.FAILED,
|
|
)
|
|
is_valid = task.status == GenerationTaskStatus.COMPLETED and bool(task.cover_url)
|
|
assert is_valid is False
|
|
|
|
def test_step_b_skips_tasks_without_cover_url(self):
|
|
"""步骤 B 应跳过没有 cover_url 的任务"""
|
|
task = _make_task(
|
|
source_edit_plan_id="plan-abc",
|
|
cover_url="",
|
|
status=GenerationTaskStatus.COMPLETED,
|
|
)
|
|
is_valid = task.status == GenerationTaskStatus.COMPLETED and bool(task.cover_url)
|
|
assert is_valid is False
|