81 lines
2.5 KiB
Python
81 lines
2.5 KiB
Python
# tests/test_supplemental_orderbook.py
|
|
import asyncio
|
|
import json
|
|
import pytest
|
|
from unittest.mock import AsyncMock, MagicMock, patch
|
|
from hydra.supplemental.orderbook import OrderBookPoller
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_redis():
|
|
r = MagicMock()
|
|
r.keys = MagicMock(return_value=[
|
|
"hydra:indicator:binance:BTC/USDT:1m",
|
|
"hydra:indicator:binance:ETH/USDT:1h",
|
|
])
|
|
r.set = AsyncMock()
|
|
return r
|
|
|
|
|
|
@pytest.fixture
|
|
def poller(mock_redis):
|
|
return OrderBookPoller(redis_client=mock_redis, interval_sec=1)
|
|
|
|
|
|
def test_get_active_symbols_deduplicates(poller, mock_redis):
|
|
mock_redis.keys = MagicMock(return_value=[
|
|
"hydra:indicator:binance:BTC/USDT:1m",
|
|
"hydra:indicator:binance:BTC/USDT:1h",
|
|
"hydra:indicator:binance:ETH/USDT:1m",
|
|
])
|
|
symbols = poller._get_active_symbols()
|
|
assert ("binance", "BTC/USDT") in symbols
|
|
assert ("binance", "ETH/USDT") in symbols
|
|
assert len(symbols) == 2
|
|
|
|
|
|
def test_fetch_one_returns_orderbook(poller):
|
|
mock_ob = {
|
|
"bids": [[49998.0, 1.5], [49997.0, 2.0]],
|
|
"asks": [[50002.0, 1.2], [50003.0, 1.8]],
|
|
}
|
|
mock_exchange = MagicMock()
|
|
mock_exchange.fetch_order_book.return_value = mock_ob
|
|
poller._get_exchange = MagicMock(return_value=mock_exchange)
|
|
result = poller._fetch_one("binance", "BTC/USDT")
|
|
assert result is not None
|
|
assert result["bid"] == 49998.0
|
|
assert result["ask"] == 50002.0
|
|
assert "spread_pct" in result
|
|
assert "ts" in result
|
|
|
|
|
|
def test_fetch_one_returns_none_on_error(poller):
|
|
mock_exchange = MagicMock()
|
|
mock_exchange.fetch_order_book.side_effect = Exception("connection error")
|
|
poller._get_exchange = MagicMock(return_value=mock_exchange)
|
|
result = poller._fetch_one("binance", "BTC/USDT")
|
|
assert result is None
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_run_writes_redis(poller, mock_redis):
|
|
mock_ob = {
|
|
"bids": [[49998.0, 1.5]],
|
|
"asks": [[50002.0, 1.2]],
|
|
}
|
|
mock_exchange = MagicMock()
|
|
mock_exchange.fetch_order_book.return_value = mock_ob
|
|
poller._get_exchange = MagicMock(return_value=mock_exchange)
|
|
with patch("hydra.supplemental.orderbook.asyncio.sleep",
|
|
side_effect=asyncio.CancelledError):
|
|
try:
|
|
await poller.run()
|
|
except asyncio.CancelledError:
|
|
pass
|
|
assert mock_redis.set.call_count == 2 # BTC/USDT and ETH/USDT
|
|
key = mock_redis.set.call_args_list[0][0][0]
|
|
assert key.startswith("hydra:orderbook:binance:")
|
|
data = json.loads(mock_redis.set.call_args_list[0][0][1])
|
|
assert "bid" in data
|