Files
qlib/backend/tests/test_sina_provider.py
T
Simon 2da234220a feat(backend): Phase 1 数据层 — Domain / Provider / Failover 审计 + 持久化 + 同步 CLI
- domain:市场数据实体(Stock / 交易日历 / 日线 / 复权 / 财务含 announce_date)+ Repository 与 MarketDataProvider Protocol
- 数据源:TushareProvider(归一化、重试、鉴权错误归类)、SinaProvider(备用,明确前复权口径与能力边界)、FailoverProvider + SyncLog 审计(禁止静默切换)
- 持久化:SQLAlchemy 2.x Models + Repository 实现(按业务键幂等 upsert、as_of_date 防未来函数过滤)+ Alembic 迁移
- CLI:uv run python -m app.cli.sync {basic|calendar|daily|financial|verify},支持 --resume 断点续传
- 真实 Tushare 验证:stock 5556 / 交易日历 366 / daily+factor 242 / 财务 55;sync_log 审计完整
- 测试:38 passed(domain / provider / failover / repository / 未来函数 / 迁移),ruff clean
2026-09-06 16:59:28 +08:00

78 lines
2.4 KiB
Python

"""新浪 Provider 测试:代码转换、JSONP 解析、能力边界(不触网)。"""
from __future__ import annotations
from datetime import date
import pytest
from app.infrastructure.data_sources.errors import (
DataSourceError,
DataSourceNotSupported,
)
from app.infrastructure.data_sources.sina import SinaProvider, _extract_jsonp, _to_sina_symbol
_KLINE_OK = (
'var data=[{"day":"2024-08-30","open":"1700.0","high":"1720.0","low":"1690.0",'
'"close":"1710.0","volume":"20000"},{"day":"2024-08-31","open":"1710.0",'
'"high":"1725.0","low":"1705.0","close":"1720.0","volume":"18000"}]'
)
class _FakeResp:
def __enter__(self):
return self
def __exit__(self, *exc):
return False
def read(self):
return _KLINE_OK.encode("utf-8")
class _BoomResp(_FakeResp):
def read(self):
raise OSError("socket timeout")
class TestSymbolMap:
def test_mapping(self) -> None:
assert _to_sina_symbol("600519.SH") == "sh600519"
assert _to_sina_symbol("000001.SZ") == "sz000001"
assert _to_sina_symbol("830001.BJ") == "bj830001"
class TestJsonp:
def test_extract(self) -> None:
rows = _extract_jsonp(_KLINE_OK)
assert len(rows) == 2
assert rows[0]["close"] == "1710.0"
def test_bad_payload_raises(self) -> None:
with pytest.raises(DataSourceError, match="无法解析"):
_extract_jsonp("not jsonp")
class TestGetDaily:
def test_ok_with_date_filter(self) -> None:
provider = SinaProvider(urlopen=lambda _url, **kw: _FakeResp())
bars = provider.get_daily("600519.SH", date(2024, 8, 30), date(2024, 8, 30))
assert len(bars) == 1
assert bars[0].close is not None
assert bars[0].symbol == "600519.SH"
def test_network_error_wrapped(self) -> None:
provider = SinaProvider(urlopen=lambda _url, **kw: _BoomResp())
with pytest.raises(DataSourceError, match="sina 请求失败"):
provider.get_daily("600519.SH", date(2024, 8, 1), date(2024, 8, 31))
class TestCapabilities:
def test_not_supported(self) -> None:
provider = SinaProvider()
with pytest.raises(DataSourceNotSupported):
provider.get_stock_basic()
with pytest.raises(DataSourceNotSupported):
provider.get_adjust_factor("600519.SH", date(2024, 1, 1), date(2024, 1, 31))
with pytest.raises(DataSourceNotSupported):
provider.get_financial("600519.SH")