Files
aitbc/cli/tests/test_gpu_marketplace.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

247 lines
8.2 KiB
Python

"""
Unit tests for GPU marketplace CLI commands
"""
import pytest
import json
import os
from pathlib import Path
from click.testing import CliRunner
from unittest.mock import patch, MagicMock
@pytest.fixture
def mock_credentials_file(tmp_path):
"""Create a temporary credentials file for testing"""
credentials = {
"island_id": "test-island-id-12345",
"island_name": "test-island",
"island_chain_id": "ait-test",
"credentials": {
"genesis_block_hash": "0x1234567890abcdef",
"genesis_address": "0xabcdef1234567890",
"rpc_endpoint": "http://localhost:8006",
"p2p_port": 8001
},
"members": [],
"joined_at": "2024-01-01T00:00:00"
}
# Monkey patch the credentials path
import aitbc_cli.utils.island_credentials as ic_module
original_path = ic_module.CREDENTIALS_PATH
ic_module.CREDENTIALS_PATH = str(tmp_path / "island_credentials.json")
# Write credentials to temp file
with open(ic_module.CREDENTIALS_PATH, 'w') as f:
json.dump(credentials, f)
yield credentials
# Cleanup
if os.path.exists(ic_module.CREDENTIALS_PATH):
os.remove(ic_module.CREDENTIALS_PATH)
ic_module.CREDENTIALS_PATH = original_path
@pytest.fixture
def mock_keystore(tmp_path):
"""Create a temporary keystore for testing"""
keystore = {
"test_key_id": {
"public_key_pem": "-----BEGIN PUBLIC KEY-----\ntest_public_key_data\n-----END PUBLIC KEY-----"
}
}
keystore_path = tmp_path / "validator_keys.json"
with open(keystore_path, 'w') as f:
json.dump(keystore, f)
# Monkey patch keystore path
import aitbc_cli.commands.gpu_marketplace as gm_module
original_path = gm_module.__dict__.get('keystore_path')
yield str(keystore_path)
# Restore
if original_path:
gm_module.keystore_path = original_path
@pytest.fixture
def runner():
"""Create a Click CLI runner"""
return CliRunner()
def test_gpu_offer_command(mock_credentials_file, mock_keystore, runner):
"""Test GPU offer command"""
from aitbc_cli.commands.gpu_marketplace import gpu
with patch('aitbc_cli.commands.gpu_marketplace.httpx.Client') as mock_client:
mock_response = MagicMock()
mock_response.status_code = 200
mock_response.json.return_value = {"transaction_id": "test_tx_id"}
mock_client.return_value.__enter__.return_value.post.return_value = mock_response
result = runner.invoke(gpu, ['offer', '2', '0.5', '24'])
assert result.exit_code == 0
assert "GPU offer created successfully" in result.output
def test_gpu_bid_command(mock_credentials_file, mock_keystore, runner):
"""Test GPU bid command"""
from aitbc_cli.commands.gpu_marketplace import gpu
with patch('aitbc_cli.commands.gpu_marketplace.httpx.Client') as mock_client:
mock_response = MagicMock()
mock_response.status_code = 200
mock_response.json.return_value = {"transaction_id": "test_tx_id"}
mock_client.return_value.__enter__.return_value.post.return_value = mock_response
result = runner.invoke(gpu, ['bid', '2', '1.0', '24'])
assert result.exit_code == 0
assert "GPU bid created successfully" in result.output
def test_gpu_list_command(mock_credentials_file, runner):
"""Test GPU list command"""
from aitbc_cli.commands.gpu_marketplace import gpu
with patch('aitbc_cli.commands.gpu_marketplace.httpx.Client') as mock_client:
mock_response = MagicMock()
mock_response.status_code = 200
mock_response.json.return_value = [
{
"action": "offer",
"offer_id": "gpu_offer_test",
"gpu_count": 2,
"price_per_gpu": 0.5,
"duration_hours": 24,
"total_price": 24.0,
"status": "active",
"provider_node_id": "test_provider",
"created_at": "2024-01-01T00:00:00"
}
]
mock_client.return_value.__enter__.return_value.get.return_value = mock_response
result = runner.invoke(gpu, ['list'])
assert result.exit_code == 0
def test_gpu_cancel_command(mock_credentials_file, mock_keystore, runner):
"""Test GPU cancel command"""
from aitbc_cli.commands.gpu_marketplace import gpu
with patch('aitbc_cli.commands.gpu_marketplace.httpx.Client') as mock_client:
mock_response = MagicMock()
mock_response.status_code = 200
mock_client.return_value.__enter__.return_value.post.return_value = mock_response
result = runner.invoke(gpu, ['cancel', 'gpu_offer_test123'])
assert result.exit_code == 0
assert "cancelled successfully" in result.output
def test_gpu_accept_command(mock_credentials_file, mock_keystore, runner):
"""Test GPU accept command"""
from aitbc_cli.commands.gpu_marketplace import gpu
with patch('aitbc_cli.commands.gpu_marketplace.httpx.Client') as mock_client:
mock_response = MagicMock()
mock_response.status_code = 200
mock_client.return_value.__enter__.return_value.post.return_value = mock_response
result = runner.invoke(gpu, ['accept', 'gpu_bid_test123'])
assert result.exit_code == 0
assert "accepted successfully" in result.output
def test_gpu_status_command(mock_credentials_file, runner):
"""Test GPU status command"""
from aitbc_cli.commands.gpu_marketplace import gpu
with patch('aitbc_cli.commands.gpu_marketplace.httpx.Client') as mock_client:
mock_response = MagicMock()
mock_response.status_code = 200
mock_response.json.return_value = [
{
"action": "offer",
"offer_id": "gpu_offer_test",
"gpu_count": 2,
"price_per_gpu": 0.5,
"duration_hours": 24,
"total_price": 24.0,
"status": "active",
"provider_node_id": "test_provider",
"created_at": "2024-01-01T00:00:00"
}
]
mock_client.return_value.__enter__.return_value.get.return_value = mock_response
result = runner.invoke(gpu, ['status', 'gpu_offer_test'])
assert result.exit_code == 0
def test_gpu_match_command(mock_credentials_file, runner):
"""Test GPU match command"""
from aitbc_cli.commands.gpu_marketplace import gpu
with patch('aitbc_cli.commands.gpu_marketplace.httpx.Client') as mock_client:
# Mock the GET request for transactions
mock_get_response = MagicMock()
mock_get_response.status_code = 200
mock_get_response.json.return_value = [
{
"action": "offer",
"offer_id": "gpu_offer_test",
"gpu_count": 2,
"price_per_gpu": 0.5,
"duration_hours": 24,
"total_price": 24.0,
"status": "active",
"provider_node_id": "test_provider"
},
{
"action": "bid",
"bid_id": "gpu_bid_test",
"gpu_count": 2,
"max_price_per_gpu": 1.0,
"duration_hours": 24,
"max_total_price": 48.0,
"status": "pending",
"bidder_node_id": "test_bidder"
}
]
# Mock the POST request for match transaction
mock_post_response = MagicMock()
mock_post_response.status_code = 200
mock_client.return_value.__enter__.return_value.get.return_value = mock_get_response
mock_client.return_value.__enter__.return_value.post.return_value = mock_post_response
result = runner.invoke(gpu, ['match'])
assert result.exit_code == 0
def test_gpu_providers_command(mock_credentials_file, runner):
"""Test GPU providers command"""
from aitbc_cli.commands.gpu_marketplace import gpu
result = runner.invoke(gpu, ['providers'])
assert result.exit_code == 0
if __name__ == "__main__":
pytest.main([__file__])