"""Tests for voice_ids fallback in _download_all_assets. When voice_library_id is empty but voice_ids is non-empty, the Worker should fallback to voice_ids[0] as the audio asset_id. """ from pathlib import Path from unittest.mock import MagicMock, patch import pytest class TestDownloadAllAssetsVoiceIdsFallback: """_download_all_assets 配音下载 fallback 逻辑测试。""" @patch("worker_app.tasks.generation._download_voice_asset") @patch("worker_app.tasks.generation._download_library_assets") def test_voice_library_id_takes_priority(self, mock_download_videos, mock_download_voice, tmp_path): """voice_library_id 存在时优先使用,不 fallback 到 voice_ids。""" from worker_app.tasks.generation import _download_all_assets mock_download_videos.return_value = [tmp_path / "v1.mp4"] mock_download_voice.return_value = True videos, audio = _download_all_assets( temp_path=tmp_path, asset_library_id="lib-1", project_id="proj-1", task_asset_ids=["a1"], voice_library_id="voice-lib-123", task_id="task-1", voice_ids=["voice-ids-456"], ) assert audio is not None mock_download_voice.assert_called_once() call_args = mock_download_voice.call_args assert call_args[0][0] == "voice-lib-123" # first positional arg @patch("worker_app.tasks.generation._download_voice_asset") @patch("worker_app.tasks.generation._download_library_assets") def test_fallback_to_voice_ids_when_voice_library_id_empty( self, mock_download_videos, mock_download_voice, tmp_path ): """voice_library_id 为空时 fallback 到 voice_ids[0]。""" from worker_app.tasks.generation import _download_all_assets mock_download_videos.return_value = [tmp_path / "v1.mp4"] mock_download_voice.return_value = True videos, audio = _download_all_assets( temp_path=tmp_path, asset_library_id="lib-1", project_id="proj-1", task_asset_ids=["a1"], voice_library_id="", # 空字符串 task_id="task-2", voice_ids=["voice-asset-789"], ) assert audio is not None mock_download_voice.assert_called_once() call_args = mock_download_voice.call_args assert call_args[0][0] == "voice-asset-789" @patch("worker_app.tasks.generation._download_voice_asset") @patch("worker_app.tasks.generation._download_library_assets") def test_no_audio_when_both_empty(self, mock_download_videos, mock_download_voice, tmp_path): """voice_library_id 和 voice_ids 都为空时,不下载音频。""" from worker_app.tasks.generation import _download_all_assets mock_download_videos.return_value = [tmp_path / "v1.mp4"] videos, audio = _download_all_assets( temp_path=tmp_path, asset_library_id="lib-1", project_id="proj-1", task_asset_ids=["a1"], voice_library_id="", task_id="task-3", voice_ids=[], ) assert audio is None mock_download_voice.assert_not_called() @patch("worker_app.tasks.generation._download_voice_asset") @patch("worker_app.tasks.generation._download_library_assets") def test_no_audio_when_voice_ids_none(self, mock_download_videos, mock_download_voice, tmp_path): """voice_ids 为 None 时,不触发 fallback。""" from worker_app.tasks.generation import _download_all_assets mock_download_videos.return_value = [tmp_path / "v1.mp4"] videos, audio = _download_all_assets( temp_path=tmp_path, asset_library_id="lib-1", project_id="proj-1", task_asset_ids=["a1"], voice_library_id="", task_id="task-4", voice_ids=None, ) assert audio is None mock_download_voice.assert_not_called() @patch("worker_app.tasks.generation._download_voice_asset") @patch("worker_app.tasks.generation._download_library_assets") def test_voice_library_id_empty_string_fallback(self, mock_download_videos, mock_download_voice, tmp_path): """voice_library_id 为空字符串且 voice_ids 有多个元素时,取第一个。""" from worker_app.tasks.generation import _download_all_assets mock_download_videos.return_value = [tmp_path / "v1.mp4"] mock_download_voice.return_value = True videos, audio = _download_all_assets( temp_path=tmp_path, asset_library_id="lib-1", project_id="proj-1", task_asset_ids=["a1"], voice_library_id="", task_id="task-5", voice_ids=["first-id", "second-id", "third-id"], ) assert audio is not None call_args = mock_download_voice.call_args assert call_args[0][0] == "first-id" @patch("worker_app.tasks.generation._download_voice_asset") @patch("worker_app.tasks.generation._download_library_assets") def test_backward_compat_no_voice_ids_param(self, mock_download_videos, mock_download_voice, tmp_path): """不传 voice_ids 参数时,行为与之前一致(向后兼容)。""" from worker_app.tasks.generation import _download_all_assets mock_download_videos.return_value = [tmp_path / "v1.mp4"] mock_download_voice.return_value = True # 不传 voice_ids videos, audio = _download_all_assets( temp_path=tmp_path, asset_library_id="lib-1", project_id="proj-1", task_asset_ids=["a1"], voice_library_id="voice-lib-999", task_id="task-6", ) assert audio is not None mock_download_voice.assert_called_once_with("voice-lib-999", tmp_path / "voice.mp3")