dfbd141895
CI/CD Pipeline / Check if frontend-only change (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 1m54s
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 / Validate - Migration (alembic) (push) Successful in 2m1s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 2m14s
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Successful in 2m22s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 1m8s
CI/CD Pipeline / Validate - Code Quality (push) Failing after 3m33s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 5m25s
CI/CD Pipeline / Integration Tests (push) Successful in 2m38s
CI/CD Pipeline / Unit Tests (push) Failing after 6m7s
CI/CD Pipeline / Build Staging API Image (push) Successful in 12m16s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 3m12s
CI/CD Pipeline / ACR Image Cleanup (push) Failing after 13s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 5m30s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 6m24s
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
311 lines
11 KiB
Python
Executable File
311 lines
11 KiB
Python
Executable File
"""generated_video 领域模型单元测试."""
|
|
|
|
import pytest
|
|
from domain.generated_video import GeneratedVideo
|
|
|
|
|
|
class TestGeneratedVideoCreate:
|
|
"""GeneratedVideo.create 工厂方法测试."""
|
|
|
|
def test_create_with_required_fields(self):
|
|
video = GeneratedVideo.create(
|
|
project_id="proj_001",
|
|
generation_task_id="task_001",
|
|
name="测试视频",
|
|
file_url="https://example.com/out.mp4",
|
|
)
|
|
assert video.id
|
|
assert len(video.id) == 32
|
|
assert video.project_id == "proj_001"
|
|
assert video.generation_task_id == "task_001"
|
|
assert video.name == "测试视频"
|
|
assert video.file_url == "https://example.com/out.mp4"
|
|
# 默认值
|
|
assert video.user_id == ""
|
|
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.status == "completed"
|
|
assert video.review_status == "pending_review"
|
|
assert video.generation_params == {}
|
|
assert video.video_fingerprint is None
|
|
assert video.is_duplicate is False
|
|
assert video.duplicate_of is None
|
|
assert video.generated_at is not None
|
|
assert video.created_at is not None
|
|
|
|
def test_create_with_all_fields(self):
|
|
video = GeneratedVideo.create(
|
|
project_id="proj_002",
|
|
generation_task_id="task_002",
|
|
name="完整视频",
|
|
file_url="https://example.com/full.mp4",
|
|
user_id="user_001",
|
|
file_size=1024000,
|
|
duration=30.5,
|
|
width=1920,
|
|
height=1080,
|
|
fps=30.0,
|
|
thumbnail_url="https://example.com/thumb.jpg",
|
|
generation_params={"quality": "high"},
|
|
)
|
|
assert video.user_id == "user_001"
|
|
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.thumbnail_url == "https://example.com/thumb.jpg"
|
|
assert video.generation_params == {"quality": "high"}
|
|
|
|
def test_create_strips_strings(self):
|
|
video = GeneratedVideo.create(
|
|
project_id=" proj_003 ",
|
|
generation_task_id=" task_003 ",
|
|
name=" 测试视频 ",
|
|
file_url=" https://example.com/out.mp4 ",
|
|
user_id=" user_003 ",
|
|
)
|
|
assert video.project_id == "proj_003"
|
|
assert video.generation_task_id == "task_003"
|
|
assert video.name == "测试视频"
|
|
assert video.file_url == "https://example.com/out.mp4"
|
|
assert video.user_id == "user_003"
|
|
|
|
def test_create_empty_project_id_raises(self):
|
|
with pytest.raises(ValueError, match="project_id"):
|
|
GeneratedVideo.create(
|
|
project_id="",
|
|
generation_task_id="t",
|
|
name="n",
|
|
file_url="u",
|
|
)
|
|
|
|
def test_create_whitespace_project_id_raises(self):
|
|
with pytest.raises(ValueError, match="project_id"):
|
|
GeneratedVideo.create(
|
|
project_id=" ",
|
|
generation_task_id="t",
|
|
name="n",
|
|
file_url="u",
|
|
)
|
|
|
|
def test_create_empty_generation_task_id_raises(self):
|
|
with pytest.raises(ValueError, match="generation_task_id"):
|
|
GeneratedVideo.create(
|
|
project_id="p",
|
|
generation_task_id="",
|
|
name="n",
|
|
file_url="u",
|
|
)
|
|
|
|
def test_create_empty_name_raises(self):
|
|
with pytest.raises(ValueError, match="name"):
|
|
GeneratedVideo.create(
|
|
project_id="p",
|
|
generation_task_id="t",
|
|
name="",
|
|
file_url="u",
|
|
)
|
|
|
|
def test_create_empty_file_url_raises(self):
|
|
with pytest.raises(ValueError, match="file_url"):
|
|
GeneratedVideo.create(
|
|
project_id="p",
|
|
generation_task_id="t",
|
|
name="n",
|
|
file_url="",
|
|
)
|
|
|
|
def test_create_none_generation_params_defaults_to_empty_dict(self):
|
|
video = GeneratedVideo.create(
|
|
project_id="p",
|
|
generation_task_id="t",
|
|
name="n",
|
|
file_url="u",
|
|
generation_params=None,
|
|
)
|
|
assert video.generation_params == {}
|
|
|
|
def test_create_ids_are_unique(self):
|
|
v1 = GeneratedVideo.create(project_id="p", generation_task_id="t1", name="n1", file_url="u1")
|
|
v2 = GeneratedVideo.create(project_id="p", generation_task_id="t2", name="n2", file_url="u2")
|
|
assert v1.id != v2.id
|
|
|
|
def test_create_timestamps_are_utc(self):
|
|
video = GeneratedVideo.create(project_id="p", generation_task_id="t", name="n", file_url="u")
|
|
assert video.created_at.tzinfo is not None
|
|
assert video.generated_at.tzinfo is not None
|
|
|
|
|
|
class TestGeneratedVideoProperties:
|
|
"""GeneratedVideo 属性测试"""
|
|
|
|
def test_default_status_completed(self):
|
|
gv = GeneratedVideo.create(
|
|
project_id="proj-1",
|
|
generation_task_id="task-1",
|
|
name="测试视频",
|
|
file_url="https://example.com/video.mp4",
|
|
)
|
|
assert gv.status == "completed"
|
|
|
|
def test_default_review_status(self):
|
|
gv = GeneratedVideo.create(
|
|
project_id="proj-1",
|
|
generation_task_id="task-1",
|
|
name="测试视频",
|
|
file_url="https://example.com/video.mp4",
|
|
)
|
|
assert gv.review_status == "pending_review"
|
|
|
|
def test_set_status(self):
|
|
gv = GeneratedVideo.create(
|
|
project_id="proj-1",
|
|
generation_task_id="task-1",
|
|
name="测试视频",
|
|
file_url="https://example.com/video.mp4",
|
|
)
|
|
gv.status = "failed"
|
|
assert gv.status == "failed"
|
|
|
|
def test_mark_as_duplicate(self):
|
|
gv = GeneratedVideo.create(
|
|
project_id="proj-1",
|
|
generation_task_id="task-1",
|
|
name="测试视频",
|
|
file_url="https://example.com/video.mp4",
|
|
)
|
|
gv.is_duplicate = True
|
|
gv.duplicate_of = "video-original"
|
|
assert gv.is_duplicate is True
|
|
assert gv.duplicate_of == "video-original"
|
|
|
|
def test_set_fingerprint(self):
|
|
gv = GeneratedVideo.create(
|
|
project_id="proj-1",
|
|
generation_task_id="task-1",
|
|
name="测试视频",
|
|
file_url="https://example.com/video.mp4",
|
|
)
|
|
fingerprint = {"phash": "abc123", "md5": "def456"}
|
|
gv.video_fingerprint = fingerprint
|
|
assert gv.video_fingerprint == fingerprint
|
|
|
|
|
|
class TestGeneratedVideoExtended:
|
|
"""GeneratedVideo 深度补充测试"""
|
|
|
|
def test_id_is_hex(self):
|
|
v = GeneratedVideo.create(project_id="p", generation_task_id="t", name="n", file_url="u")
|
|
int(v.id, 16)
|
|
|
|
def test_zero_file_size(self):
|
|
v = GeneratedVideo.create(project_id="p", generation_task_id="t", name="n", file_url="u", file_size=0)
|
|
assert v.file_size == 0
|
|
|
|
def test_large_file_size(self):
|
|
large = 1024 * 1024 * 1024 # 1GB
|
|
v = GeneratedVideo.create(project_id="p", generation_task_id="t", name="n", file_url="u", file_size=large)
|
|
assert v.file_size == large
|
|
|
|
def test_zero_duration(self):
|
|
v = GeneratedVideo.create(project_id="p", generation_task_id="t", name="n", file_url="u", duration=0.0)
|
|
assert v.duration == 0.0
|
|
|
|
def test_large_duration(self):
|
|
v = GeneratedVideo.create(project_id="p", generation_task_id="t", name="n", file_url="u", duration=9999.99)
|
|
assert v.duration == 9999.99
|
|
|
|
def test_zero_dimensions(self):
|
|
v = GeneratedVideo.create(project_id="p", generation_task_id="t", name="n", file_url="u", width=0, height=0)
|
|
assert v.width == 0
|
|
assert v.height == 0
|
|
|
|
def test_4k_dimensions(self):
|
|
v = GeneratedVideo.create(
|
|
project_id="p", generation_task_id="t", name="n", file_url="u", width=3840, height=2160
|
|
)
|
|
assert v.width == 3840
|
|
assert v.height == 2160
|
|
|
|
def test_zero_fps(self):
|
|
v = GeneratedVideo.create(project_id="p", generation_task_id="t", name="n", file_url="u", fps=0.0)
|
|
assert v.fps == 0.0
|
|
|
|
def test_high_fps(self):
|
|
v = GeneratedVideo.create(project_id="p", generation_task_id="t", name="n", file_url="u", fps=120.0)
|
|
assert v.fps == 120.0
|
|
|
|
def test_empty_user_id(self):
|
|
v = GeneratedVideo.create(project_id="p", generation_task_id="t", name="n", file_url="u", user_id="")
|
|
assert v.user_id == ""
|
|
|
|
def test_long_name(self):
|
|
long_name = "视频" * 100
|
|
v = GeneratedVideo.create(project_id="p", generation_task_id="t", name=long_name, file_url="u")
|
|
assert v.name == long_name
|
|
assert len(v.name) == 200
|
|
|
|
def test_unicode_name(self):
|
|
v = GeneratedVideo.create(
|
|
project_id="p", generation_task_id="t", name="🎬 我的精彩视频 · 旅行vlog", file_url="u"
|
|
)
|
|
assert "🎬" in v.name
|
|
assert "旅行vlog" in v.name
|
|
|
|
def test_special_characters_name(self):
|
|
special = "视!@#$%^&*()频"
|
|
v = GeneratedVideo.create(project_id="p", generation_task_id="t", name=special, file_url="u")
|
|
assert v.name == special
|
|
|
|
def test_thumbnail_url_none(self):
|
|
v = GeneratedVideo.create(project_id="p", generation_task_id="t", name="n", file_url="u", thumbnail_url=None)
|
|
assert v.thumbnail_url is None
|
|
|
|
def test_generation_params_complex(self):
|
|
params = {
|
|
"mode": "voice_over",
|
|
"quality": "high",
|
|
"resolution": {"width": 1920, "height": 1080},
|
|
"effects": ["filter", "transition"],
|
|
}
|
|
v = GeneratedVideo.create(
|
|
project_id="p", generation_task_id="t", name="n", file_url="u", generation_params=params
|
|
)
|
|
assert v.generation_params["mode"] == "voice_over"
|
|
assert v.generation_params["resolution"]["width"] == 1920
|
|
assert len(v.generation_params["effects"]) == 2
|
|
|
|
def test_generation_params_independence(self):
|
|
v1 = GeneratedVideo.create(project_id="p", generation_task_id="t1", name="n1", file_url="u1")
|
|
v2 = GeneratedVideo.create(project_id="p", generation_task_id="t2", name="n2", file_url="u2")
|
|
v1.generation_params["key"] = "val"
|
|
assert "key" not in v2.generation_params
|
|
|
|
def test_status_failed(self):
|
|
v = GeneratedVideo.create(project_id="p", generation_task_id="t", name="n", file_url="u")
|
|
v.status = "failed"
|
|
assert v.status == "failed"
|
|
|
|
def test_review_status_approved(self):
|
|
v = GeneratedVideo.create(project_id="p", generation_task_id="t", name="n", file_url="u")
|
|
v.review_status = "approved"
|
|
assert v.review_status == "approved"
|
|
|
|
def test_is_duplicate_default_false(self):
|
|
v = GeneratedVideo.create(project_id="p", generation_task_id="t", name="n", file_url="u")
|
|
assert v.is_duplicate is False
|
|
assert v.duplicate_of is None
|
|
|
|
def test_fingerprint_none_default(self):
|
|
v = GeneratedVideo.create(project_id="p", generation_task_id="t", name="n", file_url="u")
|
|
assert v.video_fingerprint is None
|
|
|
|
def test_empty_file_url_raises(self):
|
|
with pytest.raises(ValueError):
|
|
GeneratedVideo.create(project_id="p", generation_task_id="t", name="n", file_url=" ")
|