Files
xiaoxia-saas/tests/unit/test_generation_tasks.py
T
saas-backend-agent ba9837986e test(#1749): 旧行为测试适配新口径(目标段长为准/逐处转场重叠/voice_ids 移除)+ filter_complex trim 口径统一
- unified_render_service filter_complex Step1 trim 时长改为 effective-freeze(与直通路径同口径,tpad 补冻结)
- test_duration_compensation / render_audio_utils / render_audio_pure / 两处 render_layer_utils:min(duration,actual) 断言改为目标段长为准
- estimate_total_duration 测试:cut 零重叠、非 cut 逐处扣转场(FakeClip 加 transition_effect/duration)
- test_generation_tasks/preview:voice_ids kwarg/字段移除,配音改 voice_library_id
2026-09-07 07:02:08 +08:00

251 lines
8.5 KiB
Python
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""生成任务 UseCase 单元测试."""
from __future__ import annotations
from unittest.mock import MagicMock
import pytest
from packages.application.generation_tasks import (
CreateGenerationTaskCommand,
CreateGenerationTaskUseCase,
GetGenerationTaskUseCase,
ListGenerationTasksResult,
ListTasksFilter,
ListUserTasksFilteredUseCase,
RetryGenerationTaskUseCase,
)
from packages.domain import GenerationTask
@pytest.fixture
def mock_repo():
return MagicMock()
@pytest.fixture
def sample_task():
task = MagicMock(spec=GenerationTask)
task.id = "task_001"
task.project_id = "proj_001"
task.status = "pending"
return task
class TestCreateGenerationTaskUseCase:
"""CreateGenerationTaskUseCase 测试"""
def test_create_task_success(self, mock_repo):
"""正常创建生成任务"""
mock_repo.create.side_effect = lambda t: t
use_case = CreateGenerationTaskUseCase(mock_repo)
command = CreateGenerationTaskCommand(
project_id="proj_001",
template_id="tpl_001",
asset_library_id="lib_001",
voice_library_id="voice_lib_001",
created_by_user_id="user_001",
)
result = use_case.execute(command)
assert isinstance(result, GenerationTask)
assert result.project_id == "proj_001"
assert result.template_id == "tpl_001"
assert result.status == "pending"
assert result.progress == 0.0
assert result.result_count == 0
mock_repo.create.assert_called_once()
def test_create_task_generates_id(self, mock_repo):
"""创建任务时生成 id"""
mock_repo.create.side_effect = lambda t: t
use_case = CreateGenerationTaskUseCase(mock_repo)
command = CreateGenerationTaskCommand(project_id="proj_001")
result = use_case.execute(command)
assert result.id is not None
assert len(result.id) > 0
def test_create_task_with_asset_ids(self, mock_repo):
"""创建带 asset_ids 的任务"""
mock_repo.create.side_effect = lambda t: t
use_case = CreateGenerationTaskUseCase(mock_repo)
command = CreateGenerationTaskCommand(
project_id="proj_001",
asset_ids=["asset_1", "asset_2", "asset_3"],
title_ids=["title_1", "title_2"],
)
result = use_case.execute(command)
assert len(result.asset_ids) == 3
assert len(result.title_ids) == 2
# #1749voice_ids 已从 Command 移除(配音走 voice_library_id(s)),落库固定空列表
assert list(getattr(result, "voice_ids", []) or []) == []
def test_create_task_with_auto_retry(self, mock_repo):
"""创建带自动重试配置的任务"""
mock_repo.create.side_effect = lambda t: t
use_case = CreateGenerationTaskUseCase(mock_repo)
command = CreateGenerationTaskCommand(
project_id="proj_001",
auto_retry_enabled=True,
auto_retry_max=3,
)
result = use_case.execute(command)
assert result.auto_retry_enabled is True
assert result.auto_retry_max == 3
def test_create_task_with_bgm_config(self, mock_repo):
"""创建带 BGM 配置的任务"""
mock_repo.create.side_effect = lambda t: t
use_case = CreateGenerationTaskUseCase(mock_repo)
bgm = {"enabled": True, "volume": 0.5, "library_id": "bgm_lib"}
command = CreateGenerationTaskCommand(
project_id="proj_001",
bgm_config=bgm,
resolution="1080p",
video_title="测试视频",
)
result = use_case.execute(command)
assert result.bgm_config == bgm
assert result.resolution == "1080p"
assert result.video_title == "测试视频"
def test_create_task_defaults(self, mock_repo):
"""默认参数的任务"""
mock_repo.create.side_effect = lambda t: t
use_case = CreateGenerationTaskUseCase(mock_repo)
command = CreateGenerationTaskCommand()
result = use_case.execute(command)
assert result.project_id == ""
assert result.asset_ids == []
assert result.auto_retry_enabled is False
assert result.auto_retry_max == 0
class TestGetGenerationTaskUseCase:
"""GetGenerationTaskUseCase 测试"""
def test_get_task_success(self, mock_repo, sample_task):
"""获取任务成功"""
mock_repo.get.return_value = sample_task
use_case = GetGenerationTaskUseCase(mock_repo)
result = use_case.execute("task_001")
assert result is sample_task
mock_repo.get.assert_called_once_with("task_001")
def test_get_task_not_found(self, mock_repo):
"""任务不存在返回 None"""
mock_repo.get.return_value = None
use_case = GetGenerationTaskUseCase(mock_repo)
result = use_case.execute("nonexistent")
assert result is None
class TestListUserTasksFilteredUseCase:
"""ListUserTasksFilteredUseCase 测试"""
def test_list_without_filter(self, mock_repo, sample_task):
"""不带筛选条件查询"""
mock_repo.list_by_user_filtered.return_value = [sample_task]
mock_repo.count_by_user_filtered.return_value = 1
use_case = ListUserTasksFilteredUseCase(mock_repo)
result = use_case.execute("user_001")
assert isinstance(result, ListGenerationTasksResult)
assert len(result.items) == 1
assert result.total == 1
mock_repo.list_by_user_filtered.assert_called_once_with("user_001", status=None, limit=None, offset=0)
def test_list_with_status_filter(self, mock_repo):
"""按状态筛选"""
mock_repo.list_by_user_filtered.return_value = []
mock_repo.count_by_user_filtered.return_value = 0
use_case = ListUserTasksFilteredUseCase(mock_repo)
result = use_case.execute("user_001", status="completed")
assert result.total == 0
mock_repo.list_by_user_filtered.assert_called_once_with("user_001", status="completed", limit=None, offset=0)
def test_list_with_pagination(self, mock_repo):
"""带分页参数查询"""
mock_repo.list_by_user_filtered.return_value = []
mock_repo.count_by_user_filtered.return_value = 50
use_case = ListUserTasksFilteredUseCase(mock_repo)
result = use_case.execute("user_001", limit=10, offset=20)
assert result.total == 50
mock_repo.list_by_user_filtered.assert_called_once_with("user_001", status=None, limit=10, offset=20)
def test_list_with_all_params(self, mock_repo):
"""带所有筛选和分页参数"""
mock_repo.list_by_user_filtered.return_value = []
mock_repo.count_by_user_filtered.return_value = 5
use_case = ListUserTasksFilteredUseCase(mock_repo)
use_case.execute("user_001", status="failed", limit=20, offset=0)
mock_repo.list_by_user_filtered.assert_called_once_with("user_001", status="failed", limit=20, offset=0)
mock_repo.count_by_user_filtered.assert_called_once_with("user_001", status="failed")
class TestRetryGenerationTaskUseCase:
"""RetryGenerationTaskUseCase 测试"""
def test_retry_failed_task(self, mock_repo):
"""重试失败的任务"""
task = MagicMock(spec=GenerationTask)
task.is_failed = True
mock_repo.get.return_value = task
mock_repo.update.return_value = task
use_case = RetryGenerationTaskUseCase(mock_repo)
result = use_case.execute("task_001")
task.mark_pending_from_failed.assert_called_once()
mock_repo.update.assert_called_once_with(task)
assert result is task
def test_retry_not_found(self, mock_repo):
"""任务不存在抛出 ValueError"""
mock_repo.get.return_value = None
use_case = RetryGenerationTaskUseCase(mock_repo)
with pytest.raises(ValueError, match="任务不存在"):
use_case.execute("nonexistent")
mock_repo.update.assert_not_called()
def test_retry_non_failed_task(self, mock_repo):
"""非失败状态的任务不能重试"""
task = MagicMock(spec=GenerationTask)
task.is_failed = False
task.status = MagicMock()
task.status.value = "running"
mock_repo.get.return_value = task
use_case = RetryGenerationTaskUseCase(mock_repo)
with pytest.raises(ValueError, match="只有失败状态的任务才能重试"):
use_case.execute("task_001")
mock_repo.update.assert_not_called()
task.mark_pending_from_failed.assert_not_called()