test: 补充 _resolve_strategy_id_from_template 单元测试
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 41s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 48s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 1m5s
AI Code Review / AI Code Review (pull_request) Successful in 1m14s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 1m26s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 1m44s
CI/CD Pipeline / Validate - Code Quality (pull_request) Failing after 1m47s
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / PR Build API Image (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
PR Automation / Auto Approve on CI Green (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Web Image (pull_request) Failing after 1032h52m50s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Failing after 1032h52m51s
CI/CD Pipeline / Staging E2E Tests (pull_request) Failing after 1032h53m31s
CI/CD Pipeline / Frontend Lint (pull_request) Failing after 1032h52m52s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Failing after 1032h53m33s
CI/CD Pipeline / Build Staging API Image (pull_request) Failing after 1032h53m35s
CI/CD Pipeline / ACR Image Cleanup (pull_request) Failing after 1032h53m30s
CI/CD Pipeline / Build Staging Worker Image (pull_request) Failing after 1032h53m34s
CI/CD Pipeline / Staging API Integration Tests (pull_request) Failing after 1033h26m47s
CI/CD Pipeline / Build Staging Web Image (pull_request) Failing after 1033h26m51s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 41s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 48s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 1m5s
AI Code Review / AI Code Review (pull_request) Successful in 1m14s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 1m26s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 1m44s
CI/CD Pipeline / Validate - Code Quality (pull_request) Failing after 1m47s
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / PR Build API Image (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
PR Automation / Auto Approve on CI Green (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Web Image (pull_request) Failing after 1032h52m50s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Failing after 1032h52m51s
CI/CD Pipeline / Staging E2E Tests (pull_request) Failing after 1032h53m31s
CI/CD Pipeline / Frontend Lint (pull_request) Failing after 1032h52m52s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Failing after 1032h53m33s
CI/CD Pipeline / Build Staging API Image (pull_request) Failing after 1032h53m35s
CI/CD Pipeline / ACR Image Cleanup (pull_request) Failing after 1032h53m30s
CI/CD Pipeline / Build Staging Worker Image (pull_request) Failing after 1032h53m34s
CI/CD Pipeline / Staging API Integration Tests (pull_request) Failing after 1033h26m47s
CI/CD Pipeline / Build Staging Web Image (pull_request) Failing after 1033h26m51s
- 新增 TestResolveStrategyIdFromTemplate (8个用例) - 新增 TestPreviewRoutePassesStrategyId (2个用例) - 修复已有 test_auto_infer_pip_resolution 适配新 import
This commit is contained in:
@@ -1264,8 +1264,182 @@ class TestPreviewRouteAutoInfersVideoRatio:
|
||||
bgm_config={},
|
||||
)
|
||||
|
||||
with patch("app.api.routes.generation_preview.SQLAlchemyTemplateRepository") as MockRepo:
|
||||
MockRepo.return_value.get.return_value = mock_template
|
||||
with patch("app.api.routes.generation_preview.SQLAlchemyEditTemplateRepository") as MockNewRepo:
|
||||
MockNewRepo.return_value.get.return_value = None # 新模板系统无数据,fallback 旧系统
|
||||
with patch("app.api.routes.generation_preview.SQLAlchemyTemplateRepository") as MockRepo:
|
||||
MockRepo.return_value.get.return_value = mock_template
|
||||
with patch("app.api.routes.generation_preview.CreateGenerationTaskUseCase") as MockUC:
|
||||
MockUC.return_value.execute.return_value = task
|
||||
with patch(
|
||||
"app.api.routes.generation_preview.safe_enqueue_generation_task",
|
||||
return_value=True,
|
||||
):
|
||||
resp = create_preview_generation_task(
|
||||
request,
|
||||
authenticated_user=_make_user(),
|
||||
generation_task_repository=repo,
|
||||
db=mock_db,
|
||||
)
|
||||
|
||||
# Verify the resolution passed to CreateGenerationTaskCommand
|
||||
call_args = MockUC.return_value.execute.call_args
|
||||
cmd = call_args[0][0]
|
||||
assert cmd.resolution == "480x854", f"Expected 480x854, got {cmd.resolution}"
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
# _resolve_strategy_id_from_template 单元测试
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
|
||||
class TestResolveStrategyIdFromTemplate:
|
||||
"""_resolve_strategy_id_from_template 单元测试:预览生成从模板读取 editing_mode。"""
|
||||
|
||||
def test_new_template_found_returns_editing_mode(self):
|
||||
"""新模板系统找到模板 → 返回 editing_mode。"""
|
||||
from app.api.routes.generation_preview import _resolve_strategy_id_from_template
|
||||
|
||||
mock_new_template = MagicMock()
|
||||
mock_new_template.editing_mode = "pip"
|
||||
mock_db = MagicMock()
|
||||
|
||||
with patch("app.api.routes.generation_preview.SQLAlchemyEditTemplateRepository") as MockNewRepo:
|
||||
MockNewRepo.return_value.get.return_value = mock_new_template
|
||||
result = _resolve_strategy_id_from_template("tpl_001", mock_db, "user_1")
|
||||
|
||||
assert result == "pip"
|
||||
|
||||
def test_new_template_not_found_fallback_to_old(self):
|
||||
"""新模板系统未找到 → fallback 旧模板系统返回 mode。"""
|
||||
from app.api.routes.generation_preview import _resolve_strategy_id_from_template
|
||||
|
||||
mock_old_template = MagicMock()
|
||||
mock_old_template.mode = "standard"
|
||||
mock_db = MagicMock()
|
||||
|
||||
with patch("app.api.routes.generation_preview.SQLAlchemyEditTemplateRepository") as MockNewRepo:
|
||||
MockNewRepo.return_value.get.return_value = None
|
||||
with patch("app.api.routes.generation_preview.SQLAlchemyTemplateRepository") as MockOldRepo:
|
||||
MockOldRepo.return_value.get.return_value = mock_old_template
|
||||
result = _resolve_strategy_id_from_template("tpl_001", mock_db, "user_1")
|
||||
|
||||
assert result == "standard"
|
||||
|
||||
def test_both_not_found_returns_empty(self):
|
||||
"""新旧模板系统都未找到 → 返回空字符串。"""
|
||||
from app.api.routes.generation_preview import _resolve_strategy_id_from_template
|
||||
|
||||
mock_db = MagicMock()
|
||||
|
||||
with patch("app.api.routes.generation_preview.SQLAlchemyEditTemplateRepository") as MockNewRepo:
|
||||
MockNewRepo.return_value.get.return_value = None
|
||||
with patch("app.api.routes.generation_preview.SQLAlchemyTemplateRepository") as MockOldRepo:
|
||||
MockOldRepo.return_value.get.return_value = None
|
||||
result = _resolve_strategy_id_from_template("tpl_nonexistent", mock_db, "user_1")
|
||||
|
||||
assert result == ""
|
||||
|
||||
def test_empty_template_id_returns_empty(self):
|
||||
"""空 template_id → 直接返回空字符串。"""
|
||||
from app.api.routes.generation_preview import _resolve_strategy_id_from_template
|
||||
|
||||
mock_db = MagicMock()
|
||||
result = _resolve_strategy_id_from_template("", mock_db, "user_1")
|
||||
assert result == ""
|
||||
|
||||
def test_new_template_exception_fallback_to_old(self):
|
||||
"""新模板系统异常 → 降级到旧模板系统。"""
|
||||
from app.api.routes.generation_preview import _resolve_strategy_id_from_template
|
||||
|
||||
mock_old_template = MagicMock()
|
||||
mock_old_template.mode = "voice_over"
|
||||
mock_db = MagicMock()
|
||||
|
||||
with patch("app.api.routes.generation_preview.SQLAlchemyEditTemplateRepository") as MockNewRepo:
|
||||
MockNewRepo.side_effect = RuntimeError("db error")
|
||||
with patch("app.api.routes.generation_preview.SQLAlchemyTemplateRepository") as MockOldRepo:
|
||||
MockOldRepo.return_value.get.return_value = mock_old_template
|
||||
result = _resolve_strategy_id_from_template("tpl_001", mock_db, "user_1")
|
||||
|
||||
assert result == "voice_over"
|
||||
|
||||
def test_both_exception_returns_empty(self):
|
||||
"""新旧模板系统都异常 → 返回空字符串。"""
|
||||
from app.api.routes.generation_preview import _resolve_strategy_id_from_template
|
||||
|
||||
mock_db = MagicMock()
|
||||
|
||||
with patch("app.api.routes.generation_preview.SQLAlchemyEditTemplateRepository") as MockNewRepo:
|
||||
MockNewRepo.side_effect = RuntimeError("new db error")
|
||||
with patch("app.api.routes.generation_preview.SQLAlchemyTemplateRepository") as MockOldRepo:
|
||||
MockOldRepo.side_effect = RuntimeError("old db error")
|
||||
result = _resolve_strategy_id_from_template("tpl_001", mock_db, "user_1")
|
||||
|
||||
assert result == ""
|
||||
|
||||
def test_new_template_empty_editing_mode_fallback(self):
|
||||
"""新模板找到但 editing_mode 为空 → fallback 旧模板。"""
|
||||
from app.api.routes.generation_preview import _resolve_strategy_id_from_template
|
||||
|
||||
mock_new_template = MagicMock()
|
||||
mock_new_template.editing_mode = ""
|
||||
mock_old_template = MagicMock()
|
||||
mock_old_template.mode = "one_take"
|
||||
mock_db = MagicMock()
|
||||
|
||||
with patch("app.api.routes.generation_preview.SQLAlchemyEditTemplateRepository") as MockNewRepo:
|
||||
MockNewRepo.return_value.get.return_value = mock_new_template
|
||||
with patch("app.api.routes.generation_preview.SQLAlchemyTemplateRepository") as MockOldRepo:
|
||||
MockOldRepo.return_value.get.return_value = mock_old_template
|
||||
result = _resolve_strategy_id_from_template("tpl_001", mock_db, "user_1")
|
||||
|
||||
assert result == "one_take"
|
||||
|
||||
def test_voice_pip_mode(self):
|
||||
"""模板 editing_mode=voice_pip → 返回 'voice_pip'。"""
|
||||
from app.api.routes.generation_preview import _resolve_strategy_id_from_template
|
||||
|
||||
mock_new_template = MagicMock()
|
||||
mock_new_template.editing_mode = "voice_pip"
|
||||
mock_db = MagicMock()
|
||||
|
||||
with patch("app.api.routes.generation_preview.SQLAlchemyEditTemplateRepository") as MockNewRepo:
|
||||
MockNewRepo.return_value.get.return_value = mock_new_template
|
||||
result = _resolve_strategy_id_from_template("tpl_voice", mock_db, "user_1")
|
||||
|
||||
assert result == "voice_pip"
|
||||
|
||||
|
||||
class TestPreviewRoutePassesStrategyId:
|
||||
"""验证预览路由正确传递 strategy_id 到 CreateGenerationTaskCommand。"""
|
||||
|
||||
def test_strategy_id_from_new_template(self):
|
||||
"""预览路由从新模板读取 strategy_id=pip。"""
|
||||
from app.api.routes.generation_preview import create_preview_generation_task
|
||||
from app.schemas.generation_task import CreatePreviewGenerationTaskRequest
|
||||
|
||||
repo = MagicMock()
|
||||
repo.count_pending_by_user.return_value = 0
|
||||
repo.count_pending_total.return_value = 0
|
||||
mock_db = MagicMock()
|
||||
|
||||
mock_new_template = MagicMock()
|
||||
mock_new_template.editing_mode = "pip"
|
||||
|
||||
task = _make_task()
|
||||
|
||||
request = CreatePreviewGenerationTaskRequest(
|
||||
template_id="tpl_pip",
|
||||
asset_ids=["a1"],
|
||||
title_ids=[],
|
||||
voice_ids=[],
|
||||
video_title="test",
|
||||
duration=0.0,
|
||||
video_ratio="",
|
||||
bgm_config={},
|
||||
)
|
||||
|
||||
with patch("app.api.routes.generation_preview.SQLAlchemyEditTemplateRepository") as MockNewRepo:
|
||||
MockNewRepo.return_value.get.return_value = mock_new_template
|
||||
with patch("app.api.routes.generation_preview.CreateGenerationTaskUseCase") as MockUC:
|
||||
MockUC.return_value.execute.return_value = task
|
||||
with patch(
|
||||
@@ -1279,7 +1453,53 @@ class TestPreviewRouteAutoInfersVideoRatio:
|
||||
db=mock_db,
|
||||
)
|
||||
|
||||
# Verify the resolution passed to CreateGenerationTaskCommand
|
||||
call_args = MockUC.return_value.execute.call_args
|
||||
cmd = call_args[0][0]
|
||||
assert cmd.resolution == "480x854", f"Expected 480x854, got {cmd.resolution}"
|
||||
assert cmd.strategy_id == "pip", f"Expected strategy_id='pip', got '{cmd.strategy_id}'"
|
||||
|
||||
def test_strategy_id_fallback_to_old_template(self):
|
||||
"""新模板无数据时,从旧模板读取 strategy_id=standard。"""
|
||||
from app.api.routes.generation_preview import create_preview_generation_task
|
||||
from app.schemas.generation_task import CreatePreviewGenerationTaskRequest
|
||||
|
||||
repo = MagicMock()
|
||||
repo.count_pending_by_user.return_value = 0
|
||||
repo.count_pending_total.return_value = 0
|
||||
mock_db = MagicMock()
|
||||
|
||||
mock_old_template = MagicMock()
|
||||
mock_old_template.mode = "standard"
|
||||
|
||||
task = _make_task()
|
||||
|
||||
request = CreatePreviewGenerationTaskRequest(
|
||||
template_id="tpl_standard",
|
||||
asset_ids=["a1"],
|
||||
title_ids=[],
|
||||
voice_ids=[],
|
||||
video_title="test",
|
||||
duration=0.0,
|
||||
video_ratio="",
|
||||
bgm_config={},
|
||||
)
|
||||
|
||||
with patch("app.api.routes.generation_preview.SQLAlchemyEditTemplateRepository") as MockNewRepo:
|
||||
MockNewRepo.return_value.get.return_value = None
|
||||
with patch("app.api.routes.generation_preview.SQLAlchemyTemplateRepository") as MockOldRepo:
|
||||
MockOldRepo.return_value.get.return_value = mock_old_template
|
||||
with patch("app.api.routes.generation_preview.CreateGenerationTaskUseCase") as MockUC:
|
||||
MockUC.return_value.execute.return_value = task
|
||||
with patch(
|
||||
"app.api.routes.generation_preview.safe_enqueue_generation_task",
|
||||
return_value=True,
|
||||
):
|
||||
resp = create_preview_generation_task(
|
||||
request,
|
||||
authenticated_user=_make_user(),
|
||||
generation_task_repository=repo,
|
||||
db=mock_db,
|
||||
)
|
||||
|
||||
call_args = MockUC.return_value.execute.call_args
|
||||
cmd = call_args[0][0]
|
||||
assert cmd.strategy_id == "standard", f"Expected strategy_id='standard', got '{cmd.strategy_id}'"
|
||||
|
||||
Reference in New Issue
Block a user