Files
xiaoxia-saas/tests/unit/test_batch_clips_endpoint.py
CI Bot 6f222db4c7
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 45s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 44s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 1m49s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 1m52s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 1m53s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m23s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 1m44s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m35s
CI/CD Pipeline / Unit Tests (pull_request) Successful in 3m9s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 5m54s
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
AI Code Review / AI Code Review (pull_request) Successful in 6m51s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 2m15s
CI/CD Pipeline / CI Gate (pull_request) Successful in 6s
ACR Cleanup / ACR Image Cleanup (pull_request_target) Successful in 39s
Preview Cleanup / Cleanup Preview Environment (pull_request) Successful in 57s
fix(editor): 移除asset_id min_length限制+order默认None (#1468)
AI Code Review 第三轮修复:
1. EditorClipBatchItem.asset_id 移除 min_length=1,允许空字符串(占位片段场景)
2. EditorClipBatchItem.order 默认值改为 None(非0),仅在显式传入时加入 dict
3. 服务层 order 逻辑:dict 无 order key 时回退到索引 i
4. 测试更新:9 passed
2026-08-23 15:54:34 +08:00

136 lines
4.7 KiB
Python
Executable File

"""Tests for PUT /templates/{id}/editor/clips batch update endpoint.
Updated for transactional replace_all_clips_transactional method.
"""
from __future__ import annotations
import os
from unittest.mock import MagicMock
import pytest
os.environ.setdefault("JWT_SECRET_KEY", "unit-test-secret-key-for-testing")
@pytest.fixture
def mock_services():
plan_svc = MagicMock()
tpl_svc = MagicMock()
plan_svc.get_plan_or_raise.return_value = MagicMock(id="plan-1", template_id="tpl-1")
plan_svc.replace_all_clips_transactional.return_value = 2
return tpl_svc, plan_svc
class TestBatchUpdateClips:
def test_batch_update_calls_transactional_replace(self, mock_services):
"""验证批量更新调用事务性替换方法,传入正确的参数。"""
from app.api.routes.templates_editor.draft import batch_update_clips
from app.api.routes.templates_editor.schemas import (
EditorClipBatchItem,
EditorClipBatchUpdateRequest,
)
_, plan_svc = mock_services
req = EditorClipBatchUpdateRequest(
clips=[
EditorClipBatchItem(asset_id="a1", start_time=0.0, duration=3.0, order=0),
EditorClipBatchItem(asset_id="a2", start_time=3.0, duration=5.0, order=1),
]
)
result = batch_update_clips(
template_id="tpl-1",
req=req,
plan_id="plan-1",
services=mock_services,
_=MagicMock(),
)
assert result.plan_id == "plan-1"
assert result.clip_count == 2
plan_svc.replace_all_clips_transactional.assert_called_once()
call_args = plan_svc.replace_all_clips_transactional.call_args
assert call_args[0][0] == "plan-1"
clips_data = call_args[0][1]
assert len(clips_data) == 2
assert clips_data[0]["asset_id"] == "a1"
assert clips_data[0]["start_time"] == 0.0
assert clips_data[0]["duration"] == 3.0
assert clips_data[1]["asset_id"] == "a2"
def test_batch_update_empty_clips(self, mock_services):
"""空 clips 列表也能正常处理。"""
from app.api.routes.templates_editor.draft import batch_update_clips
from app.api.routes.templates_editor.schemas import EditorClipBatchUpdateRequest
_, plan_svc = mock_services
req = EditorClipBatchUpdateRequest(clips=[])
result = batch_update_clips(
template_id="tpl-1",
req=req,
plan_id="plan-1",
services=mock_services,
_=MagicMock(),
)
assert result.clip_count == 0
plan_svc.replace_all_clips_transactional.assert_called_once()
call_args = plan_svc.replace_all_clips_transactional.call_args
assert call_args[0][1] == []
def test_batch_update_passes_order_correctly(self, mock_services):
"""验证 order 字段正确传递。"""
from app.api.routes.templates_editor.draft import batch_update_clips
from app.api.routes.templates_editor.schemas import (
EditorClipBatchItem,
EditorClipBatchUpdateRequest,
)
_, plan_svc = mock_services
req = EditorClipBatchUpdateRequest(
clips=[
EditorClipBatchItem(asset_id="a1", start_time=0.0, duration=3.0, order=5),
]
)
batch_update_clips(
template_id="tpl-1",
req=req,
plan_id="plan-1",
services=mock_services,
_=MagicMock(),
)
clips_data = plan_svc.replace_all_clips_transactional.call_args[0][1]
assert clips_data[0]["order"] == 5
assert clips_data[0]["asset_id"] == "a1"
assert clips_data[0]["start_time"] == 0.0
assert clips_data[0]["duration"] == 3.0
class TestEditorClipBatchItemValidation:
"""验证 schema 校验规则。"""
def test_asset_id_empty_string_allowed(self):
"""asset_id 空字符串允许通过(占位片段场景)。"""
from app.api.routes.templates_editor.schemas import EditorClipBatchItem
item = EditorClipBatchItem(asset_id="", start_time=0.0, duration=3.0, order=0)
assert item.asset_id == ""
def test_asset_id_valid(self):
"""有效 asset_id 应通过校验。"""
from app.api.routes.templates_editor.schemas import EditorClipBatchItem
item = EditorClipBatchItem(asset_id="abc123", start_time=0.0, duration=3.0, order=0)
assert item.asset_id == "abc123"
def test_order_none_by_default(self):
"""order 默认为 None,表示按数组顺序。"""
from app.api.routes.templates_editor.schemas import EditorClipBatchItem
item = EditorClipBatchItem(asset_id="a1", start_time=0.0, duration=3.0)
assert item.order is None