mirror of
https://ghfast.top/https://github.com/aeroxw/tick-stock-panel.git
synced 2026-09-12 15:34:16 +08:00
135 lines
4.6 KiB
Python
135 lines
4.6 KiB
Python
"""Custom depth provider routing and failure-isolation tests."""
|
|
from __future__ import annotations
|
|
|
|
from types import SimpleNamespace
|
|
from unittest.mock import MagicMock, call
|
|
|
|
from app.services import depth_service as depth_module
|
|
from app.services.depth_service import DepthService
|
|
from app.tickflow.capabilities import Cap, CapabilityLimits, CapabilitySet
|
|
|
|
|
|
def _service(*, batch: int = 2, rpm: int = 30) -> DepthService:
|
|
service = DepthService()
|
|
service._app_state = SimpleNamespace(
|
|
capabilities=CapabilitySet({
|
|
Cap.DEPTH5_BATCH: CapabilityLimits(batch=batch, rpm=rpm),
|
|
}),
|
|
)
|
|
return service
|
|
|
|
|
|
def test_custom_depth_uses_shared_batching_and_rate_limit(monkeypatch):
|
|
provider = SimpleNamespace(
|
|
get_depth_batch=MagicMock(
|
|
side_effect=lambda symbols: {symbol: {"ask_volumes": [0]} for symbol in symbols}
|
|
)
|
|
)
|
|
sleep = MagicMock()
|
|
monkeypatch.setattr(
|
|
"app.services.preferences.get_depth5_data_provider",
|
|
lambda: "custom_depth",
|
|
)
|
|
monkeypatch.setattr(
|
|
"app.data_providers.custom.provider_has_dataset",
|
|
lambda name, dataset: name == "custom_depth" and dataset == "depth5",
|
|
)
|
|
monkeypatch.setattr("app.data_providers.custom.get_provider", lambda name: provider)
|
|
monkeypatch.setattr(depth_module, "sleep_between_batches", sleep)
|
|
|
|
result = _service()._call_depth_batch(["A", "B", "C", "D", "E"])
|
|
|
|
assert set(result) == {"A", "B", "C", "D", "E"}
|
|
assert provider.get_depth_batch.call_args_list == [
|
|
call(["A", "B"]),
|
|
call(["C", "D"]),
|
|
call(["E"]),
|
|
]
|
|
assert sleep.call_args_list == [
|
|
call(0, 24, default_interval=2.0),
|
|
call(1, 24, default_interval=2.0),
|
|
call(2, 24, default_interval=2.0),
|
|
]
|
|
|
|
|
|
def test_custom_depth_failure_does_not_fall_back_to_tickflow(monkeypatch):
|
|
provider = SimpleNamespace(
|
|
get_depth_batch=MagicMock(side_effect=RuntimeError("custom source down"))
|
|
)
|
|
monkeypatch.setattr(
|
|
"app.services.preferences.get_depth5_data_provider",
|
|
lambda: "custom_depth",
|
|
)
|
|
monkeypatch.setattr(
|
|
"app.data_providers.custom.provider_has_dataset",
|
|
lambda name, dataset: True,
|
|
)
|
|
monkeypatch.setattr("app.data_providers.custom.get_provider", lambda name: provider)
|
|
monkeypatch.setattr(
|
|
"app.tickflow.client.get_client",
|
|
lambda: (_ for _ in ()).throw(AssertionError("must not fall back to TickFlow")),
|
|
)
|
|
|
|
assert _service()._call_depth_batch(["A"]) == {}
|
|
provider.get_depth_batch.assert_called_once_with(["A"])
|
|
|
|
|
|
def test_custom_depth_failure_isolated_per_batch(monkeypatch):
|
|
provider = SimpleNamespace(
|
|
get_depth_batch=MagicMock(
|
|
side_effect=[
|
|
RuntimeError("first batch down"),
|
|
{"C": {"ask_volumes": [0]}},
|
|
]
|
|
)
|
|
)
|
|
monkeypatch.setattr(
|
|
"app.services.preferences.get_depth5_data_provider",
|
|
lambda: "custom_depth",
|
|
)
|
|
monkeypatch.setattr(
|
|
"app.data_providers.custom.provider_has_dataset",
|
|
lambda name, dataset: True,
|
|
)
|
|
monkeypatch.setattr("app.data_providers.custom.get_provider", lambda name: provider)
|
|
monkeypatch.setattr(depth_module, "sleep_between_batches", MagicMock())
|
|
|
|
assert _service()._call_depth_batch(["A", "B", "C"]) == {
|
|
"C": {"ask_volumes": [0]},
|
|
}
|
|
assert provider.get_depth_batch.call_count == 2
|
|
|
|
|
|
def test_tickflow_depth_uses_provider_contract_and_shared_batching(monkeypatch):
|
|
batch = MagicMock(
|
|
side_effect=lambda symbols: {symbol: {"ask_volumes": [0]} for symbol in symbols}
|
|
)
|
|
tickflow = SimpleNamespace(depth=SimpleNamespace(batch=batch))
|
|
monkeypatch.setattr(
|
|
"app.services.preferences.get_depth5_data_provider",
|
|
lambda: "tickflow",
|
|
)
|
|
monkeypatch.setattr("app.data_providers.tickflow_provider.get_client", lambda: tickflow)
|
|
monkeypatch.setattr(depth_module, "sleep_between_batches", MagicMock())
|
|
|
|
result = _service()._call_depth_batch(["A", "B", "C"])
|
|
|
|
assert set(result) == {"A", "B", "C"}
|
|
assert batch.call_args_list == [call(["A", "B"]), call(["C"])]
|
|
|
|
|
|
def test_invalid_custom_depth_contract_fails_closed(monkeypatch):
|
|
monkeypatch.setattr(
|
|
"app.services.preferences.get_depth5_data_provider",
|
|
lambda: "broken_depth",
|
|
)
|
|
monkeypatch.setattr(
|
|
"app.data_providers.custom.provider_has_dataset",
|
|
lambda name, dataset: False,
|
|
)
|
|
get_provider = MagicMock()
|
|
monkeypatch.setattr("app.data_providers.custom.get_provider", get_provider)
|
|
|
|
assert _service()._call_depth_batch(["A"]) == {}
|
|
get_provider.assert_not_called()
|