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
325 lines
11 KiB
Python
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__])
|