18bd0de3fa
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 1m42s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 1m44s
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 / Build Staging Web Image (push) Successful in 1m42s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 1m26s
CI/CD Pipeline / Validate - Code Quality (push) Failing after 3m13s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 2m22s
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 4m29s
CI/CD Pipeline / Integration Tests (push) Successful in 2m16s
CI/CD Pipeline / Unit Tests (push) Failing after 5m46s
CI/CD Pipeline / Build Staging API Image (push) Successful in 11m28s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 3m18s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 30s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 2m13s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 5m58s
251 lines
7.8 KiB
Python
Executable File
251 lines
7.8 KiB
Python
Executable File
"""
|
|
模板编辑器 Schema 验证测试.
|
|
|
|
覆盖 ExportUpdateRequest 等带 validator 的 Schema.
|
|
纯数据 model 不写单测(无业务逻辑)。
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import pytest
|
|
from app.api.routes.templates_editor.schemas import (
|
|
ExportUpdateRequest,
|
|
)
|
|
|
|
|
|
class TestExportUpdateRequestResolution:
|
|
"""resolution 字段验证."""
|
|
|
|
def test_valid_1080p(self):
|
|
req = ExportUpdateRequest(resolution="1920x1080")
|
|
assert req.resolution == "1920x1080"
|
|
|
|
def test_valid_portrait(self):
|
|
req = ExportUpdateRequest(resolution="1080x1920")
|
|
assert req.resolution == "1080x1920"
|
|
|
|
def test_valid_square(self):
|
|
req = ExportUpdateRequest(resolution="1080x1080")
|
|
assert req.resolution == "1080x1080"
|
|
|
|
def test_valid_min(self):
|
|
req = ExportUpdateRequest(resolution="100x100")
|
|
assert req.resolution == "100x100"
|
|
|
|
def test_valid_max(self):
|
|
req = ExportUpdateRequest(resolution="4096x4096")
|
|
assert req.resolution == "4096x4096"
|
|
|
|
def test_none_is_valid(self):
|
|
req = ExportUpdateRequest()
|
|
assert req.resolution is None
|
|
|
|
def test_invalid_format_no_x(self):
|
|
with pytest.raises(ValueError, match="分辨率格式错误"):
|
|
ExportUpdateRequest(resolution="19201080")
|
|
|
|
def test_invalid_format_letters(self):
|
|
with pytest.raises(ValueError, match="分辨率格式错误"):
|
|
ExportUpdateRequest(resolution="abcxdef")
|
|
|
|
def test_invalid_format_empty(self):
|
|
with pytest.raises(ValueError, match="分辨率格式错误"):
|
|
ExportUpdateRequest(resolution="")
|
|
|
|
def test_invalid_format_upper_x(self):
|
|
"""大写 X 不匹配正则"""
|
|
with pytest.raises(ValueError, match="分辨率格式错误"):
|
|
ExportUpdateRequest(resolution="1920X1080")
|
|
|
|
def test_too_small_width(self):
|
|
with pytest.raises(ValueError, match="过小"):
|
|
ExportUpdateRequest(resolution="50x1080")
|
|
|
|
def test_too_small_height(self):
|
|
with pytest.raises(ValueError, match="过小"):
|
|
ExportUpdateRequest(resolution="1920x50")
|
|
|
|
def test_too_large_width(self):
|
|
with pytest.raises(ValueError, match="过大"):
|
|
ExportUpdateRequest(resolution="5000x1080")
|
|
|
|
def test_too_large_height(self):
|
|
with pytest.raises(ValueError, match="过大"):
|
|
ExportUpdateRequest(resolution="1920x5000")
|
|
|
|
def test_extra_chars_after(self):
|
|
"""后面多字符也不匹配"""
|
|
with pytest.raises(ValueError, match="分辨率格式错误"):
|
|
ExportUpdateRequest(resolution="1920x1080p")
|
|
|
|
def test_extra_chars_before(self):
|
|
with pytest.raises(ValueError, match="分辨率格式错误"):
|
|
ExportUpdateRequest(resolution="fhd1920x1080")
|
|
|
|
|
|
class TestExportUpdateRequestFormat:
|
|
"""format 字段验证."""
|
|
|
|
def test_valid_mp4(self):
|
|
req = ExportUpdateRequest(format="mp4")
|
|
assert req.format == "mp4"
|
|
|
|
def test_valid_mov(self):
|
|
req = ExportUpdateRequest(format="mov")
|
|
assert req.format == "mov"
|
|
|
|
def test_none_is_valid(self):
|
|
req = ExportUpdateRequest()
|
|
assert req.format is None
|
|
|
|
def test_invalid_avi(self):
|
|
with pytest.raises(ValueError, match="无效格式"):
|
|
ExportUpdateRequest(format="avi")
|
|
|
|
def test_invalid_empty(self):
|
|
with pytest.raises(ValueError, match="无效格式"):
|
|
ExportUpdateRequest(format="")
|
|
|
|
def test_invalid_upper(self):
|
|
with pytest.raises(ValueError, match="无效格式"):
|
|
ExportUpdateRequest(format="MP4")
|
|
|
|
|
|
class TestExportUpdateRequestQualityPreset:
|
|
"""quality_preset 字段验证."""
|
|
|
|
@pytest.mark.parametrize("preset", ["ultra_fast", "fast", "balanced", "high", "best"])
|
|
def test_valid_presets(self, preset):
|
|
req = ExportUpdateRequest(quality_preset=preset)
|
|
assert req.quality_preset == preset
|
|
|
|
def test_none_is_valid(self):
|
|
req = ExportUpdateRequest()
|
|
assert req.quality_preset is None
|
|
|
|
def test_invalid_preset(self):
|
|
with pytest.raises(ValueError, match="无效质量预设"):
|
|
ExportUpdateRequest(quality_preset="ultra")
|
|
|
|
def test_invalid_empty(self):
|
|
with pytest.raises(ValueError, match="无效质量预设"):
|
|
ExportUpdateRequest(quality_preset="")
|
|
|
|
|
|
class TestExportUpdateRequestFps:
|
|
"""fps 字段范围验证(由 Field ge/le 控制)."""
|
|
|
|
def test_valid_30(self):
|
|
req = ExportUpdateRequest(fps=30)
|
|
assert req.fps == 30
|
|
|
|
def test_valid_min(self):
|
|
req = ExportUpdateRequest(fps=15)
|
|
assert req.fps == 15
|
|
|
|
def test_valid_max(self):
|
|
req = ExportUpdateRequest(fps=60)
|
|
assert req.fps == 60
|
|
|
|
def test_below_min(self):
|
|
with pytest.raises(ValueError):
|
|
ExportUpdateRequest(fps=10)
|
|
|
|
def test_above_max(self):
|
|
with pytest.raises(ValueError):
|
|
ExportUpdateRequest(fps=120)
|
|
|
|
def test_none_is_valid(self):
|
|
req = ExportUpdateRequest()
|
|
assert req.fps is None
|
|
|
|
|
|
class TestExportUpdateRequestBitrate:
|
|
"""码率字段范围验证."""
|
|
|
|
def test_video_bitrate_valid(self):
|
|
req = ExportUpdateRequest(video_bitrate=5000)
|
|
assert req.video_bitrate == 5000
|
|
|
|
def test_video_bitrate_min(self):
|
|
req = ExportUpdateRequest(video_bitrate=1000)
|
|
assert req.video_bitrate == 1000
|
|
|
|
def test_video_bitrate_max(self):
|
|
req = ExportUpdateRequest(video_bitrate=20000)
|
|
assert req.video_bitrate == 20000
|
|
|
|
def test_video_bitrate_below_min(self):
|
|
with pytest.raises(ValueError):
|
|
ExportUpdateRequest(video_bitrate=500)
|
|
|
|
def test_video_bitrate_above_max(self):
|
|
with pytest.raises(ValueError):
|
|
ExportUpdateRequest(video_bitrate=50000)
|
|
|
|
def test_audio_bitrate_valid(self):
|
|
req = ExportUpdateRequest(audio_bitrate=128)
|
|
assert req.audio_bitrate == 128
|
|
|
|
def test_audio_bitrate_min(self):
|
|
req = ExportUpdateRequest(audio_bitrate=64)
|
|
assert req.audio_bitrate == 64
|
|
|
|
def test_audio_bitrate_max(self):
|
|
req = ExportUpdateRequest(audio_bitrate=320)
|
|
assert req.audio_bitrate == 320
|
|
|
|
def test_audio_bitrate_below_min(self):
|
|
with pytest.raises(ValueError):
|
|
ExportUpdateRequest(audio_bitrate=32)
|
|
|
|
def test_audio_bitrate_above_max(self):
|
|
with pytest.raises(ValueError):
|
|
ExportUpdateRequest(audio_bitrate=512)
|
|
|
|
|
|
class TestExportUpdateRequestWatermark:
|
|
"""水印字段."""
|
|
|
|
def test_watermark_enabled(self):
|
|
req = ExportUpdateRequest(watermark_enabled=True, watermark_text="hello")
|
|
assert req.watermark_enabled is True
|
|
assert req.watermark_text == "hello"
|
|
|
|
def test_watermark_disabled(self):
|
|
req = ExportUpdateRequest(watermark_enabled=False)
|
|
assert req.watermark_enabled is False
|
|
|
|
def test_watermark_default_none(self):
|
|
req = ExportUpdateRequest()
|
|
assert req.watermark_enabled is None
|
|
assert req.watermark_text is None
|
|
|
|
|
|
class TestExportUpdateRequestCombined:
|
|
"""组合字段验证."""
|
|
|
|
def test_full_valid(self):
|
|
req = ExportUpdateRequest(
|
|
resolution="1920x1080",
|
|
fps=30,
|
|
video_bitrate=8000,
|
|
audio_bitrate=128,
|
|
format="mp4",
|
|
quality_preset="balanced",
|
|
watermark_enabled=True,
|
|
watermark_text="test",
|
|
)
|
|
assert req.resolution == "1920x1080"
|
|
assert req.fps == 30
|
|
assert req.format == "mp4"
|
|
assert req.quality_preset == "balanced"
|
|
|
|
def test_partial_update(self):
|
|
"""只更新部分字段,其余为 None"""
|
|
req = ExportUpdateRequest(fps=24)
|
|
assert req.fps == 24
|
|
assert req.resolution is None
|
|
assert req.format is None
|
|
assert req.quality_preset is None
|