7e505a04c7
CI/CD Pipeline / Check if frontend-only change (push) Has been cancelled
CI/CD Pipeline / Validate - Code Quality (push) Has been cancelled
CI/CD Pipeline / Validate - Type Check (mypy) (push) Has been cancelled
CI/CD Pipeline / Validate - Migration (alembic) (push) Has been cancelled
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Frontend Lint (push) Has been cancelled
CI/CD Pipeline / Frontend Unit Tests (push) Has been cancelled
CI/CD Pipeline / PR Build API Image (push) Has been cancelled
CI/CD Pipeline / PR Build Web Image (push) Has been cancelled
CI/CD Pipeline / PR Build Worker Image (push) Has been cancelled
CI/CD Pipeline / Build Staging API Image (push) Has been cancelled
CI/CD Pipeline / Build Staging Web Image (push) Has been cancelled
CI/CD Pipeline / Build Staging Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (push) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (push) Has been cancelled
198 lines
6.4 KiB
Python
Executable File
198 lines
6.4 KiB
Python
Executable File
"""Assets UseCase 单元测试."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from unittest.mock import MagicMock
|
|
|
|
import pytest
|
|
|
|
from packages.application.assets import (
|
|
CreateAssetCommand,
|
|
CreateAssetUseCase,
|
|
ListAssetsUseCase,
|
|
)
|
|
from packages.domain import Asset, AssetStatus, ClassificationStatus
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_asset_repo():
|
|
return MagicMock()
|
|
|
|
|
|
@pytest.fixture
|
|
def sample_asset():
|
|
asset = Asset.create(
|
|
project_id="proj_001",
|
|
library_id="lib_001",
|
|
name="test_video.mp4",
|
|
storage_key="videos/test.mp4",
|
|
mime_type="video/mp4",
|
|
file_size=1024000,
|
|
duration=15.5,
|
|
width=1920,
|
|
height=1080,
|
|
)
|
|
asset.id = "asset_001"
|
|
return asset
|
|
|
|
|
|
class TestListAssetsUseCase:
|
|
"""ListAssetsUseCase 测试"""
|
|
|
|
def test_list_returns_repo_results(self, mock_asset_repo, sample_asset):
|
|
"""正常返回 repository 的查询结果"""
|
|
mock_asset_repo.find_by_library.return_value = [sample_asset]
|
|
use_case = ListAssetsUseCase(mock_asset_repo)
|
|
|
|
result = use_case.execute("lib_001")
|
|
|
|
assert len(result) == 1
|
|
assert result[0].id == "asset_001"
|
|
mock_asset_repo.find_by_library.assert_called_once_with("lib_001")
|
|
|
|
def test_empty_library_id_raises_value_error(self, mock_asset_repo):
|
|
"""空 library_id 抛出 ValueError"""
|
|
use_case = ListAssetsUseCase(mock_asset_repo)
|
|
|
|
with pytest.raises(ValueError, match="library_id 不能为空"):
|
|
use_case.execute("")
|
|
|
|
mock_asset_repo.find_by_library.assert_not_called()
|
|
|
|
def test_whitespace_library_id_raises_value_error(self, mock_asset_repo):
|
|
"""纯空格 library_id 抛出 ValueError"""
|
|
use_case = ListAssetsUseCase(mock_asset_repo)
|
|
|
|
with pytest.raises(ValueError, match="library_id 不能为空"):
|
|
use_case.execute(" ")
|
|
|
|
mock_asset_repo.find_by_library.assert_not_called()
|
|
|
|
def test_library_id_stripped_before_query(self, mock_asset_repo, sample_asset):
|
|
"""library_id 会被 strip 后再查询"""
|
|
mock_asset_repo.find_by_library.return_value = [sample_asset]
|
|
use_case = ListAssetsUseCase(mock_asset_repo)
|
|
|
|
use_case.execute(" lib_001 ")
|
|
|
|
mock_asset_repo.find_by_library.assert_called_once_with("lib_001")
|
|
|
|
def test_empty_list(self, mock_asset_repo):
|
|
"""素材库为空时返回空列表"""
|
|
mock_asset_repo.find_by_library.return_value = []
|
|
use_case = ListAssetsUseCase(mock_asset_repo)
|
|
|
|
result = use_case.execute("lib_001")
|
|
|
|
assert result == []
|
|
mock_asset_repo.find_by_library.assert_called_once_with("lib_001")
|
|
|
|
|
|
class TestCreateAssetUseCase:
|
|
"""CreateAssetUseCase 测试"""
|
|
|
|
def test_create_asset_success(self, mock_asset_repo):
|
|
"""正常创建素材"""
|
|
mock_asset_repo.create.side_effect = lambda a: a
|
|
use_case = CreateAssetUseCase(mock_asset_repo)
|
|
|
|
command = CreateAssetCommand(
|
|
project_id="proj_001",
|
|
library_id="lib_001",
|
|
name="test.png",
|
|
storage_key="images/test.png",
|
|
mime_type="image/png",
|
|
file_size=512000,
|
|
)
|
|
result = use_case.execute(command)
|
|
|
|
assert result.name == "test.png"
|
|
assert result.library_id == "lib_001"
|
|
assert result.mime_type == "image/png"
|
|
assert result.status == AssetStatus.UPLOADING
|
|
assert result.classification_status == ClassificationStatus.PENDING
|
|
mock_asset_repo.create.assert_called_once()
|
|
|
|
def test_create_asset_with_metadata(self, mock_asset_repo):
|
|
"""创建带 metadata 的素材"""
|
|
mock_asset_repo.create.side_effect = lambda a: a
|
|
use_case = CreateAssetUseCase(mock_asset_repo)
|
|
|
|
command = CreateAssetCommand(
|
|
project_id="proj_001",
|
|
library_id="lib_001",
|
|
name="test.mp3",
|
|
storage_key="audio/test.mp3",
|
|
mime_type="audio/mpeg",
|
|
metadata={"bitrate": 320, "sample_rate": 44100},
|
|
duration=180.0,
|
|
)
|
|
result = use_case.execute(command)
|
|
|
|
assert result.metadata["bitrate"] == 320
|
|
assert result.duration == 180.0
|
|
|
|
def test_create_asset_with_quality_score(self, mock_asset_repo):
|
|
"""创建带质量分的素材"""
|
|
mock_asset_repo.create.side_effect = lambda a: a
|
|
use_case = CreateAssetUseCase(mock_asset_repo)
|
|
|
|
command = CreateAssetCommand(
|
|
project_id="proj_001",
|
|
library_id="lib_001",
|
|
name="high_quality.mp4",
|
|
storage_key="videos/hq.mp4",
|
|
mime_type="video/mp4",
|
|
quality_score=95.5,
|
|
uploaded_by_user_id="user_001",
|
|
)
|
|
result = use_case.execute(command)
|
|
|
|
assert result.quality_score == 95.5
|
|
assert result.uploaded_by_user_id == "user_001"
|
|
|
|
def test_create_asset_custom_status(self, mock_asset_repo):
|
|
"""创建时指定自定义状态"""
|
|
mock_asset_repo.create.side_effect = lambda a: a
|
|
use_case = CreateAssetUseCase(mock_asset_repo)
|
|
|
|
command = CreateAssetCommand(
|
|
project_id="proj_001",
|
|
library_id="lib_001",
|
|
name="ready.mp4",
|
|
storage_key="videos/ready.mp4",
|
|
mime_type="video/mp4",
|
|
status=AssetStatus.READY,
|
|
classification_status=ClassificationStatus.COMPLETED,
|
|
)
|
|
result = use_case.execute(command)
|
|
|
|
assert result.status == AssetStatus.READY
|
|
assert result.classification_status == ClassificationStatus.COMPLETED
|
|
|
|
def test_create_asset_with_video_info(self, mock_asset_repo):
|
|
"""创建带视频参数的素材"""
|
|
mock_asset_repo.create.side_effect = lambda a: a
|
|
use_case = CreateAssetUseCase(mock_asset_repo)
|
|
|
|
command = CreateAssetCommand(
|
|
project_id="proj_001",
|
|
library_id="lib_001",
|
|
name="video.mp4",
|
|
storage_key="videos/v.mp4",
|
|
mime_type="video/mp4",
|
|
width=1920,
|
|
height=1080,
|
|
fps=30.0,
|
|
codec="h264",
|
|
duration=60.0,
|
|
thumbnail_url="https://cdn.example.com/thumb.jpg",
|
|
)
|
|
result = use_case.execute(command)
|
|
|
|
assert result.width == 1920
|
|
assert result.height == 1080
|
|
assert result.fps == 30.0
|
|
assert result.codec == "h264"
|
|
assert result.thumbnail_url == "https://cdn.example.com/thumb.jpg"
|