baed0c6431
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 1s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 2s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 22s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 56s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 55s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 2m45s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 2m50s
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Successful in 3m12s
CI/CD Pipeline / Validate - Style (pull_request) Successful in 3m26s
AI Code Review / AI Code Review (pull_request) Successful in 6m25s
CI/CD Pipeline / Validate - Security (pull_request) Successful in 8m4s
CI/CD Pipeline / Unit Tests (pull_request) Failing after 9m55s
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Failing after 1s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 7m15s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Failing after 116h36m32s
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Failing after 116h36m38s
CI/CD Pipeline / Build Staging API Image (pull_request) Failing after 116h36m39s
CI/CD Pipeline / Build Production Worker Image (pull_request) Failing after 116h26m25s
CI/CD Pipeline / Build Production API Image (pull_request) Failing after 116h26m25s
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Failing after 116h36m21s
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Failing after 116h36m21s
CI/CD Pipeline / Build Staging Worker Image (pull_request) Failing after 116h36m23s
CI/CD Pipeline / Build Staging Web Image (pull_request) Failing after 116h36m23s
CI/CD Pipeline / Check push changed paths (pull_request) Failing after 116h36m24s
CI/CD Pipeline / ACR Image Cleanup (pull_request) Failing after 116h36m9s
CI/CD Pipeline / Deploy Production (pull_request) Failing after 116h26m25s
CI/CD Pipeline / Build Production Web Image (pull_request) Failing after 116h26m25s
CI/CD Pipeline / Staging API Integration Tests (pull_request) Failing after 116h36m10s
CI/CD Pipeline / Staging E2E Tests (pull_request) Failing after 116h36m11s
CI/CD Pipeline / Canary Release to Production (pull_request) Failing after 116h26m25s
CI/CD Pipeline / PR Build Web Image (pull_request) Failing after 116h36m17s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Failing after 116h36m18s
CI/CD Pipeline / Frontend Lint (pull_request) Failing after 117h11m28s
P0 Bug:AI数字人视频渲染成功但成片库看不到 - packages/domain/generated_video.py: GeneratedVideo.create 去掉 project_id/generation_task_id 非空必填校验(AI数字人无项目概念,project_id为空;lipsync路径下task_id也可能为空),name/file_url仍强制非空 - apps/api/app/services/ai_avatar_render_service.py: 第7步保存成片时,project_id为空兜底为'ai_avatar',generation_task_id为空兜底为job.id;except块日志从logger.warning改为logger.error+exc_info=True,避免异常被吞 优化:封面抽帧加速(解决60s超时) - apps/api/app/services/ai_avatar_cover_service.py: COVER_POLL_INTERVAL 3s→1s,COVER_MAX_POLL_ATTEMPTS 20→15(最长15s,之前60s);max_frames默认已是5 - requirements.txt: 加 numpy==1.26.4 + opencv-python-headless==4.10.0.84(cover_frame_scorer 用cv2做清晰度/亮度/色彩评分,API镜像之前缺cv2只能回退默认分50.0) 测试适配: - 4处GeneratedVideo单测:从期望ValueError改为允许空串/空白归一化 - test_ai_avatar_emotion_tts_lipsync.py: poll_interval断言1.0,max_poll_attempts断言15
143 lines
4.9 KiB
Python
Executable File
143 lines
4.9 KiB
Python
Executable File
"""GeneratedVideo 生成视频领域实体单测."""
|
|
|
|
import pytest
|
|
|
|
from packages.domain.generated_video import GeneratedVideo
|
|
|
|
|
|
class TestGeneratedVideoCreate:
|
|
def test_create_normal(self):
|
|
video = GeneratedVideo.create(
|
|
project_id="proj1",
|
|
generation_task_id="task1",
|
|
name="我的视频",
|
|
file_url="https://example.com/video.mp4",
|
|
file_size=1024000,
|
|
duration=30.5,
|
|
width=1920,
|
|
height=1080,
|
|
fps=30.0,
|
|
)
|
|
assert video.id
|
|
assert video.project_id == "proj1"
|
|
assert video.generation_task_id == "task1"
|
|
assert video.name == "我的视频"
|
|
assert video.file_url == "https://example.com/video.mp4"
|
|
assert video.file_size == 1024000
|
|
assert video.duration == 30.5
|
|
assert video.width == 1920
|
|
assert video.height == 1080
|
|
assert video.fps == 30.0
|
|
assert video.status == "completed"
|
|
assert video.review_status == "pending_review"
|
|
assert video.is_duplicate is False
|
|
assert video.generation_params == {}
|
|
|
|
def test_create_strips_whitespace(self):
|
|
video = GeneratedVideo.create(
|
|
project_id=" proj1 ",
|
|
generation_task_id=" task1 ",
|
|
name=" 我的视频 ",
|
|
file_url=" https://example.com/video.mp4 ",
|
|
user_id=" user1 ",
|
|
)
|
|
assert video.project_id == "proj1"
|
|
assert video.generation_task_id == "task1"
|
|
assert video.name == "我的视频"
|
|
assert video.file_url == "https://example.com/video.mp4"
|
|
assert video.user_id == "user1"
|
|
|
|
def test_create_empty_project_id_allowed(self):
|
|
"""project_id 允许为空(AI数字人等无项目场景)。"""
|
|
video = GeneratedVideo.create(
|
|
project_id="",
|
|
generation_task_id="task1",
|
|
name="视频",
|
|
file_url="https://example.com/v.mp4",
|
|
)
|
|
assert video.project_id == ""
|
|
|
|
def test_create_whitespace_project_id_normalized_to_empty(self):
|
|
"""project_id 纯空白会被 strip 为空串,不抛异常。"""
|
|
video = GeneratedVideo.create(
|
|
project_id=" ",
|
|
generation_task_id="task1",
|
|
name="视频",
|
|
file_url="https://example.com/v.mp4",
|
|
)
|
|
assert video.project_id == ""
|
|
|
|
def test_create_empty_generation_task_id_allowed(self):
|
|
"""generation_task_id 允许为空(兼容部分异步链路)。"""
|
|
video = GeneratedVideo.create(
|
|
project_id="proj1",
|
|
generation_task_id="",
|
|
name="视频",
|
|
file_url="https://example.com/v.mp4",
|
|
)
|
|
assert video.generation_task_id == ""
|
|
|
|
def test_create_empty_name_raises(self):
|
|
with pytest.raises(ValueError, match="name cannot be empty"):
|
|
GeneratedVideo.create(
|
|
project_id="proj1",
|
|
generation_task_id="task1",
|
|
name="",
|
|
file_url="https://example.com/v.mp4",
|
|
)
|
|
|
|
def test_create_empty_file_url_raises(self):
|
|
with pytest.raises(ValueError, match="file_url cannot be empty"):
|
|
GeneratedVideo.create(
|
|
project_id="proj1",
|
|
generation_task_id="task1",
|
|
name="视频",
|
|
file_url="",
|
|
)
|
|
|
|
def test_create_default_values(self):
|
|
video = GeneratedVideo.create(
|
|
project_id="proj1",
|
|
generation_task_id="task1",
|
|
name="视频",
|
|
file_url="https://example.com/v.mp4",
|
|
)
|
|
assert video.file_size == 0
|
|
assert video.duration == 0.0
|
|
assert video.width == 0
|
|
assert video.height == 0
|
|
assert video.fps == 0.0
|
|
assert video.thumbnail_url is None
|
|
assert video.user_id == ""
|
|
assert video.generation_params == {}
|
|
|
|
def test_create_with_generation_params(self):
|
|
params = {"mode": "pip", "resolution": "1080p"}
|
|
video = GeneratedVideo.create(
|
|
project_id="proj1",
|
|
generation_task_id="task1",
|
|
name="视频",
|
|
file_url="https://example.com/v.mp4",
|
|
generation_params=params,
|
|
)
|
|
assert video.generation_params == params
|
|
|
|
def test_create_none_generation_params(self):
|
|
video = GeneratedVideo.create(
|
|
project_id="proj1",
|
|
generation_task_id="task1",
|
|
name="视频",
|
|
file_url="https://example.com/v.mp4",
|
|
generation_params=None,
|
|
)
|
|
assert video.generation_params == {}
|
|
|
|
def test_create_unique_ids(self):
|
|
v1 = GeneratedVideo.create(
|
|
project_id="proj1", generation_task_id="t1", name="v1", file_url="https://a.com/1.mp4"
|
|
)
|
|
v2 = GeneratedVideo.create(
|
|
project_id="proj1", generation_task_id="t2", name="v2", file_url="https://a.com/2.mp4"
|
|
)
|
|
assert v1.id != v2.id
|