Files
aitbc/apps/blockchain-node/tests/network/test_hub_manager.py
aitbc d72945f20c
Some checks failed
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
API Endpoint Tests / test-api-endpoints (push) Has been cancelled
network: add hub registration, Redis persistence, and federated mesh join protocol
- 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
2026-04-13 11:47:34 +02:00

325 lines
11 KiB
Python

"""
Tests for Hub Manager with Redis persistence
"""
import pytest
import asyncio
from unittest.mock import Mock, AsyncMock, patch
from aitbc_chain.network.hub_manager import HubManager, HubInfo, HubStatus, PeerInfo
class TestHubManager:
"""Test cases for Hub Manager with Redis persistence"""
@pytest.fixture
def hub_manager(self):
"""Create a HubManager instance for testing"""
return HubManager(
local_node_id="test-node-id",
local_address="127.0.0.1",
local_port=7070,
island_id="test-island-id",
island_name="test-island",
redis_url="redis://localhost:6379"
)
@pytest.mark.asyncio
async def test_connect_redis_success(self, hub_manager):
"""Test successful Redis connection"""
with patch('aitbc_chain.network.hub_manager.redis.asyncio') as mock_redis:
mock_client = AsyncMock()
mock_client.ping = AsyncMock(return_value=True)
mock_redis.from_url.return_value = mock_client
result = await hub_manager._connect_redis()
assert result is True
assert hub_manager._redis is not None
mock_redis.from_url.assert_called_once_with("redis://localhost:6379")
mock_client.ping.assert_called_once()
@pytest.mark.asyncio
async def test_connect_redis_failure(self, hub_manager):
"""Test Redis connection failure"""
with patch('aitbc_chain.network.hub_manager.redis.asyncio') as mock_redis:
mock_redis.from_url.side_effect = Exception("Connection failed")
result = await hub_manager._connect_redis()
assert result is False
assert hub_manager._redis is None
@pytest.mark.asyncio
async def test_persist_hub_registration_success(self, hub_manager):
"""Test successful hub registration persistence to Redis"""
hub_info = HubInfo(
node_id="test-node-id",
address="127.0.0.1",
port=7070,
island_id="test-island-id",
island_name="test-island",
public_address="1.2.3.4",
public_port=7070,
registered_at=1234567890.0,
last_seen=1234567890.0
)
with patch('aitbc_chain.network.hub_manager.redis.asyncio') as mock_redis:
mock_client = AsyncMock()
mock_client.setex = AsyncMock(return_value=True)
mock_redis.from_url.return_value = mock_client
result = await hub_manager._persist_hub_registration(hub_info)
assert result is True
mock_client.setex.assert_called_once()
key = mock_client.setex.call_args[0][0]
assert key == "hub:test-node-id"
@pytest.mark.asyncio
async def test_persist_hub_registration_no_redis(self, hub_manager):
"""Test hub registration persistence when Redis is unavailable"""
hub_info = HubInfo(
node_id="test-node-id",
address="127.0.0.1",
port=7070,
island_id="test-island-id",
island_name="test-island"
)
with patch.object(hub_manager, '_connect_redis', return_value=False):
result = await hub_manager._persist_hub_registration(hub_info)
assert result is False
@pytest.mark.asyncio
async def test_remove_hub_registration_success(self, hub_manager):
"""Test successful hub registration removal from Redis"""
with patch('aitbc_chain.network.hub_manager.redis.asyncio') as mock_redis:
mock_client = AsyncMock()
mock_client.delete = AsyncMock(return_value=True)
mock_redis.from_url.return_value = mock_client
result = await hub_manager._remove_hub_registration("test-node-id")
assert result is True
mock_client.delete.assert_called_once_with("hub:test-node-id")
@pytest.mark.asyncio
async def test_load_hub_registration_success(self, hub_manager):
"""Test successful hub registration loading from Redis"""
with patch('aitbc_chain.network.hub_manager.redis.asyncio') as mock_redis:
mock_client = AsyncMock()
hub_data = {
"node_id": "test-node-id",
"address": "127.0.0.1",
"port": 7070,
"island_id": "test-island-id",
"island_name": "test-island"
}
mock_client.get = AsyncMock(return_value='{"node_id": "test-node-id", "address": "127.0.0.1", "port": 7070, "island_id": "test-island-id", "island_name": "test-island"}')
mock_redis.from_url.return_value = mock_client
result = await hub_manager._load_hub_registration()
assert result is not None
assert result.node_id == "test-node-id"
mock_client.get.assert_called_once_with("hub:test-node-id")
@pytest.mark.asyncio
async def test_load_hub_registration_not_found(self, hub_manager):
"""Test hub registration loading when not found in Redis"""
with patch('aitbc_chain.network.hub_manager.redis.asyncio') as mock_redis:
mock_client = AsyncMock()
mock_client.get = AsyncMock(return_value=None)
mock_redis.from_url.return_value = mock_client
result = await hub_manager._load_hub_registration()
assert result is None
@pytest.mark.asyncio
async def test_register_as_hub_success(self, hub_manager):
"""Test successful hub registration"""
with patch.object(hub_manager, '_persist_hub_registration', return_value=True):
result = await hub_manager.register_as_hub(public_address="1.2.3.4", public_port=7070)
assert result is True
assert hub_manager.is_hub is True
assert hub_manager.hub_status == HubStatus.REGISTERED
assert hub_manager.registered_at is not None
assert hub_manager.local_node_id in hub_manager.known_hubs
@pytest.mark.asyncio
async def test_register_as_hub_already_registered(self, hub_manager):
"""Test hub registration when already registered"""
hub_manager.is_hub = True
hub_manager.hub_status = HubStatus.REGISTERED
result = await hub_manager.register_as_hub()
assert result is False
assert hub_manager.is_hub is True
@pytest.mark.asyncio
async def test_unregister_as_hub_success(self, hub_manager):
"""Test successful hub unregistration"""
hub_manager.is_hub = True
hub_manager.hub_status = HubStatus.REGISTERED
hub_manager.known_hubs["test-node-id"] = HubInfo(
node_id="test-node-id",
address="127.0.0.1",
port=7070,
island_id="test-island-id",
island_name="test-island"
)
with patch.object(hub_manager, '_remove_hub_registration', return_value=True):
result = await hub_manager.unregister_as_hub()
assert result is True
assert hub_manager.is_hub is False
assert hub_manager.hub_status == HubStatus.UNREGISTERED
assert hub_manager.registered_at is None
assert hub_manager.local_node_id not in hub_manager.known_hubs
@pytest.mark.asyncio
async def test_unregister_as_hub_not_registered(self, hub_manager):
"""Test hub unregistration when not registered"""
result = await hub_manager.unregister_as_hub()
assert result is False
assert hub_manager.is_hub is False
def test_register_peer(self, hub_manager):
"""Test peer registration"""
peer_info = PeerInfo(
node_id="peer-1",
address="192.168.1.1",
port=7071,
island_id="test-island-id",
is_hub=False
)
result = hub_manager.register_peer(peer_info)
assert result is True
assert "peer-1" in hub_manager.peer_registry
assert "peer-1" in hub_manager.island_peers["test-island-id"]
def test_unregister_peer(self, hub_manager):
"""Test peer unregistration"""
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)
result = hub_manager.unregister_peer("peer-1")
assert result is True
assert "peer-1" not in hub_manager.peer_registry
assert "peer-1" not in hub_manager.island_peers["test-island-id"]
def test_add_known_hub(self, hub_manager):
"""Test adding a known hub"""
hub_info = HubInfo(
node_id="hub-1",
address="10.1.1.1",
port=7070,
island_id="test-island-id",
island_name="test-island"
)
hub_manager.add_known_hub(hub_info)
assert "hub-1" in hub_manager.known_hubs
assert hub_manager.known_hubs["hub-1"] == hub_info
def test_remove_known_hub(self, hub_manager):
"""Test removing a known hub"""
hub_info = HubInfo(
node_id="hub-1",
address="10.1.1.1",
port=7070,
island_id="test-island-id",
island_name="test-island"
)
hub_manager.add_known_hub(hub_info)
result = hub_manager.remove_known_hub("hub-1")
assert result is True
assert "hub-1" not in hub_manager.known_hubs
def test_get_peer_list(self, hub_manager):
"""Test getting peer list for an island"""
peer_info1 = PeerInfo(
node_id="peer-1",
address="192.168.1.1",
port=7071,
island_id="test-island-id",
is_hub=False
)
peer_info2 = PeerInfo(
node_id="peer-2",
address="192.168.1.2",
port=7072,
island_id="other-island-id",
is_hub=False
)
hub_manager.register_peer(peer_info1)
hub_manager.register_peer(peer_info2)
peers = hub_manager.get_peer_list("test-island-id")
assert len(peers) == 1
assert peers[0].node_id == "peer-1"
def test_get_hub_list(self, hub_manager):
"""Test getting hub list"""
hub_info1 = HubInfo(
node_id="hub-1",
address="10.1.1.1",
port=7070,
island_id="test-island-id",
island_name="test-island"
)
hub_info2 = HubInfo(
node_id="hub-2",
address="10.1.1.2",
port=7070,
island_id="other-island-id",
island_name="other-island"
)
hub_manager.add_known_hub(hub_info1)
hub_manager.add_known_hub(hub_info2)
hubs = hub_manager.get_hub_list("test-island-id")
assert len(hubs) == 1
assert hubs[0].node_id == "hub-1"
def test_update_peer_last_seen(self, hub_manager):
"""Test updating peer last seen time"""
peer_info = PeerInfo(
node_id="peer-1",
address="192.168.1.1",
port=7071,
island_id="test-island-id",
is_hub=False,
last_seen=100.0
)
hub_manager.register_peer(peer_info)
hub_manager.update_peer_last_seen("peer-1")
assert hub_manager.peer_registry["peer-1"].last_seen > 100.0
if __name__ == "__main__":
pytest.main([__file__])