""" Tests for the Candles module. Note: The candle data fetching has been moved to EDM (Exchange Data Manager). These tests use mocked EDM responses to avoid requiring a running EDM server. Functions like ts_of_n_minutes_ago and timeframe_to_minutes are tested in test_shared_utilities.py. """ import datetime as dt import pytest import pandas as pd from unittest.mock import MagicMock, patch from candles import Candles from Configuration import Configuration from DataCache_v3 import DataCache @pytest.fixture def mock_edm_client(): """Create a mock EDM client.""" mock = MagicMock() # Mock get_candles_sync to return sample candle data sample_candles = pd.DataFrame({ 'time': [1700000000000, 1700000060000, 1700000120000, 1700000180000, 1700000240000], 'open': [100.0, 101.0, 102.0, 101.5, 103.0], 'high': [102.0, 103.0, 104.0, 103.5, 105.0], 'low': [99.0, 100.0, 101.0, 100.5, 102.0], 'close': [101.0, 102.0, 101.5, 103.0, 104.0], 'volume': [1000.0, 1200.0, 800.0, 1500.0, 900.0] }) mock.get_candles_sync.return_value = sample_candles return mock @pytest.fixture def mock_exchanges(): """Create mock exchange interface.""" return MagicMock() @pytest.fixture def mock_users(): """Create mock users object.""" mock = MagicMock() mock.get_chart_view.return_value = {'timeframe': '1m', 'exchange': 'binance', 'market': 'BTC/USDT'} return mock @pytest.fixture def data_cache(): """Create a fresh DataCache.""" return DataCache() @pytest.fixture def config(): """Create a Configuration instance.""" return Configuration() @pytest.fixture def candles(mock_exchanges, mock_users, data_cache, config, mock_edm_client): """Create a Candles instance with mocked dependencies.""" return Candles( exchanges=mock_exchanges, users=mock_users, datacache=data_cache, config=config, edm_client=mock_edm_client ) class TestCandles: """Tests for the Candles class.""" def test_candles_creation(self, candles): """Test that Candles object can be created.""" assert candles is not None def test_get_last_n_candles(self, candles, mock_edm_client): """Test getting last N candles.""" result = candles.get_last_n_candles( num_candles=5, asset='BTC/USDT', timeframe='1m', exchange='binance', user_name='test_user' ) assert result is not None assert isinstance(result, pd.DataFrame) assert len(result) == 5 assert 'open' in result.columns assert 'high' in result.columns assert 'low' in result.columns assert 'close' in result.columns assert 'volume' in result.columns def test_get_last_n_candles_caps_at_1000(self, candles, mock_edm_client): """Test that requests for more than 1000 candles are capped.""" candles.get_last_n_candles( num_candles=2000, asset='BTC/USDT', timeframe='1m', exchange='binance', user_name='test_user' ) # Check that EDM was called with capped limit call_args = mock_edm_client.get_candles_sync.call_args assert call_args.kwargs.get('limit', call_args[1].get('limit')) == 1000 def test_candles_raises_without_edm(self, mock_exchanges, mock_users, data_cache, config): """Test that Candles raises error when EDM is not available.""" candles_no_edm = Candles( exchanges=mock_exchanges, users=mock_users, datacache=data_cache, config=config, edm_client=None ) with pytest.raises(RuntimeError, match="EDM client not initialized"): candles_no_edm.get_last_n_candles( num_candles=5, asset='BTC/USDT', timeframe='1m', exchange='binance', user_name='test_user' ) def test_get_latest_values(self, candles, mock_edm_client): """Test getting latest values for a specific field.""" result = candles.get_latest_values( value_name='close', symbol='BTC/USDT', timeframe='1m', exchange='binance', num_record=5, user_name='test_user' ) assert result is not None # Should return series/list of close values assert len(result) <= 5 def test_max_records_from_config(self, candles, config): """Test that max_records is loaded from config.""" expected_max = config.get_setting('max_data_loaded') assert candles.max_records == expected_max def test_candle_cache_created(self, candles, data_cache): """Test that candle cache is created on initialization.""" # The cache should exist assert 'candles' in data_cache.caches class TestCandlesIntegration: """Integration-style tests that verify EDM client interaction.""" def test_edm_client_called_correctly(self, candles, mock_edm_client): """Test that EDM client is called with correct parameters.""" candles.get_last_n_candles( num_candles=10, asset='ETH/USDT', timeframe='5m', exchange='binance', user_name='test_user' ) mock_edm_client.get_candles_sync.assert_called_once() call_kwargs = mock_edm_client.get_candles_sync.call_args.kwargs assert call_kwargs['symbol'] == 'ETH/USDT' assert call_kwargs['timeframe'] == '5m' assert call_kwargs['exchange'] == 'binance' assert call_kwargs['limit'] == 10