7a72cfd709
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 - Migration (alembic) (push) Successful in 2m9s
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 - Type Check (mypy) (push) Successful in 2m19s
CI/CD Pipeline / Validate - Code Quality (push) Failing after 3m10s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 3m7s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 3m7s
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 1m17s
CI/CD Pipeline / Frontend Lint (push) Successful in 3m37s
CI/CD Pipeline / Integration Tests (push) Successful in 2m18s
CI/CD Pipeline / Unit Tests (push) Failing after 4m59s
CI/CD Pipeline / Build Staging API Image (push) Successful in 8m39s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 3m25s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 42s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 27m2s
CI/CD Pipeline / Staging API Integration Tests (push) Failing after 30m15s
178 lines
5.6 KiB
Python
Executable File
178 lines
5.6 KiB
Python
Executable File
"""统一渲染服务纯逻辑测试 — _resolve_layer_role + 图层配置 + 数据结构."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
from video_processing.unified_render_service import (
|
|
_LAYER_Z_INDEX,
|
|
_PIP_SCALE,
|
|
RenderLayer,
|
|
ResolvedClip,
|
|
_resolve_layer_role,
|
|
)
|
|
|
|
|
|
class TestResolveLayerRole:
|
|
"""_resolve_layer_role 图层角色映射测试."""
|
|
|
|
def test_intro_is_main(self):
|
|
"""intro片段 → main层."""
|
|
assert _resolve_layer_role("intro", {}) == "main"
|
|
|
|
def test_outro_is_main(self):
|
|
"""outro片段 → main层."""
|
|
assert _resolve_layer_role("outro", {}) == "main"
|
|
|
|
def test_overlay_is_overlay(self):
|
|
"""overlay片段 → overlay层."""
|
|
assert _resolve_layer_role("overlay", {}) == "overlay"
|
|
|
|
def test_corner_voice(self):
|
|
"""corner_voice片段 → corner_voice层."""
|
|
assert _resolve_layer_role("corner_voice", {}) == "corner_voice"
|
|
|
|
def test_background(self):
|
|
"""background片段 → background层."""
|
|
assert _resolve_layer_role("background", {}) == "background"
|
|
|
|
def test_b_roll(self):
|
|
"""b_roll片段 → broll层."""
|
|
assert _resolve_layer_role("b_roll", {}) == "broll"
|
|
|
|
def test_main_default(self):
|
|
"""main type默认 → main层."""
|
|
assert _resolve_layer_role("main", {}) == "main"
|
|
|
|
def test_main_with_broll_role(self):
|
|
"""main type + role=b_roll → broll层."""
|
|
assert _resolve_layer_role("main", {"role": "b_roll"}) == "broll"
|
|
|
|
def test_main_with_audio_role(self):
|
|
"""main type + role=audio → audio层."""
|
|
assert _resolve_layer_role("main", {"role": "audio"}) == "audio"
|
|
|
|
def test_unknown_type_falls_back_to_main(self):
|
|
"""未知类型 → main层."""
|
|
assert _resolve_layer_role("random_type", {}) == "main"
|
|
|
|
def test_intro_ignores_role(self):
|
|
"""intro/outro忽略role配置."""
|
|
assert _resolve_layer_role("intro", {"role": "b_roll"}) == "main"
|
|
assert _resolve_layer_role("outro", {"role": "overlay"}) == "main"
|
|
|
|
def test_empty_config(self):
|
|
"""空config不影响结果."""
|
|
assert _resolve_layer_role("main", {}) == "main"
|
|
|
|
def test_none_role(self):
|
|
"""role=None时走默认."""
|
|
assert _resolve_layer_role("main", {"role": None}) == "main"
|
|
|
|
|
|
class TestLayerZIndex:
|
|
"""_LAYER_Z_INDEX 图层层级配置测试."""
|
|
|
|
def test_background_lowest(self):
|
|
"""background在最底层."""
|
|
assert _LAYER_Z_INDEX["background"] == -1
|
|
|
|
def test_main_and_broll_same_level(self):
|
|
"""main和broll在同一层(z=0)."""
|
|
assert _LAYER_Z_INDEX["main"] == 0
|
|
assert _LAYER_Z_INDEX["broll"] == 0
|
|
|
|
def test_overlay_and_corner_voice_above(self):
|
|
"""overlay和corner_voice在z=1."""
|
|
assert _LAYER_Z_INDEX["overlay"] == 1
|
|
assert _LAYER_Z_INDEX["corner_voice"] == 1
|
|
|
|
def test_audio_highest(self):
|
|
"""audio在z=2(最高,因为音频不涉及z顺序但参与混音)."""
|
|
assert _LAYER_Z_INDEX["audio"] == 2
|
|
|
|
def test_pip_scale_is_positive(self):
|
|
"""PiP缩放比例为正数."""
|
|
assert _PIP_SCALE > 0
|
|
assert _PIP_SCALE < 1.0
|
|
|
|
|
|
class TestResolvedClip:
|
|
"""ResolvedClip 数据结构测试."""
|
|
|
|
def test_default_values(self):
|
|
"""默认值正确."""
|
|
clip = ResolvedClip(
|
|
clip_id="c1",
|
|
asset_id="a1",
|
|
local_path=Path("/tmp/test.mp4"),
|
|
clip_type="main",
|
|
order=0,
|
|
)
|
|
assert clip.start_time == 0.0
|
|
assert clip.duration == 0.0
|
|
assert clip.transition_effect == "cut"
|
|
assert clip.transition_duration == 0.0
|
|
assert clip.playback_speed == 1.0
|
|
assert clip.config == {}
|
|
assert clip.actual_duration == 0.0
|
|
assert clip.trim_config is None
|
|
|
|
def test_custom_values(self):
|
|
"""自定义值正确."""
|
|
clip = ResolvedClip(
|
|
clip_id="c2",
|
|
asset_id="a2",
|
|
local_path=Path("/tmp/video.mp4"),
|
|
clip_type="overlay",
|
|
order=1,
|
|
start_time=5.0,
|
|
duration=10.0,
|
|
transition_effect="fade",
|
|
transition_duration=0.5,
|
|
playback_speed=1.5,
|
|
)
|
|
assert clip.clip_id == "c2"
|
|
assert clip.asset_id == "a2"
|
|
assert clip.clip_type == "overlay"
|
|
assert clip.order == 1
|
|
assert clip.start_time == 5.0
|
|
assert clip.duration == 10.0
|
|
assert clip.transition_effect == "fade"
|
|
assert clip.transition_duration == 0.5
|
|
assert clip.playback_speed == 1.5
|
|
|
|
|
|
class TestRenderLayer:
|
|
"""RenderLayer 数据结构测试."""
|
|
|
|
def test_default_values(self):
|
|
"""默认值正确."""
|
|
layer = RenderLayer(role="main")
|
|
assert layer.clips == []
|
|
assert layer.z_index == 0
|
|
assert layer.opacity == 1.0
|
|
assert layer.position is None
|
|
|
|
def test_with_clips(self):
|
|
"""带片段的图层."""
|
|
clip = ResolvedClip(
|
|
clip_id="c1",
|
|
asset_id="a1",
|
|
local_path=Path("/tmp/t.mp4"),
|
|
clip_type="main",
|
|
order=0,
|
|
)
|
|
layer = RenderLayer(role="overlay", clips=[clip], z_index=1)
|
|
assert len(layer.clips) == 1
|
|
assert layer.z_index == 1
|
|
assert layer.role == "overlay"
|
|
|
|
def test_background_layer(self):
|
|
"""background图层配置."""
|
|
layer = RenderLayer(role="background", z_index=-1, opacity=1.0)
|
|
assert layer.role == "background"
|
|
assert layer.z_index == -1
|
|
assert layer.opacity == 1.0
|