"""测试音频URL预签名逻辑。 验证所有 API 返回的音频 URL 都会经过 OSS 预签名(24小时有效期), 确保私有 bucket 下的音频文件前端可正常访问。 """ from __future__ import annotations from unittest.mock import MagicMock, patch class TestAudioUrlSigner: """测试音频URL签名函数的行为。""" def _make_signer(self, mock_storage): """构造一个签名函数(模拟 get_audio_url_signer 的逻辑)。""" def sign_audio_url(url: str) -> str: if not url: return url return mock_storage.get_download_url(url, expires_seconds=86400) return sign_audio_url def test_empty_url_returns_empty(self): """空URL直接返回,不调用签名。""" mock_storage = MagicMock() signer = self._make_signer(mock_storage) result = signer("") assert result == "" mock_storage.get_download_url.assert_not_called() def test_none_url_returns_none(self): """None URL直接返回(有些字段可能为None)。""" mock_storage = MagicMock() signer = self._make_signer(mock_storage) result = signer(None) # type: ignore assert result is None mock_storage.get_download_url.assert_not_called() def test_valid_url_gets_signed_24h(self): """有效URL会调用 storage.get_download_url,有效期24小时(86400秒)。""" mock_storage = MagicMock() mock_storage.get_download_url.return_value = ( "https://bucket.oss-cn-hangzhou.aliyuncs.com/audio/test.mp3?signature=xxx" ) signer = self._make_signer(mock_storage) result = signer("https://bucket.oss-cn-hangzhou.aliyuncs.com/audio/test.mp3") assert "signature=xxx" in result mock_storage.get_download_url.assert_called_once_with( "https://bucket.oss-cn-hangzhou.aliyuncs.com/audio/test.mp3", expires_seconds=86400, ) def test_storage_key_format_also_works(self): """纯 storage key 格式也能正常签名(storage内部会处理)。""" mock_storage = MagicMock() mock_storage.get_download_url.return_value = "https://signed-url/audio.mp3?sig=xxx" signer = self._make_signer(mock_storage) result = signer("audio/test.mp3") assert result == "https://signed-url/audio.mp3?sig=xxx" mock_storage.get_download_url.assert_called_once_with( "audio/test.mp3", expires_seconds=86400, ) def test_signer_via_dependencies_module(self): """通过 dependencies 模块获取 signer,验证集成正确。""" from app.core.storage import OSSStorageService mock_svc = MagicMock(spec=OSSStorageService) mock_svc.get_download_url.return_value = "https://signed/a.mp3?sig=123" # 替换全局单例(现在位于 packages.shared.storage) with patch("packages.shared.storage._storage_service", mock_svc): from app.dependencies import get_audio_url_signer signer = get_audio_url_signer() result = signer("test/audio.mp3") assert result == "https://signed/a.mp3?sig=123" mock_svc.get_download_url.assert_called_once_with( "test/audio.mp3", expires_seconds=86400, )