orchestrator adaptor

This commit is contained in:
Dobromir Popov
2025-08-04 23:13:44 +03:00
parent 1479ac1624
commit 68a556e09c
6 changed files with 1957 additions and 7 deletions

View File

@ -0,0 +1,385 @@
"""
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)