""" Integration tests for COBY orchestrator compatibility. Tests the adapter's compatibility with the existing orchestrator interface. """ import asyncio import logging import pytest from datetime import datetime, timedelta from unittest.mock import Mock, AsyncMock from ..integration.orchestrator_adapter import COBYOrchestratorAdapter, MarketTick from ..integration.data_provider_replacement import COBYDataProvider from ..config import Config # Set up logging logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) class TestOrchestratorIntegration: """Test suite for orchestrator integration.""" @pytest.fixture async def adapter(self): """Create adapter instance for testing.""" config = Config() adapter = COBYOrchestratorAdapter(config) # Mock the storage manager for testing adapter.storage_manager = Mock() adapter.storage_manager.initialize = AsyncMock() adapter.storage_manager.is_healthy = Mock(return_value=True) adapter.storage_manager.get_latest_orderbook = AsyncMock(return_value={ 'symbol': 'BTCUSDT', 'timestamp': datetime.utcnow(), 'mid_price': 50000.0, 'spread': 0.01, 'bid_volume': 10.5, 'ask_volume': 8.3, 'exchange': 'binance' }) adapter.storage_manager.get_historical_data = AsyncMock(return_value=[ { 'timestamp': datetime.utcnow() - timedelta(minutes=i), 'open': 50000 + i, 'high': 50010 + i, 'low': 49990 + i, 'close': 50005 + i, 'volume': 100 + i, 'symbol': 'BTCUSDT', 'exchange': 'binance' } for i in range(100) ]) # Mock Redis manager adapter.redis_manager = Mock() adapter.redis_manager.initialize = AsyncMock() adapter.redis_manager.get = AsyncMock(return_value=None) adapter.redis_manager.set = AsyncMock() # Mock connectors adapter.connectors = {'binance': Mock()} adapter.connectors['binance'].connect = AsyncMock() adapter.connectors['binance'].is_connected = True await adapter._initialize_components() return adapter @pytest.fixture async def data_provider(self): """Create data provider replacement for testing.""" # Mock the adapter initialization provider = COBYDataProvider() # Use the same mocks as adapter provider.adapter.storage_manager = Mock() provider.adapter.storage_manager.get_latest_orderbook = AsyncMock(return_value={ 'symbol': 'BTCUSDT', 'timestamp': datetime.utcnow(), 'mid_price': 50000.0, 'spread': 0.01, 'bid_volume': 10.5, 'ask_volume': 8.3, 'exchange': 'binance' }) return provider async def test_adapter_initialization(self, adapter): """Test adapter initializes correctly.""" assert adapter is not None assert adapter.mode == 'live' assert adapter.config is not None assert 'binance' in adapter.connectors async def test_get_current_price(self, adapter): """Test getting current price.""" price = adapter.get_current_price('BTCUSDT') assert price == 50000.0 async def test_get_historical_data(self, adapter): """Test getting historical data.""" df = adapter.get_historical_data('BTCUSDT', '1m', limit=50) assert df is not None assert len(df) == 100 # Mock returns 100 records assert 'open' in df.columns assert 'high' in df.columns assert 'low' in df.columns assert 'close' in df.columns assert 'volume' in df.columns async def test_build_base_data_input(self, adapter): """Test building base data input.""" base_data = adapter.build_base_data_input('BTCUSDT') assert base_data is not None assert hasattr(base_data, 'get_feature_vector') features = base_data.get_feature_vector() assert isinstance(features, type(features)) # numpy array assert len(features) == 100 # Expected feature size async def test_cob_data_methods(self, adapter): """Test COB data access methods.""" # Mock COB data adapter.storage_manager.get_historical_data = AsyncMock(return_value=[ { 'symbol': 'BTCUSDT', 'timestamp': datetime.utcnow(), 'mid_price': 50000.0, 'spread': 0.01, 'bid_volume': 10.5, 'ask_volume': 8.3, 'exchange': 'binance' } ]) # Test raw ticks raw_ticks = adapter.get_cob_raw_ticks('BTCUSDT', count=10) assert isinstance(raw_ticks, list) # Test latest COB data latest_cob = adapter.get_latest_cob_data('BTCUSDT') assert latest_cob is not None assert latest_cob['symbol'] == 'BTCUSDT' assert 'mid_price' in latest_cob async def test_subscription_management(self, adapter): """Test subscription methods.""" callback_called = False received_tick = None def tick_callback(tick): nonlocal callback_called, received_tick callback_called = True received_tick = tick # Subscribe to ticks subscriber_id = adapter.subscribe_to_ticks( tick_callback, symbols=['BTCUSDT'], subscriber_name='test_subscriber' ) assert subscriber_id != "" assert len(adapter.subscribers['ticks']) == 1 # Simulate tick notification test_tick = MarketTick( symbol='BTCUSDT', price=50000.0, volume=1.5, timestamp=datetime.utcnow(), exchange='binance' ) await adapter._notify_tick_subscribers(test_tick) assert callback_called assert received_tick is not None assert received_tick.symbol == 'BTCUSDT' # Unsubscribe success = adapter.unsubscribe(subscriber_id) assert success assert len(adapter.subscribers['ticks']) == 0 async def test_mode_switching(self, adapter): """Test switching between live and replay modes.""" # Initially in live mode assert adapter.get_current_mode() == 'live' # Mock replay manager adapter.replay_manager = Mock() adapter.replay_manager.create_replay_session = Mock(return_value='test_session_123') adapter.replay_manager.add_data_callback = Mock() adapter.replay_manager.start_replay = AsyncMock() adapter.replay_manager.stop_replay = AsyncMock() # Switch to replay mode start_time = datetime.utcnow() - timedelta(hours=1) end_time = datetime.utcnow() success = await adapter.switch_to_replay_mode( start_time=start_time, end_time=end_time, speed=2.0, symbols=['BTCUSDT'] ) assert success assert adapter.get_current_mode() == 'replay' assert adapter.current_replay_session == 'test_session_123' # Switch back to live mode success = await adapter.switch_to_live_mode() assert success assert adapter.get_current_mode() == 'live' assert adapter.current_replay_session is None async def test_data_quality_indicators(self, adapter): """Test data quality indicators.""" quality = adapter.get_data_quality_indicators('BTCUSDT') assert quality is not None assert quality['symbol'] == 'BTCUSDT' assert 'quality_score' in quality assert 'timestamp' in quality assert isinstance(quality['quality_score'], float) assert 0.0 <= quality['quality_score'] <= 1.0 async def test_system_metadata(self, adapter): """Test system metadata retrieval.""" metadata = adapter.get_system_metadata() assert metadata is not None assert metadata['system'] == 'COBY' assert metadata['version'] == '1.0.0' assert 'mode' in metadata assert 'components' in metadata assert 'statistics' in metadata async def test_data_provider_compatibility(self, data_provider): """Test data provider replacement compatibility.""" # Test core methods exist and work assert hasattr(data_provider, 'get_historical_data') assert hasattr(data_provider, 'get_current_price') assert hasattr(data_provider, 'build_base_data_input') assert hasattr(data_provider, 'subscribe_to_ticks') assert hasattr(data_provider, 'get_cob_raw_ticks') # Test current price price = data_provider.get_current_price('BTCUSDT') assert price == 50000.0 # Test COB imbalance imbalance = data_provider.get_current_cob_imbalance('BTCUSDT') assert 'bid_volume' in imbalance assert 'ask_volume' in imbalance assert 'imbalance' in imbalance # Test WebSocket status status = data_provider.get_cob_websocket_status() assert 'connected' in status assert 'exchanges' in status async def test_error_handling(self, adapter): """Test error handling in various scenarios.""" # Test with invalid symbol price = adapter.get_current_price('INVALID_SYMBOL') # Should not raise exception, may return None # Test with storage error adapter.storage_manager.get_latest_orderbook = AsyncMock(side_effect=Exception("Storage error")) price = adapter.get_current_price('BTCUSDT') # Should handle error gracefully # Test subscription with invalid callback subscriber_id = adapter.subscribe_to_ticks(None, ['BTCUSDT']) # Should handle gracefully async def test_performance_metrics(self, adapter): """Test performance metrics and statistics.""" # Get initial stats initial_stats = adapter.get_stats() assert 'ticks_processed' in initial_stats assert 'orderbooks_processed' in initial_stats # Simulate some data processing from ..models.core import OrderBookSnapshot, PriceLevel test_orderbook = OrderBookSnapshot( symbol='BTCUSDT', exchange='binance', timestamp=datetime.utcnow(), bids=[PriceLevel(price=49999.0, size=1.5)], asks=[PriceLevel(price=50001.0, size=1.2)] ) await adapter._handle_connector_data(test_orderbook) # Check stats updated updated_stats = adapter.get_stats() assert updated_stats['orderbooks_processed'] >= initial_stats['orderbooks_processed'] async def test_integration_suite(): """Run the complete integration test suite.""" logger.info("Starting COBY orchestrator integration tests...") try: # Create test instances config = Config() adapter = COBYOrchestratorAdapter(config) # Mock components for testing adapter.storage_manager = Mock() adapter.storage_manager.initialize = AsyncMock() adapter.storage_manager.is_healthy = Mock(return_value=True) adapter.redis_manager = Mock() adapter.redis_manager.initialize = AsyncMock() adapter.connectors = {'binance': Mock()} adapter.connectors['binance'].connect = AsyncMock() await adapter._initialize_components() # Run basic functionality tests logger.info("Testing basic functionality...") # Test price retrieval adapter.storage_manager.get_latest_orderbook = AsyncMock(return_value={ 'symbol': 'BTCUSDT', 'timestamp': datetime.utcnow(), 'mid_price': 50000.0, 'spread': 0.01, 'bid_volume': 10.5, 'ask_volume': 8.3, 'exchange': 'binance' }) price = adapter.get_current_price('BTCUSDT') assert price == 50000.0 logger.info(f"✓ Current price retrieval: {price}") # Test subscription callback_called = False def test_callback(tick): nonlocal callback_called callback_called = True subscriber_id = adapter.subscribe_to_ticks(test_callback, ['BTCUSDT']) assert subscriber_id != "" logger.info(f"✓ Subscription created: {subscriber_id}") # Test data quality quality = adapter.get_data_quality_indicators('BTCUSDT') assert quality['symbol'] == 'BTCUSDT' logger.info(f"✓ Data quality check: {quality['quality_score']}") # Test system metadata metadata = adapter.get_system_metadata() assert metadata['system'] == 'COBY' logger.info(f"✓ System metadata: {metadata['mode']}") logger.info("All integration tests passed successfully!") return True except Exception as e: logger.error(f"Integration test failed: {e}") return False if __name__ == "__main__": # Run the integration tests success = asyncio.run(test_integration_suite()) if success: print("✓ COBY orchestrator integration tests completed successfully") else: print("✗ COBY orchestrator integration tests failed") exit(1)