"""SafetySellConfig env-var parsing tests (REQ-041 / BAT-010).""" from __future__ import annotations import pytest from trex_core.runtime.config import DaemonConfig, SafetySellConfig _SAFETY_KEYS = ( "TREX_WATCHDOG_TIMEOUT", "TREX_WATCHDOG_GRACE_PERIOD", "TREX_FORCED_CLOSE_CHECK_INTERVAL", "TREX_STOP_LOSS_POLL_INTERVAL", "TREX_MARKET_CLOSE_LIQUIDATION_TIME", "TREX_SAFETY_SELL_MIN_RETRY_INTERVAL", "TREX_SAFETY_SELL_MAX_RETRY_WARN_COUNT", ) @pytest.fixture(autouse=True) def _clean_env(monkeypatch): for k in _SAFETY_KEYS: monkeypatch.delenv(k, raising=False) @pytest.fixture def _base_env(monkeypatch): monkeypatch.setenv("TREX_POSTGRESQL_DSN", "dbname=x") def test_safety_sell_config_defaults(tmp_path, monkeypatch, _base_env): """AC-1: unset env vars produce documented defaults.""" monkeypatch.chdir(tmp_path) cfg = DaemonConfig.from_env() ss = cfg.safety_sell assert ss.watchdog_timeout_sec == 120 assert ss.watchdog_grace_period_sec == 60 assert ss.forced_close_check_interval_sec == 60 assert ss.stop_loss_poll_interval_sec == 30 assert ss.market_close_liquidation_time is None # BAT-014 / REQ-053 assert ss.min_retry_interval_sec == 600 assert ss.max_retry_warn_count == 3 def test_retry_cooldown_env_tuning(tmp_path, monkeypatch, _base_env): """REQ-053 AC-2: retry cooldown env vars are parsed.""" monkeypatch.chdir(tmp_path) monkeypatch.setenv("TREX_SAFETY_SELL_MIN_RETRY_INTERVAL", "300") monkeypatch.setenv("TREX_SAFETY_SELL_MAX_RETRY_WARN_COUNT", "5") ss = DaemonConfig.from_env().safety_sell assert ss.min_retry_interval_sec == 300 assert ss.max_retry_warn_count == 5 def test_safety_sell_config_env_tuning(tmp_path, monkeypatch, _base_env): """AC-2~5: all five env vars are parsed correctly.""" monkeypatch.chdir(tmp_path) monkeypatch.setenv("TREX_WATCHDOG_TIMEOUT", "180") monkeypatch.setenv("TREX_WATCHDOG_GRACE_PERIOD", "90") monkeypatch.setenv("TREX_FORCED_CLOSE_CHECK_INTERVAL", "45") monkeypatch.setenv("TREX_STOP_LOSS_POLL_INTERVAL", "15") monkeypatch.setenv("TREX_MARKET_CLOSE_LIQUIDATION_TIME", "15:30") cfg = DaemonConfig.from_env() ss = cfg.safety_sell assert ss.watchdog_timeout_sec == 180 assert ss.watchdog_grace_period_sec == 90 assert ss.forced_close_check_interval_sec == 45 assert ss.stop_loss_poll_interval_sec == 15 assert ss.market_close_liquidation_time == "15:30" def test_market_close_liquidation_time_empty_string_becomes_none(tmp_path, monkeypatch, _base_env): """Empty string for optional field collapses to None.""" monkeypatch.chdir(tmp_path) monkeypatch.setenv("TREX_MARKET_CLOSE_LIQUIDATION_TIME", "") cfg = DaemonConfig.from_env() assert cfg.safety_sell.market_close_liquidation_time is None def test_safety_sell_config_is_frozen(): """SafetySellConfig is a frozen dataclass.""" ss = SafetySellConfig() with pytest.raises((AttributeError, TypeError)): ss.watchdog_timeout_sec = 999 # type: ignore[misc]