"""data_source 测试(mock _read_fn,不依赖 vnpy 链,spec §5/§3.3)。 read_parquet_15min 的真测试依赖 vnpy BarData + NAS parquet,本机无完整依赖, 在容器内冒烟(spec §17);本文件只测 iter_bars 调度逻辑。 """ import logging from datetime import datetime from types import SimpleNamespace import pytest from sanguo_trader.data_source import iter_bars def _mock_bar(sym: str, date_str: str, close: float): return SimpleNamespace( symbol=sym, datetime=datetime.strptime(date_str, "%Y-%m-%d"), close_price=close, ) def test_iter_bars_cross_section_multi_symbol(monkeypatch): def mock_read(sym, start, end, cfg): return [_mock_bar(sym, "2024-01-02", 10.5 if sym == "600000" else 15.5)] monkeypatch.setattr("sanguo_trader.data_source._read_fn", lambda iv: mock_read) sections = list(iter_bars(["600000", "000001"], "2024-01-01", "2024-01-31", "d")) assert len(sections) == 1 _date, d = sections[0] assert "600000" in d and "000001" in d assert d["600000"].close_price == 10.5 def test_iter_bars_raw_fallback_warning(monkeypatch, caplog): monkeypatch.setattr( "sanguo_trader.data_source._read_fn", lambda iv: lambda s, st, e, c: [], ) with caplog.at_level(logging.WARNING): list(iter_bars(["600000"], "2024-01-01", "2024-01-31", "d", adjust="raw")) assert "raw" in caplog.text def test_unsupported_interval_rejected(): with pytest.raises(ValueError): # _read_fn 在生成器首次 next 时才执行,用 list 触发 list(iter_bars(["600000"], "2024-01-01", "2024-01-31", "5m")) def test_fetch_day_returns_last_bar(monkeypatch): from sanguo_trader.data_source import fetch_day monkeypatch.setattr( "sanguo_trader.data_source._read_fn", lambda iv: lambda s, st, e, c: [_mock_bar(s, "2024-01-02", 10.0), _mock_bar(s, "2024-01-02", 10.5)], ) bar = fetch_day("600000", "2024-01-02", "d") assert bar.close_price == 10.5 # 取最后一个