test: 更新预览测试 — URL签名mock + 分辨率逻辑匹配修复后行为
CI/CD Pipeline / Check if frontend-only change (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Code Quality (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Frontend Lint (pull_request) Has been cancelled
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / PR Build API Image (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Web 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
AI Code Review / AI Code Review (pull_request) Has been cancelled
PR Automation / Auto Approve on CI Green (pull_request) Has been cancelled
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been cancelled
Preview Deploy / Deploy Preview Environment (pull_request) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (pull_request) Failing after 1048h18m34s
CI/CD Pipeline / Build Staging API Image (pull_request) Failing after 1048h18m38s
CI/CD Pipeline / Staging API Integration Tests (pull_request) Failing after 1048h18m34s
CI/CD Pipeline / Staging E2E Tests (pull_request) Failing after 1048h18m35s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Failing after 1048h18m36s
CI/CD Pipeline / Build Staging Worker Image (pull_request) Failing after 1048h18m37s
CI/CD Pipeline / Build Staging Web Image (pull_request) Failing after 1048h51m53s

This commit is contained in:
2026-08-03 23:08:44 +08:00
parent 11fa1f31da
commit 6800ee31a3
+101 -20
View File
@@ -963,7 +963,7 @@ class TestGetPreviewRoute:
assert exc_info.value.status_code == 403
def test_get_completed_task_with_videos(self):
"""查询 completed 状态任务,返回视频列表"""
"""查询 completed 状态任务,返回视频列表(URL 已签名)"""
repo = MagicMock()
vid_repo = MagicMock()
task = _make_task(status=GenerationTaskStatus.COMPLETED, progress=100.0)
@@ -973,17 +973,22 @@ class TestGetPreviewRoute:
video.duration = 25.0
video.file_size = 512000
# Mock URL 签名(返回带签名的 URL)
mock_storage = MagicMock()
mock_storage.get_download_url.return_value = "https://cdn.example.com/preview_final.mp4?sig=abc123"
with patch("app.api.routes.generation_preview.GetGenerationTaskUseCase") as MockGet:
MockGet.return_value.execute.return_value = task
with patch("app.api.routes.generation_preview.ListGeneratedVideosByTaskUseCase") as MockList:
MockList.return_value.execute.return_value = [video]
resp = get_preview_generation_task(
task_id="preview_task_001",
authenticated_user=_make_user(),
generation_task_repository=repo,
generated_video_repository=vid_repo,
)
assert resp.video_url == "https://cdn.example.com/preview_final.mp4"
with patch("app.api.routes.generation_preview.get_storage_service", return_value=mock_storage):
resp = get_preview_generation_task(
task_id="preview_task_001",
authenticated_user=_make_user(),
generation_task_repository=repo,
generated_video_repository=vid_repo,
)
assert resp.video_url == "https://cdn.example.com/preview_final.mp4?sig=abc123"
assert resp.duration == 25.0
@@ -995,37 +1000,38 @@ class TestGetPreviewRoute:
class TestWorkerPreviewResolution:
"""Worker 层预览模式分辨率强制逻辑测试"""
def test_preview_mode_forces_480p(self):
"""预览模式强制 854x480 + 1M 码率"""
# 模拟 worker 中 export_cfg 逻辑(与实际代码一致,使用 dict 拷贝)
def test_preview_mode_respects_resolution(self):
"""预览模式尊重传入的 resolution 参数(如竖屏 480x854)"""
is_preview = True
resolution = "1920x1080" # 用户指定的分辨率应被忽略
resolution = "480x854" # 竖屏模板
original_config = {"export": {"resolution": "1280x720", "bitrate": "5M"}}
plan_cfg = dict(original_config)
export_cfg = dict(plan_cfg.get("export", {}) or {})
if is_preview:
export_cfg["resolution"] = "854x480"
preview_res = resolution if resolution else "854x480"
export_cfg["resolution"] = preview_res
export_cfg["bitrate"] = "1M"
elif resolution:
export_cfg["resolution"] = resolution
plan_cfg["export"] = export_cfg
assert export_cfg["resolution"] == "854x480"
assert export_cfg["resolution"] == "480x854" # 竖屏
assert export_cfg["bitrate"] == "1M"
# 验证原始配置未被污染
assert original_config["export"]["resolution"] == "1280x720"
def test_non_preview_uses_user_resolution(self):
"""非预览模式使用用户指定分辨率"""
"""非预览模式使用用户指定分辨率(逻辑不变)"""
is_preview = False
resolution = "1920x1080"
plan_cfg = dict({"export": {"resolution": "1280x720"}})
export_cfg = dict(plan_cfg.get("export", {}) or {})
if is_preview:
export_cfg["resolution"] = "854x480"
preview_res = resolution if resolution else "854x480"
export_cfg["resolution"] = preview_res
export_cfg["bitrate"] = "1M"
elif resolution:
export_cfg["resolution"] = resolution
@@ -1033,14 +1039,15 @@ class TestWorkerPreviewResolution:
assert export_cfg["resolution"] == "1920x1080"
def test_non_preview_no_resolution_uses_template(self):
"""非预览模式且用户未指定分辨率,使用模板配置"""
"""非预览模式且用户未指定分辨率,使用模板配置(逻辑不变)"""
is_preview = False
resolution = ""
plan_cfg = dict({"export": {"resolution": "1280x720"}})
export_cfg = dict(plan_cfg.get("export", {}) or {})
if is_preview:
export_cfg["resolution"] = "854x480"
preview_res = resolution if resolution else "854x480"
export_cfg["resolution"] = preview_res
export_cfg["bitrate"] = "1M"
elif resolution:
export_cfg["resolution"] = resolution
@@ -1050,14 +1057,88 @@ class TestWorkerPreviewResolution:
assert export_cfg["resolution"] == "1280x720"
def test_preview_mode_empty_export_cfg(self):
"""预览模式且模板无 export 配置"""
"""预览模式且模板无 export 配置,无传入 resolution 时默认 854x480"""
is_preview = True
resolution = ""
plan_cfg = dict({})
export_cfg = dict(plan_cfg.get("export", {}) or {})
if is_preview:
export_cfg["resolution"] = "854x480"
preview_res = resolution if resolution else "854x480"
export_cfg["resolution"] = preview_res
export_cfg["bitrate"] = "1M"
assert export_cfg["resolution"] == "854x480"
assert export_cfg["bitrate"] == "1M"
# ═══════════════════════════════════════════════════════════════════════════════
# 新增:URL 签名 + 模板时长约束测试
# ═══════════════════════════════════════════════════════════════════════════════
class TestSignVideoUrl:
"""_sign_video_url 预签名 URL 测试。"""
def test_empty_url_returns_empty(self):
"""空 URL 直接返回空字符串。"""
from app.api.routes.generation_preview import _sign_video_url
assert _sign_video_url("") == ""
def test_signs_oss_url(self):
"""OSS URL 应被签名。"""
from app.api.routes.generation_preview import _sign_video_url
mock_storage = MagicMock()
mock_storage.get_download_url.return_value = "https://signed.example.com/video.mp4?sig=abc"
with patch("app.api.routes.generation_preview.get_storage_service", return_value=mock_storage):
result = _sign_video_url("https://bucket.oss.example.com/video.mp4")
assert result == "https://signed.example.com/video.mp4?sig=abc"
mock_storage.get_download_url.assert_called_once()
def test_fallback_on_sign_failure(self):
"""签名失败时降级返回原始 URL。"""
from app.api.routes.generation_preview import _sign_video_url
with patch("app.api.routes.generation_preview.get_storage_service", side_effect=RuntimeError("no storage")):
result = _sign_video_url("https://bucket.oss.example.com/video.mp4")
assert result == "https://bucket.oss.example.com/video.mp4"
def test_sign_returns_none_fallback(self):
"""get_download_url 返回 None 时降级返回原始 URL。"""
from app.api.routes.generation_preview import _sign_video_url
mock_storage = MagicMock()
mock_storage.get_download_url.return_value = None
with patch("app.api.routes.generation_preview.get_storage_service", return_value=mock_storage):
result = _sign_video_url("https://bucket.oss.example.com/video.mp4")
assert result == "https://bucket.oss.example.com/video.mp4"
class TestCalcPreviewResolution:
"""_calc_preview_resolution 单元测试。"""
def test_portrait_9_16(self):
from app.api.routes.generation_preview import _calc_preview_resolution
assert _calc_preview_resolution("9:16") == "480x854"
def test_landscape_16_9(self):
from app.api.routes.generation_preview import _calc_preview_resolution
assert _calc_preview_resolution("16:9") == "854x480"
def test_square_1_1(self):
from app.api.routes.generation_preview import _calc_preview_resolution
assert _calc_preview_resolution("1:1") == "480x480"
def test_unknown_defaults_to_landscape(self):
from app.api.routes.generation_preview import _calc_preview_resolution
assert _calc_preview_resolution("unknown") == "854x480"
def test_empty_defaults_to_landscape(self):
from app.api.routes.generation_preview import _calc_preview_resolution
assert _calc_preview_resolution("") == "854x480"