Files
fxhnt/tests/unit/test_ingest_historical_cli.py
2026-06-17 00:22:38 +02:00

88 lines
3.7 KiB
Python

"""B3a-deploy: the `ingest-historical` CLI entrypoint wires the historical-EOD ingest against the
DEDICATED backtest warehouse path (never the live cockpit warehouse) and honors --limit. No network:
the Tiingo clients are monkeypatched with fakes."""
from __future__ import annotations
from typer.testing import CliRunner
from fxhnt.config import Settings
def test_settings_has_backtest_warehouse_path_default() -> None:
s = Settings()
assert s.backtest_warehouse_path == "/backtest-data/warehouse.duckdb"
def test_settings_backtest_path_env_override(monkeypatch) -> None:
monkeypatch.setenv("FXHNT_BACKTEST_WAREHOUSE_PATH", "/tmp/bt.duckdb")
s = Settings()
assert s.backtest_warehouse_path == "/tmp/bt.duckdb"
class _FakeUniverse:
"""Survivorship-free set: three members; .survivorship_free() returns (sym, exch, start, end)."""
def survivorship_free(self):
return [
("AAA", "NYSE", "1990-01-02", "2026-06-01"),
("BBB", "NASDAQ", "1995-03-01", "2010-12-31"),
("CCC", "AMEX", "2000-06-15", "2026-06-01"),
]
class _FakeBars:
def bars(self, ticker, start_date=None):
return [{"date": "2020-01-02", "adjClose": 1.0, "close": 1.0, "volume": 100.0}]
def test_ingest_historical_builds_store_at_backtest_path_and_honors_limit(tmp_path, monkeypatch) -> None:
"""--limit N restricts to the first N tickers AND the ingest writes to the configured backtest path."""
import fxhnt.cli as cli
from fxhnt.adapters.warehouse.duckdb_feature_store import DuckDbFeatureStore
bt_path = tmp_path / "backtest" / "warehouse.duckdb"
monkeypatch.setenv("FXHNT_BACKTEST_WAREHOUSE_PATH", str(bt_path))
cli.get_settings.cache_clear() # the settings are lru_cached — pick up the env override
# Patch the concrete adapters the command imports (function-local imports -> patch at source module).
monkeypatch.setattr("fxhnt.adapters.data.tiingo_daily.TiingoDailyClient", lambda *a, **k: _FakeBars())
monkeypatch.setattr("fxhnt.adapters.data.tiingo_universe.TiingoUniverseSource", lambda *a, **k: _FakeUniverse())
result = CliRunner().invoke(cli.app, ["ingest-historical", "--limit", "2"])
cli.get_settings.cache_clear()
assert result.exit_code == 0, result.output
assert bt_path.exists(), "ingest must create the warehouse at the configured backtest path"
assert "2 ingested" in result.output # only the first 2 of 3 tickers (the --limit)
# The two limited tickers are in the dedicated warehouse; the third (CCC) is not.
store = DuckDbFeatureStore(str(bt_path))
try:
symbols = {row[0] for row in store.catalog()}
finally:
store.close()
assert symbols == {"AAA", "BBB"}
def test_ingest_historical_full_set_when_no_limit(tmp_path, monkeypatch) -> None:
"""No --limit (0) ingests the FULL survivorship-free set into the backtest warehouse."""
import fxhnt.cli as cli
from fxhnt.adapters.warehouse.duckdb_feature_store import DuckDbFeatureStore
bt_path = tmp_path / "warehouse.duckdb"
monkeypatch.setenv("FXHNT_BACKTEST_WAREHOUSE_PATH", str(bt_path))
cli.get_settings.cache_clear()
monkeypatch.setattr("fxhnt.adapters.data.tiingo_daily.TiingoDailyClient", lambda *a, **k: _FakeBars())
monkeypatch.setattr("fxhnt.adapters.data.tiingo_universe.TiingoUniverseSource", lambda *a, **k: _FakeUniverse())
result = CliRunner().invoke(cli.app, ["ingest-historical"])
cli.get_settings.cache_clear()
assert result.exit_code == 0, result.output
store = DuckDbFeatureStore(str(bt_path))
try:
symbols = {row[0] for row in store.catalog()}
finally:
store.close()
assert symbols == {"AAA", "BBB", "CCC"}