Some checks failed
API Endpoint Tests / test-api-endpoints (push) Waiting to run
Systemd Sync / sync-systemd (push) Waiting to run
CLI Tests / test-cli (push) Has been cancelled
Integration Tests / test-service-integration (push) Has been cancelled
Python Tests / test-python (push) Has been cancelled
Security Scanning / security-scan (push) Has been cancelled
Documentation Validation / validate-docs (push) Has been cancelled
- Change default P2P port from 7070 to 8001 in config and .env.example - Add redis_url configuration option for hub persistence (default: redis://localhost:6379) - Implement DNS-based hub registration/unregistration via HTTPS API endpoints - Add Redis persistence for hub registrations with 1-hour TTL - Add island join request/response protocol with member list and blockchain credentials - Add GPU marketplace tracking (offers, bids, providers) in hub manager - Add
245 lines
8.6 KiB
Python
245 lines
8.6 KiB
Python
"""
|
|
Tests for Island Join functionality
|
|
"""
|
|
|
|
import pytest
|
|
import asyncio
|
|
from unittest.mock import Mock, AsyncMock, patch, MagicMock
|
|
from aitbc_chain.network.hub_manager import HubManager, HubInfo, PeerInfo
|
|
from aitbc_chain.p2p_network import P2PNetworkService
|
|
|
|
|
|
class TestHubManagerJoin:
|
|
"""Test cases for HubManager join request handling"""
|
|
|
|
@pytest.fixture
|
|
def hub_manager(self):
|
|
"""Create a HubManager instance for testing"""
|
|
return HubManager(
|
|
local_node_id="test-hub-node",
|
|
local_address="127.0.0.1",
|
|
local_port=7070,
|
|
island_id="test-island-id",
|
|
island_name="test-island",
|
|
redis_url="redis://localhost:6379"
|
|
)
|
|
|
|
def test_get_blockchain_credentials(self, hub_manager):
|
|
"""Test blockchain credentials retrieval"""
|
|
with patch('aitbc_chain.network.hub_manager.os.path.exists', return_value=True):
|
|
with patch('aitbc_chain.network.hub_manager.open', create=True) as mock_open:
|
|
# Mock genesis.json
|
|
genesis_data = {
|
|
'blocks': [{'hash': 'test-genesis-hash'}]
|
|
}
|
|
mock_file = MagicMock()
|
|
mock_file.read.return_value = '{"blocks": [{"hash": "test-genesis-hash"}]}'
|
|
mock_open.return_value.__enter__.return_value = mock_file
|
|
|
|
# Mock keystore
|
|
with patch('aitbc_chain.network.hub_manager.json.load') as mock_json_load:
|
|
mock_json_load.return_value = {'0x123': {'public_key_pem': 'test-key'}}
|
|
|
|
credentials = hub_manager._get_blockchain_credentials()
|
|
|
|
assert credentials is not None
|
|
assert 'chain_id' in credentials
|
|
assert 'island_id' in credentials
|
|
assert credentials['island_id'] == 'test-island-id'
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_handle_join_request_success(self, hub_manager):
|
|
"""Test successful join request handling"""
|
|
# Add some peers to the registry
|
|
peer_info = PeerInfo(
|
|
node_id="peer-1",
|
|
address="192.168.1.1",
|
|
port=7071,
|
|
island_id="test-island-id",
|
|
is_hub=False
|
|
)
|
|
hub_manager.register_peer(peer_info)
|
|
|
|
join_request = {
|
|
'type': 'join_request',
|
|
'node_id': 'new-node',
|
|
'island_id': 'test-island-id',
|
|
'island_name': 'test-island',
|
|
'public_key_pem': 'test-pem'
|
|
}
|
|
|
|
with patch.object(hub_manager, '_get_blockchain_credentials', return_value={'chain_id': 'test-chain'}):
|
|
response = await hub_manager.handle_join_request(join_request)
|
|
|
|
assert response is not None
|
|
assert response['type'] == 'join_response'
|
|
assert response['island_id'] == 'test-island-id'
|
|
assert len(response['members']) >= 1 # At least the hub itself
|
|
assert 'credentials' in response
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_handle_join_request_wrong_island(self, hub_manager):
|
|
"""Test join request for wrong island"""
|
|
join_request = {
|
|
'type': 'join_request',
|
|
'node_id': 'new-node',
|
|
'island_id': 'wrong-island-id',
|
|
'island_name': 'wrong-island',
|
|
'public_key_pem': 'test-pem'
|
|
}
|
|
|
|
response = await hub_manager.handle_join_request(join_request)
|
|
|
|
assert response is None
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_handle_join_request_with_members(self, hub_manager):
|
|
"""Test join request returns all island members"""
|
|
# Add multiple peers
|
|
for i in range(3):
|
|
peer_info = PeerInfo(
|
|
node_id=f"peer-{i}",
|
|
address=f"192.168.1.{i}",
|
|
port=7070 + i,
|
|
island_id="test-island-id",
|
|
is_hub=False
|
|
)
|
|
hub_manager.register_peer(peer_info)
|
|
|
|
join_request = {
|
|
'type': 'join_request',
|
|
'node_id': 'new-node',
|
|
'island_id': 'test-island-id',
|
|
'island_name': 'test-island',
|
|
'public_key_pem': 'test-pem'
|
|
}
|
|
|
|
with patch.object(hub_manager, '_get_blockchain_credentials', return_value={'chain_id': 'test-chain'}):
|
|
response = await hub_manager.handle_join_request(join_request)
|
|
|
|
assert response is not None
|
|
# Should include all peers + hub itself
|
|
assert len(response['members']) >= 4
|
|
|
|
|
|
class TestP2PNetworkJoin:
|
|
"""Test cases for P2P network join request functionality"""
|
|
|
|
@pytest.fixture
|
|
def p2p_service(self):
|
|
"""Create a P2P service instance for testing"""
|
|
return P2PNetworkService(
|
|
host="127.0.0.1",
|
|
port=7070,
|
|
node_id="test-node",
|
|
peers=[]
|
|
)
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_send_join_request_success(self, p2p_service):
|
|
"""Test successful join request to hub"""
|
|
join_response = {
|
|
'type': 'join_response',
|
|
'island_id': 'test-island-id',
|
|
'island_name': 'test-island',
|
|
'island_chain_id': 'test-chain',
|
|
'members': [],
|
|
'credentials': {}
|
|
}
|
|
|
|
with patch('aitbc_chain.p2p_network.asyncio.open_connection') as mock_open:
|
|
# Mock reader and writer
|
|
mock_reader = AsyncMock()
|
|
mock_reader.readline = AsyncMock(return_value=b'{"type": "join_response"}')
|
|
mock_writer = AsyncMock()
|
|
mock_writer.close = AsyncMock()
|
|
mock_writer.wait_closed = AsyncMock()
|
|
mock_open.return_value = (mock_reader, mock_writer)
|
|
|
|
response = await p2p_service.send_join_request(
|
|
hub_address="127.0.0.1",
|
|
hub_port=7070,
|
|
island_id="test-island-id",
|
|
island_name="test-island",
|
|
node_id="test-node",
|
|
public_key_pem="test-pem"
|
|
)
|
|
|
|
assert response is not None
|
|
mock_open.assert_called_once_with("127.0.0.1", 7070)
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_send_join_request_connection_refused(self, p2p_service):
|
|
"""Test join request when hub refuses connection"""
|
|
with patch('aitbc_chain.p2p_network.asyncio.open_connection') as mock_open:
|
|
mock_open.side_effect = ConnectionRefusedError()
|
|
|
|
response = await p2p_service.send_join_request(
|
|
hub_address="127.0.0.1",
|
|
hub_port=7070,
|
|
island_id="test-island-id",
|
|
island_name="test-island",
|
|
node_id="test-node",
|
|
public_key_pem="test-pem"
|
|
)
|
|
|
|
assert response is None
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_send_join_request_timeout(self, p2p_service):
|
|
"""Test join request timeout"""
|
|
with patch('aitbc_chain.p2p_network.asyncio.open_connection') as mock_open:
|
|
# Mock reader that times out
|
|
mock_reader = AsyncMock()
|
|
mock_reader.readline = AsyncMock(side_effect=asyncio.TimeoutError())
|
|
mock_writer = AsyncMock()
|
|
mock_writer.close = AsyncMock()
|
|
mock_writer.wait_closed = AsyncMock()
|
|
mock_open.return_value = (mock_reader, mock_writer)
|
|
|
|
response = await p2p_service.send_join_request(
|
|
hub_address="127.0.0.1",
|
|
hub_port=7070,
|
|
island_id="test-island-id",
|
|
island_name="test-island",
|
|
node_id="test-node",
|
|
public_key_pem="test-pem"
|
|
)
|
|
|
|
assert response is None
|
|
|
|
|
|
class TestJoinMessageHandling:
|
|
"""Test cases for join message handling in P2P network"""
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_join_request_message_handling(self):
|
|
"""Test that join_request messages are handled correctly"""
|
|
service = P2PNetworkService(
|
|
host="127.0.0.1",
|
|
port=7070,
|
|
node_id="test-node",
|
|
peers=[]
|
|
)
|
|
|
|
# Mock hub manager
|
|
service.hub_manager = Mock()
|
|
service.hub_manager.handle_join_request = AsyncMock(return_value={'type': 'join_response'})
|
|
|
|
join_request = {
|
|
'type': 'join_request',
|
|
'node_id': 'new-node',
|
|
'island_id': 'test-island-id'
|
|
}
|
|
|
|
# The actual message handling happens in _listen_to_stream
|
|
# This test verifies the hub_manager.handle_join_request would be called
|
|
response = await service.hub_manager.handle_join_request(join_request)
|
|
|
|
assert response is not None
|
|
assert response['type'] == 'join_response'
|
|
|
|
|
|
if __name__ == "__main__":
|
|
pytest.main([__file__])
|