Files
gogo2/COBY/tests/test_all_connectors.py
Dobromir Popov 7339972eab Binance (completed previously)
 Coinbase Pro (completed in task 12)
 Kraken (completed in task 12)
 Bybit (completed in this task)
 OKX (completed in this task)
 Huobi (completed in this task)
2025-08-04 23:41:42 +03:00

271 lines
10 KiB
Python

"""
Comprehensive tests for all exchange connectors.
Tests the consistency and compatibility across all implemented connectors.
"""
import asyncio
import pytest
from unittest.mock import Mock, AsyncMock
from ..connectors.binance_connector import BinanceConnector
from ..connectors.coinbase_connector import CoinbaseConnector
from ..connectors.kraken_connector import KrakenConnector
from ..connectors.bybit_connector import BybitConnector
from ..connectors.okx_connector import OKXConnector
from ..connectors.huobi_connector import HuobiConnector
class TestAllConnectors:
"""Test suite for all exchange connectors."""
@pytest.fixture
def all_connectors(self):
"""Create instances of all connectors for testing."""
return {
'binance': BinanceConnector(),
'coinbase': CoinbaseConnector(use_sandbox=True),
'kraken': KrakenConnector(),
'bybit': BybitConnector(use_testnet=True),
'okx': OKXConnector(use_demo=True),
'huobi': HuobiConnector()
}
def test_all_connectors_initialization(self, all_connectors):
"""Test that all connectors initialize correctly."""
expected_names = ['binance', 'coinbase', 'kraken', 'bybit', 'okx', 'huobi']
for name, connector in all_connectors.items():
assert connector.exchange_name == name
assert hasattr(connector, 'websocket_url')
assert hasattr(connector, 'message_handlers')
assert hasattr(connector, 'subscriptions')
def test_interface_consistency(self, all_connectors):
"""Test that all connectors implement the required interface methods."""
required_methods = [
'connect',
'disconnect',
'subscribe_orderbook',
'subscribe_trades',
'unsubscribe_orderbook',
'unsubscribe_trades',
'get_symbols',
'get_orderbook_snapshot',
'normalize_symbol',
'get_connection_status',
'add_data_callback',
'remove_data_callback'
]
for name, connector in all_connectors.items():
for method in required_methods:
assert hasattr(connector, method), f"{name} missing method {method}"
assert callable(getattr(connector, method)), f"{name}.{method} not callable"
def test_symbol_normalization_consistency(self, all_connectors):
"""Test symbol normalization across all connectors."""
test_symbols = ['BTCUSDT', 'ETHUSDT', 'btcusdt', 'BTC-USDT', 'BTC/USDT']
for name, connector in all_connectors.items():
for symbol in test_symbols:
try:
normalized = connector.normalize_symbol(symbol)
assert isinstance(normalized, str)
assert len(normalized) > 0
print(f"{name}: {symbol} -> {normalized}")
except Exception as e:
print(f"{name} failed to normalize {symbol}: {e}")
@pytest.mark.asyncio
async def test_subscription_interface(self, all_connectors):
"""Test subscription interface consistency."""
for name, connector in all_connectors.items():
# Mock the _send_message method
connector._send_message = AsyncMock(return_value=True)
try:
# Test order book subscription
await connector.subscribe_orderbook('BTCUSDT')
assert 'BTCUSDT' in connector.subscriptions
# Test trade subscription
await connector.subscribe_trades('ETHUSDT')
assert 'ETHUSDT' in connector.subscriptions
# Test unsubscription
await connector.unsubscribe_orderbook('BTCUSDT')
await connector.unsubscribe_trades('ETHUSDT')
print(f"{name} subscription interface works")
except Exception as e:
print(f"{name} subscription interface failed: {e}")
def test_message_type_detection(self, all_connectors):
"""Test message type detection across connectors."""
# Test with generic message structures
test_messages = [
{'type': 'test'},
{'event': 'test'},
{'op': 'test'},
{'ch': 'test'},
{'topic': 'test'},
[1, {}, 'test', 'symbol'], # Kraken format
{'unknown': 'data'}
]
for name, connector in all_connectors.items():
for msg in test_messages:
try:
msg_type = connector._get_message_type(msg)
assert isinstance(msg_type, str)
print(f"{name}: {msg} -> {msg_type}")
except Exception as e:
print(f"{name} failed to detect message type for {msg}: {e}")
def test_statistics_interface(self, all_connectors):
"""Test statistics interface consistency."""
for name, connector in all_connectors.items():
try:
stats = connector.get_stats()
assert isinstance(stats, dict)
assert 'exchange' in stats
assert stats['exchange'] == name
assert 'connection_status' in stats
print(f"{name} statistics interface works")
except Exception as e:
print(f"{name} statistics interface failed: {e}")
def test_callback_system(self, all_connectors):
"""Test callback system consistency."""
for name, connector in all_connectors.items():
try:
# Test adding callback
def test_callback(data):
pass
connector.add_data_callback(test_callback)
assert test_callback in connector.data_callbacks
# Test removing callback
connector.remove_data_callback(test_callback)
assert test_callback not in connector.data_callbacks
print(f"{name} callback system works")
except Exception as e:
print(f"{name} callback system failed: {e}")
def test_connection_status(self, all_connectors):
"""Test connection status interface."""
for name, connector in all_connectors.items():
try:
status = connector.get_connection_status()
assert hasattr(status, 'value') # Should be an enum
# Test is_connected property
is_connected = connector.is_connected
assert isinstance(is_connected, bool)
print(f"{name} connection status interface works")
except Exception as e:
print(f"{name} connection status interface failed: {e}")
async def test_connector_compatibility():
"""Test compatibility across all connectors."""
print("=== Testing All Exchange Connectors ===")
connectors = {
'binance': BinanceConnector(),
'coinbase': CoinbaseConnector(use_sandbox=True),
'kraken': KrakenConnector(),
'bybit': BybitConnector(use_testnet=True),
'okx': OKXConnector(use_demo=True),
'huobi': HuobiConnector()
}
# Test basic functionality
for name, connector in connectors.items():
try:
print(f"\nTesting {name.upper()} connector:")
# Test initialization
assert connector.exchange_name == name
print(f" ✓ Initialization: {connector.exchange_name}")
# Test symbol normalization
btc_symbol = connector.normalize_symbol('BTCUSDT')
eth_symbol = connector.normalize_symbol('ETHUSDT')
print(f" ✓ Symbol normalization: BTCUSDT -> {btc_symbol}, ETHUSDT -> {eth_symbol}")
# Test message type detection
test_msg = {'type': 'test'} if name != 'kraken' else [1, {}, 'test', 'symbol']
msg_type = connector._get_message_type(test_msg)
print(f" ✓ Message type detection: {msg_type}")
# Test statistics
stats = connector.get_stats()
print(f" ✓ Statistics: {len(stats)} fields")
# Test connection status
status = connector.get_connection_status()
print(f" ✓ Connection status: {status.value}")
print(f"{name.upper()} connector passed all tests")
except Exception as e:
print(f"{name.upper()} connector failed: {e}")
print("\n=== All Connector Tests Completed ===")
return True
async def test_multi_connector_data_flow():
"""Test data flow across multiple connectors simultaneously."""
print("=== Testing Multi-Connector Data Flow ===")
connectors = {
'binance': BinanceConnector(),
'coinbase': CoinbaseConnector(use_sandbox=True),
'kraken': KrakenConnector()
}
# Set up data collection
received_data = {name: [] for name in connectors.keys()}
def create_callback(exchange_name):
def callback(data):
received_data[exchange_name].append(data)
print(f"Received data from {exchange_name}: {type(data).__name__}")
return callback
# Add callbacks to all connectors
for name, connector in connectors.items():
connector.add_data_callback(create_callback(name))
connector._send_message = AsyncMock(return_value=True)
# Test subscription to same symbol across exchanges
symbol = 'BTCUSDT'
for name, connector in connectors.items():
try:
await connector.subscribe_orderbook(symbol)
await connector.subscribe_trades(symbol)
print(f"✓ Subscribed to {symbol} on {name}")
except Exception as e:
print(f"✗ Failed to subscribe to {symbol} on {name}: {e}")
print("Multi-connector data flow test completed")
return True
if __name__ == "__main__":
# Run all tests
async def run_all_tests():
await test_connector_compatibility()
await test_multi_connector_data_flow()
print("✅ All connector tests completed successfully")
asyncio.run(run_all_tests())