a3967c6829
CI/CD Pipeline / Validate Code Quality And Tests (pull_request) Failing after 6s
CI/CD Pipeline / Unit Tests (pull_request) Failing after 10s
CI/CD Pipeline / Frontend Lint (pull_request) Failing after 1m6s
CI/CD Pipeline / Build Production Runtime Images (pull_request) Has been skipped
CI/CD Pipeline / Build & Push Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Failing after 28m22s
1. Remove unused aiosmtplib dependency from requirements.txt
2. Remove 5 unused config items (API_PREFIX, REDIS_MAX_CONNECTION,
JWT_SECRET_KEY_OLD, SECRET_ROTATION_DAYS, LOG_LEVEL) from config.py,
.env.production.example, and init_production_env.sh.
Kept ENABLE_REDIS_SESSIONS (actively used in dependencies.py).
3. Fix project permission check TODOs in test_error_scenarios.py —
permissions are implemented, updated assertions to expect 403.
4. Merge two Storage implementations into shared package:
- packages/shared/storage.py: merged API features (HTTPS endpoint
fix, diagnose(), detailed logging) into SharedStorageService
- apps/api/app/core/storage.py: thin re-export wrapper for
backward compatibility
- Updated test mocks to target packages.shared.storage
92 lines
3.3 KiB
Python
Executable File
92 lines
3.3 KiB
Python
Executable File
"""测试音频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,
|
||
)
|