Files
tick-stock-panel/backend/tests/test_ext_pull_timeout_config.py
T

113 lines
3.7 KiB
Python

"""扩展数据拉取的每配置超时 (PullConfig.timeout_seconds)。
历史行为是三处硬编码 30s: 大响应接口 (如全量集合竞价 /day, 实测 ~77s) 会超时。
现在超时进配置, 默认 30 与旧行为完全一致; 拉取 (_request_json) 与
URL 探测 (detect-url) 都读它。老 config.json 无该字段 → 默认 30, 手改非法值 → 归一 30。
"""
from __future__ import annotations
from types import SimpleNamespace
import pytest
from app.services import ext_pull
from app.services.ext_data import PullConfig
# ── 模型: 默认值 / 序列化 / 非法值归一 ──────────────────────────────
def test_timeout_defaults_to_30_and_roundtrips():
assert PullConfig().timeout_seconds == 30
assert PullConfig(timeout_seconds=90).timeout_seconds == 90
d = PullConfig(url="https://x", timeout_seconds=120).to_dict()
assert d["timeout_seconds"] == 120
assert PullConfig.from_dict(d).timeout_seconds == 120
def test_timeout_missing_in_old_config_falls_back_to_30():
legacy = PullConfig(url="https://x").to_dict()
del legacy["timeout_seconds"] # 模拟旧版本 config.json
assert PullConfig.from_dict(legacy).timeout_seconds == 30
@pytest.mark.parametrize("bad", [0, -5, 3, 301, 9999, "abc", None])
def test_timeout_invalid_values_normalized_to_30(bad):
assert PullConfig(timeout_seconds=bad).timeout_seconds == 30
# ── 拉取路径: _request_json 把配置超时传给 httpx ─────────────────────
class _FakeResponse:
def raise_for_status(self):
pass
def json(self):
return {"items": [{"symbol": "600000.SH"}]}
class _FakeClient:
"""捕获每次请求的 timeout。"""
last_timeout: object = None
request_timeout: object = None
def __init__(self, timeout=None, **kwargs):
_FakeClient.last_timeout = timeout
async def __aenter__(self):
return self
async def __aexit__(self, *exc):
return False
async def request(self, method, url, **kwargs):
_FakeClient.request_timeout = kwargs.get("timeout")
return _FakeResponse()
async def test_request_json_uses_configured_timeout(monkeypatch):
monkeypatch.setattr(ext_pull.httpx, "AsyncClient", _FakeClient)
pull = PullConfig(url="https://x", timeout_seconds=90)
await ext_pull._request_json(pull, "cfg1")
assert _FakeClient.request_timeout == 90
async def test_request_json_defaults_to_30_without_attr(monkeypatch):
monkeypatch.setattr(ext_pull.httpx, "AsyncClient", _FakeClient)
# 测试用的简化 pull 对象没有 timeout_seconds 属性 → 兜底 30
pull = SimpleNamespace(
url="https://x", date_param=None, date_format="iso", headers=None,
method="GET", body=None, auth=None,
)
await ext_pull._request_json(pull, "cfg1")
assert _FakeClient.request_timeout == 30
# ── 探测路径: detect-url 请求体带 timeout_seconds ───────────────────
async def test_detect_url_uses_request_timeout(monkeypatch):
import httpx
from app.api import ext_data as ext_api
monkeypatch.setattr(httpx, "AsyncClient", _FakeClient)
resp = await ext_api.detect_url(ext_api.DetectUrlReq(
url="https://x", response_path="items", timeout_seconds=120,
))
assert _FakeClient.last_timeout == 120
assert resp["status"] == "ok"
async def test_detect_url_timeout_defaults_to_30(monkeypatch):
import httpx
from app.api import ext_data as ext_api
monkeypatch.setattr(httpx, "AsyncClient", _FakeClient)
await ext_api.detect_url(ext_api.DetectUrlReq(url="https://x", response_path="items"))
assert _FakeClient.last_timeout == 30