c3ac621ebd
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 Worker Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 1m56s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 2m31s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 3m20s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 5m55s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 7m29s
CI/CD Pipeline / Integration Tests (push) Successful in 2m25s
CI/CD Pipeline / Unit Tests (push) Successful in 11m25s
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 / CI Gate (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (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 Worker Image (push) Successful in 13m21s
CI/CD Pipeline / Build Staging API Image (push) Successful in 28m52s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m17s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 40s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m0s
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Staging E2E Tests (push) Successful in 3m21s
133 lines
4.7 KiB
Python
133 lines
4.7 KiB
Python
"""Tests for cover_url backfill to GenerationTask.
|
|
|
|
Verifies _finalize_render_success correctly writes cover_url
|
|
from cover_candidates to gen_task.cover_url.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import sys
|
|
from pathlib import Path
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
import pytest
|
|
|
|
# Add worker app to sys.path
|
|
_WORKER_ROOT = Path(__file__).resolve().parents[2] / "apps" / "worker"
|
|
if str(_WORKER_ROOT) not in sys.path:
|
|
sys.path.insert(0, str(_WORKER_ROOT))
|
|
|
|
|
|
class FakeGenTask:
|
|
"""Simple stand-in for GenerationTask that tracks attribute assignment."""
|
|
|
|
def __init__(self):
|
|
object.__setattr__(self, "_assigned", {})
|
|
self.id = "task-1"
|
|
self.status = MagicMock()
|
|
self.status.value = "running"
|
|
|
|
def __setattr__(self, name, value):
|
|
if not name.startswith("_"):
|
|
self._assigned[name] = value
|
|
object.__setattr__(self, name, value)
|
|
|
|
def append_log(self, **kwargs):
|
|
pass
|
|
|
|
|
|
def _make_plan():
|
|
plan = MagicMock()
|
|
plan.project_id = "proj-1"
|
|
plan.created_by_user_id = "user-1"
|
|
plan.config = {"batch_id": "batch-1", "mode": "edit_plan", "title": {"text": "test"}}
|
|
plan.mark_completed = MagicMock()
|
|
return plan
|
|
|
|
|
|
def _call_finalize(cover_candidates=None, gen_task=None, plan=None):
|
|
from worker_app.tasks.edit_plan_generation import _finalize_render_success
|
|
|
|
plan = plan or _make_plan()
|
|
gen_task = gen_task or FakeGenTask()
|
|
|
|
plan_repo = MagicMock()
|
|
clip_repo = MagicMock()
|
|
gen_task_repo = MagicMock()
|
|
gen_task_repo.get.return_value = gen_task
|
|
db = MagicMock()
|
|
|
|
with patch("worker_app.tasks.edit_plan_generation.create_video_record_and_dedup"):
|
|
result = _finalize_render_success(
|
|
plan=plan,
|
|
plan_repo=plan_repo,
|
|
clip_repo=clip_repo,
|
|
gen_task_repo=gen_task_repo,
|
|
db=db,
|
|
plan_id="plan-1",
|
|
output_url="https://oss.example.com/output.mp4",
|
|
storage_key="rendered/plan-1/task-1.mp4",
|
|
duration=10.0,
|
|
file_size=1024,
|
|
width=1280,
|
|
height=720,
|
|
rendered_clip_ids=["clip-1"],
|
|
failed_clip_ids=[],
|
|
generation_task_id="task-1",
|
|
output_path=Path("/tmp/output.mp4"),
|
|
engine="unified",
|
|
thumbnail_url="",
|
|
cover_candidates=cover_candidates,
|
|
)
|
|
|
|
return result, gen_task, gen_task_repo
|
|
|
|
|
|
class TestFinalizeCoverUrl:
|
|
|
|
def test_cover_url_set_from_image_url(self):
|
|
"""cover_candidates with image_url should set gen_task.cover_url"""
|
|
candidates = [
|
|
{"image_url": "https://oss.example.com/cover1.jpg", "frame_time": 1.5},
|
|
{"image_url": "https://oss.example.com/cover2.jpg", "frame_time": 3.0},
|
|
]
|
|
_, gen_task, gen_task_repo = _call_finalize(cover_candidates=candidates)
|
|
assert gen_task.cover_url == "https://oss.example.com/cover1.jpg"
|
|
gen_task_repo.update.assert_called()
|
|
|
|
def test_cover_url_fallback_to_url_key(self):
|
|
"""Should fallback to 'url' key when 'image_url' is absent"""
|
|
candidates = [{"url": "https://oss.example.com/cover_url_key.jpg"}]
|
|
_, gen_task, _ = _call_finalize(cover_candidates=candidates)
|
|
assert gen_task.cover_url == "https://oss.example.com/cover_url_key.jpg"
|
|
|
|
def test_cover_url_not_set_when_empty_list(self):
|
|
"""Empty cover_candidates should not set cover_url"""
|
|
_, gen_task, _ = _call_finalize(cover_candidates=[])
|
|
assert "cover_url" not in gen_task._assigned
|
|
|
|
def test_cover_url_not_set_when_none(self):
|
|
"""None cover_candidates should not set cover_url"""
|
|
_, gen_task, _ = _call_finalize(cover_candidates=None)
|
|
assert "cover_url" not in gen_task._assigned
|
|
|
|
def test_cover_url_not_set_when_url_empty(self):
|
|
"""Empty URL strings in candidates should not set cover_url"""
|
|
candidates = [{"image_url": "", "url": ""}]
|
|
_, gen_task, _ = _call_finalize(cover_candidates=candidates)
|
|
assert "cover_url" not in gen_task._assigned
|
|
|
|
def test_no_generation_task_no_crash(self):
|
|
"""Should not crash when gen_task is None"""
|
|
candidates = [{"image_url": "https://oss.example.com/cover.jpg"}]
|
|
gen_task_repo = MagicMock()
|
|
gen_task_repo.get.return_value = None
|
|
result, _, _ = _call_finalize(cover_candidates=candidates)
|
|
assert result["status"] == "completed"
|
|
|
|
def test_image_url_priority_over_url(self):
|
|
"""image_url should take priority over url key"""
|
|
candidates = [{"image_url": "https://a.jpg", "url": "https://b.jpg"}]
|
|
_, gen_task, _ = _call_finalize(cover_candidates=candidates)
|
|
assert gen_task.cover_url == "https://a.jpg"
|