136 lines
4.6 KiB
Python
136 lines
4.6 KiB
Python
|
|
"""Unit tests for pricing service."""
|
||
|
|
|
||
|
|
import pytest
|
||
|
|
from unittest.mock import Mock, patch, MagicMock
|
||
|
|
from decimal import Decimal
|
||
|
|
|
||
|
|
from src.data.pricing_service import PricingService, get_pricing_service
|
||
|
|
from src.data.providers.base_provider import BasePricingProvider
|
||
|
|
|
||
|
|
|
||
|
|
class MockProvider(BasePricingProvider):
|
||
|
|
"""Mock provider for testing."""
|
||
|
|
|
||
|
|
@property
|
||
|
|
def name(self) -> str:
|
||
|
|
return "MockProvider"
|
||
|
|
|
||
|
|
@property
|
||
|
|
def supports_websocket(self) -> bool:
|
||
|
|
return False
|
||
|
|
|
||
|
|
def connect(self) -> bool:
|
||
|
|
self._connected = True
|
||
|
|
return True
|
||
|
|
|
||
|
|
def disconnect(self):
|
||
|
|
self._connected = False
|
||
|
|
|
||
|
|
def get_ticker(self, symbol: str):
|
||
|
|
return {
|
||
|
|
'symbol': symbol,
|
||
|
|
'bid': Decimal('50000'),
|
||
|
|
'ask': Decimal('50001'),
|
||
|
|
'last': Decimal('50000.5'),
|
||
|
|
'high': Decimal('51000'),
|
||
|
|
'low': Decimal('49000'),
|
||
|
|
'volume': Decimal('1000000'),
|
||
|
|
'timestamp': 1609459200000,
|
||
|
|
}
|
||
|
|
|
||
|
|
def get_ohlcv(self, symbol: str, timeframe: str = '1h', since=None, limit: int = 100):
|
||
|
|
return [[1609459200000, 50000, 51000, 49000, 50000, 1000]]
|
||
|
|
|
||
|
|
def subscribe_ticker(self, symbol: str, callback) -> bool:
|
||
|
|
if symbol not in self._subscribers:
|
||
|
|
self._subscribers[symbol] = []
|
||
|
|
self._subscribers[symbol].append(callback)
|
||
|
|
return True
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.fixture
|
||
|
|
def mock_config():
|
||
|
|
"""Create a mock configuration."""
|
||
|
|
config = Mock()
|
||
|
|
config.get = Mock(side_effect=lambda key, default=None: {
|
||
|
|
"data_providers.primary": [
|
||
|
|
{"name": "mock", "enabled": True, "priority": 1}
|
||
|
|
],
|
||
|
|
"data_providers.fallback": {"enabled": True, "api_key": ""},
|
||
|
|
"data_providers.caching.ticker_ttl": 2,
|
||
|
|
"data_providers.caching.ohlcv_ttl": 60,
|
||
|
|
"data_providers.caching.max_cache_size": 1000,
|
||
|
|
}.get(key, default))
|
||
|
|
return config
|
||
|
|
|
||
|
|
|
||
|
|
class TestPricingService:
|
||
|
|
"""Tests for PricingService."""
|
||
|
|
|
||
|
|
@patch('src.data.pricing_service.get_config')
|
||
|
|
@patch('src.data.providers.ccxt_provider.CCXTProvider')
|
||
|
|
@patch('src.data.providers.coingecko_provider.CoinGeckoProvider')
|
||
|
|
def test_init(self, mock_coingecko, mock_ccxt, mock_get_config, mock_config):
|
||
|
|
"""Test service initialization."""
|
||
|
|
mock_get_config.return_value = mock_config
|
||
|
|
mock_ccxt_instance = MockProvider()
|
||
|
|
mock_ccxt.return_value = mock_ccxt_instance
|
||
|
|
mock_coingecko_instance = MockProvider()
|
||
|
|
mock_coingecko.return_value = mock_coingecko_instance
|
||
|
|
|
||
|
|
service = PricingService()
|
||
|
|
|
||
|
|
assert service.cache is not None
|
||
|
|
assert service.health_monitor is not None
|
||
|
|
|
||
|
|
@patch('src.data.pricing_service.get_config')
|
||
|
|
@patch('src.data.providers.ccxt_provider.CCXTProvider')
|
||
|
|
def test_get_ticker(self, mock_ccxt, mock_get_config, mock_config):
|
||
|
|
"""Test getting ticker data."""
|
||
|
|
mock_get_config.return_value = mock_config
|
||
|
|
mock_provider = MockProvider()
|
||
|
|
mock_ccxt.return_value = mock_provider
|
||
|
|
|
||
|
|
service = PricingService()
|
||
|
|
service._providers["MockProvider"] = mock_provider
|
||
|
|
service._active_provider = "MockProvider"
|
||
|
|
|
||
|
|
ticker = service.get_ticker("BTC/USD")
|
||
|
|
|
||
|
|
assert ticker['symbol'] == "BTC/USD"
|
||
|
|
assert isinstance(ticker['last'], Decimal)
|
||
|
|
|
||
|
|
@patch('src.data.pricing_service.get_config')
|
||
|
|
@patch('src.data.providers.ccxt_provider.CCXTProvider')
|
||
|
|
def test_get_ohlcv(self, mock_ccxt, mock_get_config, mock_config):
|
||
|
|
"""Test getting OHLCV data."""
|
||
|
|
mock_get_config.return_value = mock_config
|
||
|
|
mock_provider = MockProvider()
|
||
|
|
mock_ccxt.return_value = mock_provider
|
||
|
|
|
||
|
|
service = PricingService()
|
||
|
|
service._providers["MockProvider"] = mock_provider
|
||
|
|
service._active_provider = "MockProvider"
|
||
|
|
|
||
|
|
ohlcv = service.get_ohlcv("BTC/USD", "1h", limit=10)
|
||
|
|
|
||
|
|
assert len(ohlcv) > 0
|
||
|
|
assert len(ohlcv[0]) == 6
|
||
|
|
|
||
|
|
@patch('src.data.pricing_service.get_config')
|
||
|
|
@patch('src.data.providers.ccxt_provider.CCXTProvider')
|
||
|
|
def test_subscribe_ticker(self, mock_ccxt, mock_get_config, mock_config):
|
||
|
|
"""Test subscribing to ticker updates."""
|
||
|
|
mock_get_config.return_value = mock_config
|
||
|
|
mock_provider = MockProvider()
|
||
|
|
mock_ccxt.return_value = mock_provider
|
||
|
|
|
||
|
|
service = PricingService()
|
||
|
|
service._providers["MockProvider"] = mock_provider
|
||
|
|
service._active_provider = "MockProvider"
|
||
|
|
|
||
|
|
callback = Mock()
|
||
|
|
result = service.subscribe_ticker("BTC/USD", callback)
|
||
|
|
|
||
|
|
assert result is True
|