# -*- coding: utf-8 -*- """音频流代理测试:签名校验、HEAD、Range 透传、无效 token。""" from typing import Any import pytest from fastapi import FastAPI from fastapi.testclient import TestClient from core import security from web.routers import stream as stream_router SECRET = 'stream-test-secret' PAYLOAD = b'AUDIO-DATA-' * 1000 # 11000 字节 @pytest.fixture() def client(monkeypatch): security.init_secret_key(SECRET) app = FastAPI() app.include_router(stream_router.router, prefix='/api/v1') class _Upstream: def __init__(self): self.status = 200 self.headers = {'Content-Type': 'audio/mpeg', 'Content-Length': str(len(PAYLOAD)), 'Accept-Ranges': 'bytes'} self.closed = False self.content = self async def iter_chunked(self, n): for i in range(0, len(PAYLOAD), n): yield PAYLOAD[i:i + n] def close(self): self.closed = True state: dict[str, Any] = {'last_range': None, 'upstream': None} async def fake_open(method, url, *, headers=None, timeout=None, **kw): state['last_range'] = (headers or {}).get('Range') up = _Upstream() if state['last_range']: up.status = 206 up.headers = dict(up.headers) up.headers['Content-Range'] = f'bytes 0-99/{len(PAYLOAD)}' state['upstream'] = up return up monkeypatch.setattr('web.routers.stream.http_client.open', fake_open) return TestClient(app), state def test_invalid_token(client): c, _ = client r = c.get('/api/v1/audio_stream?token=bogus') assert r.status_code == 403 def test_head_no_upstream(client): c, state = client r = c.head('/api/v1/audio_stream?token=x') assert r.status_code == 200 assert r.headers['accept-ranges'] == 'bytes' assert state['upstream'] is None # HEAD 不应请求上游 def test_stream_full(client): c, _ = client token = security.make_audio_token('http://m801.music.126.net/a.mp3') r = c.get(f'/api/v1/audio_stream?token={token}') assert r.status_code == 200 assert r.content == PAYLOAD assert r.headers['cache-control'] == 'no-store' assert r.headers['content-length'] == str(len(PAYLOAD)) def test_range_forwarded_and_206(client): c, state = client token = security.make_audio_token('http://m801.music.126.net/a.mp3') r = c.get(f'/api/v1/audio_stream?token={token}', headers={'Range': 'bytes=0-99'}) assert state['last_range'] == 'bytes=0-99' # Range 已透传上游 assert r.status_code == 206 assert 'content-range' in r.headers def test_upstream_closed_on_complete(client): c, state = client token = security.make_audio_token('http://m801.music.126.net/a.mp3') c.get(f'/api/v1/audio_stream?token={token}') assert state['upstream'].closed is True