f8bc252ded
CI/CD Pipeline / Build Production Runtime Images (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 / Staging E2E Tests (push) Failing after 49h30m34s
CI/CD Pipeline / Deploy Staging (push) Failing after 49h34m18s
CI/CD Pipeline / Frontend Lint (push) Failing after 49h36m48s
CI/CD Pipeline / Validate Code Quality And Tests (push) Failing after 49h36m54s
- 新增 POST /assets/batch-delete 批量删除素材接口 - 仓储层: abstract/SQLAlchemy/InMemory 均实现 batch_delete() - API层: 逐项校验项目权限后批量删除 - Schema: BatchDeleteRequest/BatchDeleteResponse - GET /assets 分页优化: 无 keyword/gender/style 过滤时走 DB 级 skip/limit - 素材上传 duration 字段已全链路支持(domain/schema/ORM/repository) - 新增 4 个批量删除单元测试,全量 1030 测试通过 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
78 lines
2.5 KiB
Python
78 lines
2.5 KiB
Python
"""批量删除素材 + 分页优化 单元测试。"""
|
|
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
sys.path.insert(0, str(Path(__file__).resolve().parents[2] / "apps" / "api"))
|
|
|
|
from packages.adapters.in_memory.asset_repository import InMemoryAssetRepository
|
|
from packages.domain import Asset, AssetStatus
|
|
|
|
|
|
class TestBatchDelete:
|
|
"""batch_delete 仓储方法测试。"""
|
|
|
|
def _make_repo_with_assets(self):
|
|
repo = InMemoryAssetRepository()
|
|
for i in range(5):
|
|
asset = Asset.create(
|
|
project_id="proj-1",
|
|
library_id="lib-1",
|
|
name=f"voice_{i}.mp3",
|
|
storage_key=f"uploads/voice_{i}.mp3",
|
|
mime_type="audio/mpeg",
|
|
status=AssetStatus.READY,
|
|
)
|
|
repo.create(asset)
|
|
return repo
|
|
|
|
def test_batch_delete_removes_multiple(self):
|
|
repo = InMemoryAssetRepository()
|
|
assets = []
|
|
for i in range(5):
|
|
asset = Asset.create(
|
|
project_id="proj-1",
|
|
library_id="lib-1",
|
|
name=f"voice_{i}.mp3",
|
|
storage_key=f"uploads/voice_{i}.mp3",
|
|
mime_type="audio/mpeg",
|
|
)
|
|
repo.create(asset)
|
|
assets.append(asset)
|
|
|
|
ids_to_delete = [assets[0].id, assets[2].id, assets[4].id]
|
|
deleted_count = repo.batch_delete(ids_to_delete)
|
|
|
|
assert deleted_count == 3
|
|
# 验证确实被删了
|
|
assert repo.get(assets[0].id) is None
|
|
assert repo.get(assets[2].id) is None
|
|
assert repo.get(assets[4].id) is None
|
|
# 验证其他还在
|
|
assert repo.get(assets[1].id) is not None
|
|
assert repo.get(assets[3].id) is not None
|
|
|
|
def test_batch_delete_empty_list(self):
|
|
repo = self._make_repo_with_assets()
|
|
assert repo.batch_delete([]) == 0
|
|
|
|
def test_batch_delete_nonexistent_ids(self):
|
|
repo = self._make_repo_with_assets()
|
|
deleted = repo.batch_delete(["nonexistent-1", "nonexistent-2"])
|
|
assert deleted == 0
|
|
|
|
def test_batch_delete_mixed_existing_and_nonexistent(self):
|
|
repo = InMemoryAssetRepository()
|
|
asset = Asset.create(
|
|
project_id="proj-1",
|
|
library_id="lib-1",
|
|
name="voice.mp3",
|
|
storage_key="uploads/voice.mp3",
|
|
mime_type="audio/mpeg",
|
|
)
|
|
repo.create(asset)
|
|
|
|
deleted = repo.batch_delete([asset.id, "nonexistent"])
|
|
assert deleted == 1
|
|
assert repo.get(asset.id) is None
|