Build 060.25: implement Production Runtime Integration
This commit is contained in:
202
app/tests/unit/core/test_config.py
Normal file
202
app/tests/unit/core/test_config.py
Normal file
@@ -0,0 +1,202 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
|
||||
from src.core.config import load_settings
|
||||
|
||||
|
||||
_TRADE_STREAM_VARIABLES = (
|
||||
"TRADE_STREAM_ENABLED",
|
||||
"TRADE_STREAM_WS_URL",
|
||||
"TRADE_STREAM_SYMBOLS",
|
||||
"TRADE_STREAM_OPEN_TIMEOUT_SECONDS",
|
||||
"TRADE_STREAM_PROBE_TIMEOUT_SECONDS",
|
||||
"TRADE_STREAM_CLOSE_TIMEOUT_SECONDS",
|
||||
"TRADE_STREAM_HEARTBEAT_TIMEOUT_SECONDS",
|
||||
"TRADE_STREAM_SCHEDULER_INTERVAL_SECONDS",
|
||||
"TRADE_STREAM_RECOVERY_WINDOW_MS",
|
||||
)
|
||||
|
||||
|
||||
def prepare_environment(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
monkeypatch.setenv("BOT_TOKEN", "test-token")
|
||||
monkeypatch.delenv("EXCHANGE_BASE_URL", raising=False)
|
||||
monkeypatch.delenv("EXCHANGE_ENABLED", raising=False)
|
||||
|
||||
for variable in _TRADE_STREAM_VARIABLES:
|
||||
monkeypatch.delenv(variable, raising=False)
|
||||
|
||||
|
||||
def enable_trade_stream(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
monkeypatch.setenv("TRADE_STREAM_ENABLED", "true")
|
||||
monkeypatch.setenv(
|
||||
"TRADE_STREAM_WS_URL",
|
||||
"wss://stream.example.test",
|
||||
)
|
||||
monkeypatch.setenv(
|
||||
"TRADE_STREAM_SYMBOLS",
|
||||
"ETH/USD_LEVERAGE,BTC/USD_LEVERAGE",
|
||||
)
|
||||
monkeypatch.setenv(
|
||||
"EXCHANGE_BASE_URL",
|
||||
"https://rest.example.test",
|
||||
)
|
||||
|
||||
|
||||
def test_trade_stream_is_disabled_by_default(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
prepare_environment(monkeypatch)
|
||||
monkeypatch.setenv("EXCHANGE_ENABLED", "true")
|
||||
|
||||
settings = load_settings()
|
||||
|
||||
assert settings.exchange_enabled is True
|
||||
assert settings.trade_stream.enabled is False
|
||||
assert settings.trade_stream.websocket_url == ""
|
||||
assert settings.trade_stream.symbols == ()
|
||||
|
||||
|
||||
def test_disabled_trade_stream_ignores_dependent_values(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
prepare_environment(monkeypatch)
|
||||
monkeypatch.setenv("TRADE_STREAM_OPEN_TIMEOUT_SECONDS", "invalid")
|
||||
monkeypatch.setenv("TRADE_STREAM_SYMBOLS", ",")
|
||||
|
||||
settings = load_settings()
|
||||
|
||||
assert settings.trade_stream.enabled is False
|
||||
|
||||
|
||||
def test_trade_stream_flag_is_strict(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
prepare_environment(monkeypatch)
|
||||
monkeypatch.setenv("TRADE_STREAM_ENABLED", "sometimes")
|
||||
|
||||
with pytest.raises(
|
||||
ValueError,
|
||||
match="TRADE_STREAM_ENABLED",
|
||||
):
|
||||
load_settings()
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("missing_variable", "message"),
|
||||
(
|
||||
(
|
||||
"TRADE_STREAM_WS_URL",
|
||||
"TRADE_STREAM_WS_URL",
|
||||
),
|
||||
(
|
||||
"TRADE_STREAM_SYMBOLS",
|
||||
"TRADE_STREAM_SYMBOLS",
|
||||
),
|
||||
(
|
||||
"EXCHANGE_BASE_URL",
|
||||
"EXCHANGE_BASE_URL",
|
||||
),
|
||||
),
|
||||
)
|
||||
def test_enabled_trade_stream_requires_explicit_endpoints_and_symbols(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
missing_variable: str,
|
||||
message: str,
|
||||
) -> None:
|
||||
prepare_environment(monkeypatch)
|
||||
enable_trade_stream(monkeypatch)
|
||||
monkeypatch.setenv(
|
||||
"EXCHANGE_WS_URL",
|
||||
"wss://legacy-fallback.example.test",
|
||||
)
|
||||
monkeypatch.setenv(
|
||||
"DEFAULT_SYMBOL",
|
||||
"LEGACY_FALLBACK",
|
||||
)
|
||||
monkeypatch.delenv(missing_variable)
|
||||
|
||||
with pytest.raises(
|
||||
RuntimeError,
|
||||
match=message,
|
||||
):
|
||||
load_settings()
|
||||
|
||||
|
||||
def test_enabled_trade_stream_parses_independent_settings(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
prepare_environment(monkeypatch)
|
||||
enable_trade_stream(monkeypatch)
|
||||
monkeypatch.setenv(
|
||||
"TRADE_STREAM_SYMBOLS",
|
||||
" ETH/USD_LEVERAGE, BTC/USD_LEVERAGE,ETH/USD_LEVERAGE ",
|
||||
)
|
||||
monkeypatch.setenv("TRADE_STREAM_OPEN_TIMEOUT_SECONDS", "11.5")
|
||||
monkeypatch.setenv("TRADE_STREAM_PROBE_TIMEOUT_SECONDS", "21")
|
||||
monkeypatch.setenv("TRADE_STREAM_CLOSE_TIMEOUT_SECONDS", "9")
|
||||
monkeypatch.setenv("TRADE_STREAM_HEARTBEAT_TIMEOUT_SECONDS", "31")
|
||||
monkeypatch.setenv("TRADE_STREAM_SCHEDULER_INTERVAL_SECONDS", "6")
|
||||
monkeypatch.setenv("TRADE_STREAM_RECOVERY_WINDOW_MS", "123456")
|
||||
|
||||
settings = load_settings()
|
||||
trade_stream = settings.trade_stream
|
||||
|
||||
assert trade_stream.enabled is True
|
||||
assert trade_stream.websocket_url == "wss://stream.example.test"
|
||||
assert trade_stream.symbols == (
|
||||
"BTC/USD_LEVERAGE",
|
||||
"ETH/USD_LEVERAGE",
|
||||
)
|
||||
assert trade_stream.open_timeout_seconds == 11.5
|
||||
assert trade_stream.probe_timeout_seconds == 21.0
|
||||
assert trade_stream.close_timeout_seconds == 9.0
|
||||
assert trade_stream.heartbeat_timeout_seconds == 31.0
|
||||
assert trade_stream.scheduler_interval_seconds == 6.0
|
||||
assert trade_stream.recovery_window_ms == 123_456
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("variable", "value"),
|
||||
(
|
||||
("TRADE_STREAM_OPEN_TIMEOUT_SECONDS", "0"),
|
||||
("TRADE_STREAM_PROBE_TIMEOUT_SECONDS", "-1"),
|
||||
("TRADE_STREAM_CLOSE_TIMEOUT_SECONDS", "nan"),
|
||||
("TRADE_STREAM_HEARTBEAT_TIMEOUT_SECONDS", "inf"),
|
||||
("TRADE_STREAM_SCHEDULER_INTERVAL_SECONDS", "invalid"),
|
||||
("TRADE_STREAM_RECOVERY_WINDOW_MS", "1.5"),
|
||||
("TRADE_STREAM_RECOVERY_WINDOW_MS", "0"),
|
||||
),
|
||||
)
|
||||
def test_enabled_trade_stream_rejects_invalid_numeric_settings(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
variable: str,
|
||||
value: str,
|
||||
) -> None:
|
||||
prepare_environment(monkeypatch)
|
||||
enable_trade_stream(monkeypatch)
|
||||
monkeypatch.setenv(variable, value)
|
||||
|
||||
with pytest.raises(ValueError, match=variable):
|
||||
load_settings()
|
||||
|
||||
|
||||
def test_symbols_must_not_contain_empty_items(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
prepare_environment(monkeypatch)
|
||||
enable_trade_stream(monkeypatch)
|
||||
monkeypatch.setenv(
|
||||
"TRADE_STREAM_SYMBOLS",
|
||||
"BTC/USD_LEVERAGE,,ETH/USD_LEVERAGE",
|
||||
)
|
||||
|
||||
with pytest.raises(
|
||||
ValueError,
|
||||
match="empty symbols",
|
||||
):
|
||||
load_settings()
|
||||
Reference in New Issue
Block a user