206 lines
4.8 KiB
Python
206 lines
4.8 KiB
Python
from __future__ import annotations
|
|
|
|
from types import SimpleNamespace
|
|
|
|
import pytest
|
|
|
|
import src.bootstrap.app_factory as app_factory
|
|
from src.bootstrap.application import ApplicationComposition
|
|
|
|
|
|
class RecordingJournal:
|
|
def __init__(self) -> None:
|
|
self.info_calls: list[
|
|
tuple[str, str, dict[str, object]]
|
|
] = []
|
|
|
|
def log_info(
|
|
self,
|
|
event: str,
|
|
message: str,
|
|
context: dict[str, object],
|
|
) -> None:
|
|
self.info_calls.append(
|
|
(
|
|
event,
|
|
message,
|
|
context,
|
|
)
|
|
)
|
|
|
|
def log_critical(
|
|
self,
|
|
event: str,
|
|
message: str,
|
|
context: dict[str, object],
|
|
) -> None:
|
|
del event, message, context
|
|
|
|
|
|
def make_settings() -> SimpleNamespace:
|
|
return SimpleNamespace(
|
|
bot_token="test-token",
|
|
bot_parse_mode="HTML",
|
|
log_level="INFO",
|
|
app_env="test",
|
|
exchange_name="dzengi",
|
|
default_symbol="BTC/USD_LEVERAGE",
|
|
trade_stream=SimpleNamespace(enabled=True),
|
|
market_data_storage=SimpleNamespace(enabled=True),
|
|
)
|
|
|
|
|
|
def test_create_app_builds_one_application_composition(
|
|
monkeypatch: pytest.MonkeyPatch,
|
|
) -> None:
|
|
settings = make_settings()
|
|
bot = object()
|
|
dispatcher = object()
|
|
runtime = object()
|
|
storage_lifecycle = object()
|
|
storage_sink = object()
|
|
storage = SimpleNamespace(
|
|
lifecycle=storage_lifecycle,
|
|
trade_observation_sink=storage_sink,
|
|
)
|
|
journal = RecordingJournal()
|
|
observed_runtime_settings: list[object] = []
|
|
registered_bots: list[object] = []
|
|
routed_dispatchers: list[object] = []
|
|
|
|
monkeypatch.setattr(
|
|
app_factory,
|
|
"load_settings",
|
|
lambda: settings,
|
|
)
|
|
monkeypatch.setattr(
|
|
app_factory,
|
|
"setup_logging",
|
|
lambda level: None,
|
|
)
|
|
monkeypatch.setattr(
|
|
app_factory,
|
|
"init_schema",
|
|
lambda: None,
|
|
)
|
|
monkeypatch.setattr(
|
|
app_factory,
|
|
"JournalService",
|
|
lambda: journal,
|
|
)
|
|
|
|
monkeypatch.setattr(
|
|
app_factory,
|
|
"build_market_data_storage",
|
|
lambda received_settings: (
|
|
storage
|
|
if received_settings is settings
|
|
else None
|
|
),
|
|
)
|
|
|
|
def build_runtime(
|
|
received_settings: object,
|
|
*,
|
|
trade_observation_sink: object,
|
|
) -> object:
|
|
observed_runtime_settings.append(received_settings)
|
|
assert trade_observation_sink is storage_sink
|
|
return runtime
|
|
|
|
monkeypatch.setattr(
|
|
app_factory,
|
|
"build_trade_stream_production_runtime",
|
|
build_runtime,
|
|
)
|
|
monkeypatch.setattr(
|
|
app_factory,
|
|
"Bot",
|
|
lambda **kwargs: bot,
|
|
)
|
|
monkeypatch.setattr(
|
|
app_factory,
|
|
"Dispatcher",
|
|
lambda: dispatcher,
|
|
)
|
|
monkeypatch.setattr(
|
|
app_factory.NotificationTargetRegistry,
|
|
"set_bot",
|
|
registered_bots.append,
|
|
)
|
|
monkeypatch.setattr(
|
|
app_factory,
|
|
"setup_routers",
|
|
routed_dispatchers.append,
|
|
)
|
|
|
|
application = app_factory.create_app()
|
|
|
|
assert isinstance(application, ApplicationComposition)
|
|
assert application.bot is bot
|
|
assert application.dispatcher is dispatcher
|
|
assert application.trade_stream_runtime is runtime
|
|
assert (
|
|
application.market_data_storage_lifecycle
|
|
is storage_lifecycle
|
|
)
|
|
assert observed_runtime_settings == [settings]
|
|
assert registered_bots == [bot]
|
|
assert routed_dispatchers == [dispatcher]
|
|
assert journal.info_calls[0][2]["trade_stream_enabled"] is True
|
|
assert (
|
|
journal.info_calls[0][2]["market_data_storage_enabled"]
|
|
is True
|
|
)
|
|
|
|
|
|
def test_runtime_build_error_is_fatal(
|
|
monkeypatch: pytest.MonkeyPatch,
|
|
) -> None:
|
|
expected = RuntimeError("invalid Trade Stream settings")
|
|
|
|
monkeypatch.setattr(
|
|
app_factory,
|
|
"load_settings",
|
|
make_settings,
|
|
)
|
|
monkeypatch.setattr(
|
|
app_factory,
|
|
"setup_logging",
|
|
lambda level: None,
|
|
)
|
|
monkeypatch.setattr(
|
|
app_factory,
|
|
"init_schema",
|
|
lambda: None,
|
|
)
|
|
monkeypatch.setattr(
|
|
app_factory,
|
|
"JournalService",
|
|
RecordingJournal,
|
|
)
|
|
monkeypatch.setattr(
|
|
app_factory,
|
|
"build_market_data_storage",
|
|
lambda settings: None,
|
|
)
|
|
|
|
def fail_runtime_build(
|
|
settings: object,
|
|
*,
|
|
trade_observation_sink: object,
|
|
) -> None:
|
|
del settings, trade_observation_sink
|
|
raise expected
|
|
|
|
monkeypatch.setattr(
|
|
app_factory,
|
|
"build_trade_stream_production_runtime",
|
|
fail_runtime_build,
|
|
)
|
|
|
|
with pytest.raises(RuntimeError) as exc_info:
|
|
app_factory.create_app()
|
|
|
|
assert exc_info.value is expected
|