Update Python version requirements and fix compatibility issues
- Bump minimum Python version from 3.11 to 3.13 across all apps - Add Python 3.11-3.13 test matrix to CLI workflow - Document Python 3.11+ requirement in .env.example - Fix Starlette Broadcast removal with in-process fallback implementation - Add _InProcessBroadcast class for tests when Starlette Broadcast is unavailable - Refactor API key validators to read live settings instead of cached values - Update database models with explicit
This commit is contained in:
207
tests/cli/test_agent_commands.py
Normal file
207
tests/cli/test_agent_commands.py
Normal file
@@ -0,0 +1,207 @@
|
||||
"""Tests for agent commands"""
|
||||
|
||||
import pytest
|
||||
import json
|
||||
from unittest.mock import Mock, patch
|
||||
from click.testing import CliRunner
|
||||
from aitbc_cli.commands.agent import agent, network, learning
|
||||
|
||||
|
||||
class TestAgentCommands:
|
||||
"""Test agent workflow and execution management commands"""
|
||||
|
||||
def setup_method(self):
|
||||
"""Setup test environment"""
|
||||
self.runner = CliRunner()
|
||||
self.config = {
|
||||
'coordinator_url': 'http://test:8000',
|
||||
'api_key': 'test_key'
|
||||
}
|
||||
|
||||
@patch('aitbc_cli.commands.agent.httpx.Client')
|
||||
def test_agent_create_success(self, mock_client):
|
||||
"""Test successful agent creation"""
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 201
|
||||
mock_response.json.return_value = {
|
||||
'id': 'agent_123',
|
||||
'name': 'Test Agent',
|
||||
'status': 'created'
|
||||
}
|
||||
mock_client.return_value.__enter__.return_value.post.return_value = mock_response
|
||||
|
||||
result = self.runner.invoke(agent, [
|
||||
'create',
|
||||
'--name', 'Test Agent',
|
||||
'--description', 'Test Description',
|
||||
'--verification', 'full'
|
||||
], obj={'config': self.config, 'output_format': 'json'})
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert 'agent_123' in result.output
|
||||
|
||||
@patch('aitbc_cli.commands.agent.httpx.Client')
|
||||
def test_agent_list_success(self, mock_client):
|
||||
"""Test successful agent listing"""
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.json.return_value = [
|
||||
{'id': 'agent_1', 'name': 'Agent 1'},
|
||||
{'id': 'agent_2', 'name': 'Agent 2'}
|
||||
]
|
||||
mock_client.return_value.__enter__.return_value.get.return_value = mock_response
|
||||
|
||||
result = self.runner.invoke(agent, [
|
||||
'list',
|
||||
'--type', 'multimodal',
|
||||
'--limit', '10'
|
||||
], obj={'config': self.config, 'output_format': 'json'})
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert 'agent_1' in result.output
|
||||
|
||||
@patch('aitbc_cli.commands.agent.httpx.Client')
|
||||
def test_agent_execute_success(self, mock_client):
|
||||
"""Test successful agent execution"""
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 202
|
||||
mock_response.json.return_value = {
|
||||
'id': 'exec_123',
|
||||
'agent_id': 'agent_123',
|
||||
'status': 'running'
|
||||
}
|
||||
mock_client.return_value.__enter__.return_value.post.return_value = mock_response
|
||||
|
||||
with self.runner.isolated_filesystem():
|
||||
with open('inputs.json', 'w') as f:
|
||||
json.dump({'prompt': 'test prompt'}, f)
|
||||
|
||||
result = self.runner.invoke(agent, [
|
||||
'execute',
|
||||
'agent_123',
|
||||
'--inputs', 'inputs.json',
|
||||
'--verification', 'basic'
|
||||
], obj={'config': self.config, 'output_format': 'json'})
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert 'exec_123' in result.output
|
||||
|
||||
|
||||
class TestNetworkCommands:
|
||||
"""Test multi-agent collaborative network commands"""
|
||||
|
||||
def setup_method(self):
|
||||
"""Setup test environment"""
|
||||
self.runner = CliRunner()
|
||||
self.config = {
|
||||
'coordinator_url': 'http://test:8000',
|
||||
'api_key': 'test_key'
|
||||
}
|
||||
|
||||
@patch('aitbc_cli.commands.agent.httpx.Client')
|
||||
def test_network_create_success(self, mock_client):
|
||||
"""Test successful network creation"""
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 201
|
||||
mock_response.json.return_value = {
|
||||
'id': 'network_123',
|
||||
'name': 'Test Network',
|
||||
'agents': ['agent_1', 'agent_2']
|
||||
}
|
||||
mock_client.return_value.__enter__.return_value.post.return_value = mock_response
|
||||
|
||||
result = self.runner.invoke(network, [
|
||||
'create',
|
||||
'--name', 'Test Network',
|
||||
'--agents', 'agent_1,agent_2',
|
||||
'--coordination', 'decentralized'
|
||||
], obj={'config': self.config, 'output_format': 'json'})
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert 'network_123' in result.output
|
||||
|
||||
@patch('aitbc_cli.commands.agent.httpx.Client')
|
||||
def test_network_execute_success(self, mock_client):
|
||||
"""Test successful network task execution"""
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 202
|
||||
mock_response.json.return_value = {
|
||||
'id': 'net_exec_123',
|
||||
'network_id': 'network_123',
|
||||
'status': 'running'
|
||||
}
|
||||
mock_client.return_value.__enter__.return_value.post.return_value = mock_response
|
||||
|
||||
with self.runner.isolated_filesystem():
|
||||
with open('task.json', 'w') as f:
|
||||
json.dump({'task': 'test task'}, f)
|
||||
|
||||
result = self.runner.invoke(network, [
|
||||
'execute',
|
||||
'network_123',
|
||||
'--task', 'task.json',
|
||||
'--priority', 'high'
|
||||
], obj={'config': self.config, 'output_format': 'json'})
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert 'net_exec_123' in result.output
|
||||
|
||||
|
||||
class TestLearningCommands:
|
||||
"""Test agent adaptive learning commands"""
|
||||
|
||||
def setup_method(self):
|
||||
"""Setup test environment"""
|
||||
self.runner = CliRunner()
|
||||
self.config = {
|
||||
'coordinator_url': 'http://test:8000',
|
||||
'api_key': 'test_key'
|
||||
}
|
||||
|
||||
@patch('aitbc_cli.commands.agent.httpx.Client')
|
||||
def test_learning_enable_success(self, mock_client):
|
||||
"""Test successful learning enable"""
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.json.return_value = {
|
||||
'agent_id': 'agent_123',
|
||||
'learning_enabled': True,
|
||||
'mode': 'reinforcement'
|
||||
}
|
||||
mock_client.return_value.__enter__.return_value.post.return_value = mock_response
|
||||
|
||||
result = self.runner.invoke(learning, [
|
||||
'enable',
|
||||
'agent_123',
|
||||
'--mode', 'reinforcement',
|
||||
'--learning-rate', '0.001'
|
||||
], obj={'config': self.config, 'output_format': 'json'})
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert 'learning_enabled' in result.output
|
||||
|
||||
@patch('aitbc_cli.commands.agent.httpx.Client')
|
||||
def test_learning_train_success(self, mock_client):
|
||||
"""Test successful learning training"""
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 202
|
||||
mock_response.json.return_value = {
|
||||
'id': 'training_123',
|
||||
'agent_id': 'agent_123',
|
||||
'status': 'training'
|
||||
}
|
||||
mock_client.return_value.__enter__.return_value.post.return_value = mock_response
|
||||
|
||||
with self.runner.isolated_filesystem():
|
||||
with open('feedback.json', 'w') as f:
|
||||
json.dump({'feedback': 'positive'}, f)
|
||||
|
||||
result = self.runner.invoke(learning, [
|
||||
'train',
|
||||
'agent_123',
|
||||
'--feedback', 'feedback.json',
|
||||
'--epochs', '10'
|
||||
], obj={'config': self.config, 'output_format': 'json'})
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert 'training_123' in result.output
|
||||
@@ -19,6 +19,8 @@ from starlette.testclient import TestClient as StarletteTestClient
|
||||
# Ensure coordinator-api src is importable
|
||||
# ---------------------------------------------------------------------------
|
||||
_COORD_SRC = str(Path(__file__).resolve().parents[2] / "apps" / "coordinator-api" / "src")
|
||||
_CRYPTO_SRC = str(Path(__file__).resolve().parents[2] / "packages" / "py" / "aitbc-crypto" / "src")
|
||||
_SDK_SRC = str(Path(__file__).resolve().parents[2] / "packages" / "py" / "aitbc-sdk" / "src")
|
||||
|
||||
_existing = sys.modules.get("app")
|
||||
if _existing is not None:
|
||||
@@ -27,9 +29,11 @@ if _existing is not None:
|
||||
for _k in [k for k in sys.modules if k == "app" or k.startswith("app.")]:
|
||||
del sys.modules[_k]
|
||||
|
||||
if _COORD_SRC in sys.path:
|
||||
sys.path.remove(_COORD_SRC)
|
||||
sys.path.insert(0, _COORD_SRC)
|
||||
# Add all necessary paths to sys.path
|
||||
for src_path in [_COORD_SRC, _CRYPTO_SRC, _SDK_SRC]:
|
||||
if src_path in sys.path:
|
||||
sys.path.remove(src_path)
|
||||
sys.path.insert(0, src_path)
|
||||
|
||||
from app.config import settings # noqa: E402
|
||||
from app.main import create_app # noqa: E402
|
||||
|
||||
452
tests/cli/test_marketplace_advanced_commands.py
Normal file
452
tests/cli/test_marketplace_advanced_commands.py
Normal file
@@ -0,0 +1,452 @@
|
||||
"""Tests for advanced marketplace commands"""
|
||||
|
||||
import pytest
|
||||
import json
|
||||
import base64
|
||||
from unittest.mock import Mock, patch
|
||||
from click.testing import CliRunner
|
||||
from aitbc_cli.commands.marketplace_advanced import advanced, models, analytics, trading, dispute
|
||||
|
||||
|
||||
class TestModelsCommands:
|
||||
"""Test advanced model NFT operations commands"""
|
||||
|
||||
def setup_method(self):
|
||||
"""Setup test environment"""
|
||||
self.runner = CliRunner()
|
||||
self.config = {
|
||||
'coordinator_url': 'http://test:8000',
|
||||
'api_key': 'test_key'
|
||||
}
|
||||
|
||||
@patch('aitbc_cli.commands.marketplace_advanced.httpx.Client')
|
||||
def test_models_list_success(self, mock_client):
|
||||
"""Test successful advanced models listing"""
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.json.return_value = [
|
||||
{
|
||||
'id': 'nft_1',
|
||||
'name': 'Advanced Model 1',
|
||||
'nft_version': '2.0',
|
||||
'rating': 4.5,
|
||||
'category': 'multimodal'
|
||||
},
|
||||
{
|
||||
'id': 'nft_2',
|
||||
'name': 'Advanced Model 2',
|
||||
'nft_version': '2.0',
|
||||
'rating': 4.2,
|
||||
'category': 'text'
|
||||
}
|
||||
]
|
||||
mock_client.return_value.__enter__.return_value.get.return_value = mock_response
|
||||
|
||||
result = self.runner.invoke(models, [
|
||||
'list',
|
||||
'--nft-version', '2.0',
|
||||
'--category', 'multimodal',
|
||||
'--rating-min', '4.0',
|
||||
'--limit', '10'
|
||||
], obj={'config': self.config, 'output_format': 'json'})
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert 'nft_1' in result.output
|
||||
assert '4.5' in result.output
|
||||
|
||||
@patch('aitbc_cli.commands.marketplace_advanced.httpx.Client')
|
||||
@patch('aitbc_cli.commands.marketplace_advanced.Path.exists')
|
||||
def test_models_mint_success(self, mock_exists, mock_client):
|
||||
"""Test successful model NFT minting"""
|
||||
mock_exists.return_value = True
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 201
|
||||
mock_response.json.return_value = {
|
||||
'id': 'nft_123',
|
||||
'name': 'Test Model',
|
||||
'nft_version': '2.0',
|
||||
'royalty_percentage': 5.0,
|
||||
'supply': 1
|
||||
}
|
||||
mock_client.return_value.__enter__.return_value.post.return_value = mock_response
|
||||
|
||||
with self.runner.isolated_filesystem():
|
||||
# Create dummy model file
|
||||
with open('model.pkl', 'wb') as f:
|
||||
f.write(b'fake model data')
|
||||
|
||||
# Create metadata file
|
||||
with open('metadata.json', 'w') as f:
|
||||
json.dump({
|
||||
'name': 'Test Model',
|
||||
'description': 'Test model description',
|
||||
'category': 'multimodal'
|
||||
}, f)
|
||||
|
||||
result = self.runner.invoke(models, [
|
||||
'mint',
|
||||
'--model-file', 'model.pkl',
|
||||
'--metadata', 'metadata.json',
|
||||
'--price', '100.0',
|
||||
'--royalty', '5.0',
|
||||
'--supply', '1'
|
||||
], obj={'config': self.config, 'output_format': 'json'})
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert 'nft_123' in result.output
|
||||
|
||||
@patch('aitbc_cli.commands.marketplace_advanced.httpx.Client')
|
||||
@patch('aitbc_cli.commands.marketplace_advanced.Path.exists')
|
||||
def test_models_update_success(self, mock_exists, mock_client):
|
||||
"""Test successful model NFT update"""
|
||||
mock_exists.return_value = True
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.json.return_value = {
|
||||
'id': 'nft_123',
|
||||
'version': '2.1',
|
||||
'compatibility': 'backward',
|
||||
'update_time': '2026-02-24T10:00:00Z'
|
||||
}
|
||||
mock_client.return_value.__enter__.return_value.post.return_value = mock_response
|
||||
|
||||
with self.runner.isolated_filesystem():
|
||||
# Create dummy version file
|
||||
with open('model_v2.pkl', 'wb') as f:
|
||||
f.write(b'fake model v2 data')
|
||||
|
||||
result = self.runner.invoke(models, [
|
||||
'update',
|
||||
'nft_123',
|
||||
'--new-version', 'model_v2.pkl',
|
||||
'--version-notes', 'Performance improvements',
|
||||
'--compatibility', 'backward'
|
||||
], obj={'config': self.config, 'output_format': 'json'})
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert '2.1' in result.output
|
||||
|
||||
@patch('aitbc_cli.commands.marketplace_advanced.httpx.Client')
|
||||
def test_models_verify_success(self, mock_client):
|
||||
"""Test successful model verification"""
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.json.return_value = {
|
||||
'nft_id': 'nft_123',
|
||||
'authentic': True,
|
||||
'integrity_check': 'passed',
|
||||
'performance_verified': True,
|
||||
'verification_score': 0.95
|
||||
}
|
||||
mock_client.return_value.__enter__.return_value.post.return_value = mock_response
|
||||
|
||||
result = self.runner.invoke(models, [
|
||||
'verify',
|
||||
'nft_123',
|
||||
'--deep-scan',
|
||||
'--check-integrity',
|
||||
'--verify-performance'
|
||||
], obj={'config': self.config, 'output_format': 'json'})
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert 'authentic' in result.output
|
||||
assert '0.95' in result.output
|
||||
|
||||
|
||||
class TestAnalyticsCommands:
|
||||
"""Test marketplace analytics and insights commands"""
|
||||
|
||||
def setup_method(self):
|
||||
"""Setup test environment"""
|
||||
self.runner = CliRunner()
|
||||
self.config = {
|
||||
'coordinator_url': 'http://test:8000',
|
||||
'api_key': 'test_key'
|
||||
}
|
||||
|
||||
@patch('aitbc_cli.commands.marketplace_advanced.httpx.Client')
|
||||
def test_analytics_success(self, mock_client):
|
||||
"""Test successful analytics retrieval"""
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.json.return_value = {
|
||||
'period': '30d',
|
||||
'metrics': {
|
||||
'volume': 1500000,
|
||||
'trends': {'growth': 15.5, 'direction': 'up'},
|
||||
'top_categories': ['multimodal', 'text', 'image'],
|
||||
'average_price': 250.0
|
||||
}
|
||||
}
|
||||
mock_client.return_value.__enter__.return_value.get.return_value = mock_response
|
||||
|
||||
result = self.runner.invoke(analytics, [
|
||||
'analytics',
|
||||
'--period', '30d',
|
||||
'--metrics', 'volume,trends',
|
||||
'--category', 'multimodal',
|
||||
'--format', 'json'
|
||||
], obj={'config': self.config, 'output_format': 'json'})
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert '1500000' in result.output
|
||||
assert '15.5' in result.output
|
||||
|
||||
@patch('aitbc_cli.commands.marketplace_advanced.httpx.Client')
|
||||
def test_benchmark_success(self, mock_client):
|
||||
"""Test successful model benchmarking"""
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 202
|
||||
mock_response.json.return_value = {
|
||||
'id': 'benchmark_123',
|
||||
'model_id': 'model_123',
|
||||
'status': 'running',
|
||||
'datasets': ['standard'],
|
||||
'iterations': 100
|
||||
}
|
||||
mock_client.return_value.__enter__.return_value.post.return_value = mock_response
|
||||
|
||||
result = self.runner.invoke(analytics, [
|
||||
'benchmark',
|
||||
'model_123',
|
||||
'--competitors',
|
||||
'--datasets', 'standard',
|
||||
'--iterations', '100'
|
||||
], obj={'config': self.config, 'output_format': 'json'})
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert 'benchmark_123' in result.output
|
||||
|
||||
@patch('aitbc_cli.commands.marketplace_advanced.httpx.Client')
|
||||
def test_trends_success(self, mock_client):
|
||||
"""Test successful market trends analysis"""
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.json.return_value = {
|
||||
'category': 'multimodal',
|
||||
'forecast_period': '7d',
|
||||
'trends': {
|
||||
'current': {'price': 300, 'volume': 1000},
|
||||
'forecast': {'price': 320, 'volume': 1100},
|
||||
'confidence': 0.85
|
||||
},
|
||||
'indicators': ['bullish', 'growth']
|
||||
}
|
||||
mock_client.return_value.__enter__.return_value.get.return_value = mock_response
|
||||
|
||||
result = self.runner.invoke(analytics, [
|
||||
'trends',
|
||||
'--category', 'multimodal',
|
||||
'--forecast', '7d',
|
||||
'--confidence', '0.8'
|
||||
], obj={'config': self.config, 'output_format': 'json'})
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert '320' in result.output
|
||||
assert '0.85' in result.output
|
||||
|
||||
@patch('aitbc_cli.commands.marketplace_advanced.httpx.Client')
|
||||
def test_report_success(self, mock_client):
|
||||
"""Test successful report generation"""
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 202
|
||||
mock_response.json.return_value = {
|
||||
'id': 'report_123',
|
||||
'format': 'pdf',
|
||||
'status': 'generating',
|
||||
'sections': ['overview', 'trends', 'analytics'],
|
||||
'estimated_completion': '2026-02-24T11:00:00Z'
|
||||
}
|
||||
mock_client.return_value.__enter__.return_value.post.return_value = mock_response
|
||||
|
||||
result = self.runner.invoke(analytics, [
|
||||
'report',
|
||||
'--format', 'pdf',
|
||||
'--email', 'test@example.com',
|
||||
'--sections', 'overview,trends,analytics'
|
||||
], obj={'config': self.config, 'output_format': 'json'})
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert 'report_123' in result.output
|
||||
|
||||
|
||||
class TestTradingCommands:
|
||||
"""Test advanced trading features commands"""
|
||||
|
||||
def setup_method(self):
|
||||
"""Setup test environment"""
|
||||
self.runner = CliRunner()
|
||||
self.config = {
|
||||
'coordinator_url': 'http://test:8000',
|
||||
'api_key': 'test_key'
|
||||
}
|
||||
|
||||
@patch('aitbc_cli.commands.marketplace_advanced.httpx.Client')
|
||||
def test_bid_success(self, mock_client):
|
||||
"""Test successful auction bid"""
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.json.return_value = {
|
||||
'auction_id': 'auction_123',
|
||||
'bid_id': 'bid_456',
|
||||
'amount': 1000.0,
|
||||
'status': 'active',
|
||||
'current_high_bid': 1000.0
|
||||
}
|
||||
mock_client.return_value.__enter__.return_value.post.return_value = mock_response
|
||||
|
||||
result = self.runner.invoke(trading, [
|
||||
'bid',
|
||||
'auction_123',
|
||||
'--amount', '1000.0',
|
||||
'--max-auto-bid', '1500.0',
|
||||
'--proxy'
|
||||
], obj={'config': self.config, 'output_format': 'json'})
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert 'bid_456' in result.output
|
||||
assert '1000.0' in result.output
|
||||
|
||||
@patch('aitbc_cli.commands.marketplace_advanced.httpx.Client')
|
||||
def test_royalties_success(self, mock_client):
|
||||
"""Test successful royalty agreement creation"""
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 201
|
||||
mock_response.json.return_value = {
|
||||
'id': 'royalty_123',
|
||||
'model_id': 'model_123',
|
||||
'recipients': [
|
||||
{'address': '0x123...', 'percentage': 10.0},
|
||||
{'address': '0x456...', 'percentage': 5.0}
|
||||
],
|
||||
'smart_contract': True,
|
||||
'status': 'active'
|
||||
}
|
||||
mock_client.return_value.__enter__.return_value.post.return_value = mock_response
|
||||
|
||||
result = self.runner.invoke(trading, [
|
||||
'royalties',
|
||||
'model_123',
|
||||
'--recipients', '0x123...:10,0x456...:5',
|
||||
'--smart-contract'
|
||||
], obj={'config': self.config, 'output_format': 'json'})
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert 'royalty_123' in result.output
|
||||
assert '10.0' in result.output
|
||||
|
||||
@patch('aitbc_cli.commands.marketplace_advanced.httpx.Client')
|
||||
def test_execute_success(self, mock_client):
|
||||
"""Test successful trading strategy execution"""
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 202
|
||||
mock_response.json.return_value = {
|
||||
'id': 'execution_123',
|
||||
'strategy': 'arbitrage',
|
||||
'budget': 5000.0,
|
||||
'risk_level': 'medium',
|
||||
'status': 'executing'
|
||||
}
|
||||
mock_client.return_value.__enter__.return_value.post.return_value = mock_response
|
||||
|
||||
result = self.runner.invoke(trading, [
|
||||
'execute',
|
||||
'--strategy', 'arbitrage',
|
||||
'--budget', '5000.0',
|
||||
'--risk-level', 'medium'
|
||||
], obj={'config': self.config, 'output_format': 'json'})
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert 'execution_123' in result.output
|
||||
assert 'arbitrage' in result.output
|
||||
|
||||
|
||||
class TestDisputeCommands:
|
||||
"""Test dispute resolution operations commands"""
|
||||
|
||||
def setup_method(self):
|
||||
"""Setup test environment"""
|
||||
self.runner = CliRunner()
|
||||
self.config = {
|
||||
'coordinator_url': 'http://test:8000',
|
||||
'api_key': 'test_key'
|
||||
}
|
||||
|
||||
@patch('aitbc_cli.commands.marketplace_advanced.httpx.Client')
|
||||
def test_dispute_file_success(self, mock_client):
|
||||
"""Test successful dispute filing"""
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 201
|
||||
mock_response.json.return_value = {
|
||||
'id': 'dispute_123',
|
||||
'transaction_id': 'tx_456',
|
||||
'reason': 'Model quality issues',
|
||||
'category': 'quality',
|
||||
'status': 'pending'
|
||||
}
|
||||
mock_client.return_value.__enter__.return_value.post.return_value = mock_response
|
||||
|
||||
with self.runner.isolated_filesystem():
|
||||
# Create dummy evidence file
|
||||
with open('evidence.pdf', 'wb') as f:
|
||||
f.write(b'fake evidence data')
|
||||
|
||||
result = self.runner.invoke(dispute, [
|
||||
'file',
|
||||
'tx_456',
|
||||
'--reason', 'Model quality issues',
|
||||
'--category', 'quality',
|
||||
'--evidence', 'evidence.pdf'
|
||||
], obj={'config': self.config, 'output_format': 'json'})
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert 'dispute_123' in result.output
|
||||
|
||||
@patch('aitbc_cli.commands.marketplace_advanced.httpx.Client')
|
||||
def test_dispute_status_success(self, mock_client):
|
||||
"""Test successful dispute status retrieval"""
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.json.return_value = {
|
||||
'id': 'dispute_123',
|
||||
'status': 'under_review',
|
||||
'progress': 45,
|
||||
'evidence_submitted': 2,
|
||||
'reviewer_assigned': True,
|
||||
'estimated_resolution': '2026-02-26T00:00:00Z'
|
||||
}
|
||||
mock_client.return_value.__enter__.return_value.get.return_value = mock_response
|
||||
|
||||
result = self.runner.invoke(dispute, [
|
||||
'status',
|
||||
'dispute_123'
|
||||
], obj={'config': self.config, 'output_format': 'json'})
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert 'under_review' in result.output
|
||||
assert '45' in result.output
|
||||
|
||||
@patch('aitbc_cli.commands.marketplace_advanced.httpx.Client')
|
||||
def test_dispute_resolve_success(self, mock_client):
|
||||
"""Test successful dispute resolution proposal"""
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.json.return_value = {
|
||||
'dispute_id': 'dispute_123',
|
||||
'resolution_id': 'res_456',
|
||||
'resolution': 'Partial refund - 50%',
|
||||
'status': 'proposed',
|
||||
'proposed_by': 'seller',
|
||||
'proposal_time': '2026-02-24T10:30:00Z'
|
||||
}
|
||||
mock_client.return_value.__enter__.return_value.post.return_value = mock_response
|
||||
|
||||
result = self.runner.invoke(dispute, [
|
||||
'resolve',
|
||||
'dispute_123',
|
||||
'--resolution', 'Partial refund - 50%'
|
||||
], obj={'config': self.config, 'output_format': 'json'})
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert 'res_456' in result.output
|
||||
assert 'proposed' in result.output
|
||||
267
tests/cli/test_multimodal_commands.py
Normal file
267
tests/cli/test_multimodal_commands.py
Normal file
@@ -0,0 +1,267 @@
|
||||
"""Tests for multi-modal processing commands"""
|
||||
|
||||
import pytest
|
||||
import json
|
||||
import base64
|
||||
from unittest.mock import Mock, patch
|
||||
from click.testing import CliRunner
|
||||
from aitbc_cli.commands.multimodal import multimodal, convert, search, attention
|
||||
|
||||
|
||||
class TestMultiModalCommands:
|
||||
"""Test multi-modal agent processing commands"""
|
||||
|
||||
def setup_method(self):
|
||||
"""Setup test environment"""
|
||||
self.runner = CliRunner()
|
||||
self.config = {
|
||||
'coordinator_url': 'http://test:8000',
|
||||
'api_key': 'test_key'
|
||||
}
|
||||
|
||||
@patch('aitbc_cli.commands.multimodal.httpx.Client')
|
||||
def test_multimodal_agent_create_success(self, mock_client):
|
||||
"""Test successful multi-modal agent creation"""
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 201
|
||||
mock_response.json.return_value = {
|
||||
'id': 'multimodal_agent_123',
|
||||
'name': 'MultiModal Agent',
|
||||
'modalities': ['text', 'image']
|
||||
}
|
||||
mock_client.return_value.__enter__.return_value.post.return_value = mock_response
|
||||
|
||||
result = self.runner.invoke(multimodal, [
|
||||
'agent',
|
||||
'--name', 'MultiModal Agent',
|
||||
'--modalities', 'text,image',
|
||||
'--gpu-acceleration'
|
||||
], obj={'config': self.config, 'output_format': 'json'})
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert 'multimodal_agent_123' in result.output
|
||||
|
||||
@patch('aitbc_cli.commands.multimodal.httpx.Client')
|
||||
@patch('aitbc_cli.commands.multimodal.Path.exists')
|
||||
def test_multimodal_process_success(self, mock_exists, mock_client):
|
||||
"""Test successful multi-modal processing"""
|
||||
mock_exists.return_value = True
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.json.return_value = {
|
||||
'result': 'processed',
|
||||
'modalities_used': ['text', 'image']
|
||||
}
|
||||
mock_client.return_value.__enter__.return_value.post.return_value = mock_response
|
||||
|
||||
with self.runner.isolated_filesystem():
|
||||
# Create a dummy image file
|
||||
with open('test_image.jpg', 'wb') as f:
|
||||
f.write(b'fake image data')
|
||||
|
||||
result = self.runner.invoke(multimodal, [
|
||||
'process',
|
||||
'multimodal_agent_123',
|
||||
'--text', 'Test prompt',
|
||||
'--image', 'test_image.jpg',
|
||||
'--output-format', 'json'
|
||||
], obj={'config': self.config, 'output_format': 'json'})
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert 'processed' in result.output
|
||||
|
||||
@patch('aitbc_cli.commands.multimodal.httpx.Client')
|
||||
def test_multimodal_benchmark_success(self, mock_client):
|
||||
"""Test successful multi-modal benchmarking"""
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 202
|
||||
mock_response.json.return_value = {
|
||||
'id': 'benchmark_123',
|
||||
'agent_id': 'multimodal_agent_123',
|
||||
'status': 'running'
|
||||
}
|
||||
mock_client.return_value.__enter__.return_value.post.return_value = mock_response
|
||||
|
||||
result = self.runner.invoke(multimodal, [
|
||||
'benchmark',
|
||||
'multimodal_agent_123',
|
||||
'--dataset', 'coco_vqa',
|
||||
'--metrics', 'accuracy,latency',
|
||||
'--iterations', '50'
|
||||
], obj={'config': self.config, 'output_format': 'json'})
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert 'benchmark_123' in result.output
|
||||
|
||||
|
||||
class TestConvertCommands:
|
||||
"""Test cross-modal conversion commands"""
|
||||
|
||||
def setup_method(self):
|
||||
"""Setup test environment"""
|
||||
self.runner = CliRunner()
|
||||
self.config = {
|
||||
'coordinator_url': 'http://test:8000',
|
||||
'api_key': 'test_key'
|
||||
}
|
||||
|
||||
@patch('aitbc_cli.commands.multimodal.httpx.Client')
|
||||
@patch('aitbc_cli.commands.multimodal.Path.exists')
|
||||
def test_convert_success(self, mock_exists, mock_client):
|
||||
"""Test successful modality conversion"""
|
||||
mock_exists.return_value = True
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.json.return_value = {
|
||||
'output_data': base64.b64encode(b'converted data').decode(),
|
||||
'output_format': 'text'
|
||||
}
|
||||
mock_client.return_value.__enter__.return_value.post.return_value = mock_response
|
||||
|
||||
with self.runner.isolated_filesystem():
|
||||
# Create a dummy input file
|
||||
with open('input.jpg', 'wb') as f:
|
||||
f.write(b'fake image data')
|
||||
|
||||
result = self.runner.invoke(convert, [
|
||||
'convert',
|
||||
'--input', 'input.jpg',
|
||||
'--output', 'text',
|
||||
'--model', 'blip'
|
||||
], obj={'config': self.config, 'output_format': 'json'})
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert 'converted data' not in result.output # Should be base64 encoded
|
||||
|
||||
|
||||
class TestSearchCommands:
|
||||
"""Test multi-modal search commands"""
|
||||
|
||||
def setup_method(self):
|
||||
"""Setup test environment"""
|
||||
self.runner = CliRunner()
|
||||
self.config = {
|
||||
'coordinator_url': 'http://test:8000',
|
||||
'api_key': 'test_key'
|
||||
}
|
||||
|
||||
@patch('aitbc_cli.commands.multimodal.httpx.Client')
|
||||
def test_search_success(self, mock_client):
|
||||
"""Test successful multi-modal search"""
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.json.return_value = {
|
||||
'results': [
|
||||
{'id': 'item_1', 'score': 0.95},
|
||||
{'id': 'item_2', 'score': 0.87}
|
||||
],
|
||||
'query': 'red car'
|
||||
}
|
||||
mock_client.return_value.__enter__.return_value.post.return_value = mock_response
|
||||
|
||||
result = self.runner.invoke(search, [
|
||||
'search',
|
||||
'red car',
|
||||
'--modalities', 'image,text',
|
||||
'--limit', '10',
|
||||
'--threshold', '0.8'
|
||||
], obj={'config': self.config, 'output_format': 'json'})
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert 'item_1' in result.output
|
||||
assert '0.95' in result.output
|
||||
|
||||
|
||||
class TestAttentionCommands:
|
||||
"""Test cross-modal attention analysis commands"""
|
||||
|
||||
def setup_method(self):
|
||||
"""Setup test environment"""
|
||||
self.runner = CliRunner()
|
||||
self.config = {
|
||||
'coordinator_url': 'http://test:8000',
|
||||
'api_key': 'test_key'
|
||||
}
|
||||
|
||||
@patch('aitbc_cli.commands.multimodal.httpx.Client')
|
||||
def test_attention_success(self, mock_client):
|
||||
"""Test successful attention analysis"""
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.json.return_value = {
|
||||
'attention_patterns': {
|
||||
'text_to_image': [0.8, 0.2],
|
||||
'image_to_text': [0.3, 0.7]
|
||||
},
|
||||
'visualization': base64.b64encode(b'fake viz data').decode()
|
||||
}
|
||||
mock_client.return_value.__enter__.return_value.post.return_value = mock_response
|
||||
|
||||
with self.runner.isolated_filesystem():
|
||||
with open('inputs.json', 'w') as f:
|
||||
json.dump({'text': 'test', 'image': 'test.jpg'}, f)
|
||||
|
||||
result = self.runner.invoke(attention, [
|
||||
'attention',
|
||||
'multimodal_agent_123',
|
||||
'--inputs', 'inputs.json',
|
||||
'--visualize'
|
||||
], obj={'config': self.config, 'output_format': 'json'})
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert 'attention_patterns' in result.output
|
||||
|
||||
|
||||
class TestMultiModalUtilities:
|
||||
"""Test multi-modal utility commands"""
|
||||
|
||||
def setup_method(self):
|
||||
"""Setup test environment"""
|
||||
self.runner = CliRunner()
|
||||
self.config = {
|
||||
'coordinator_url': 'http://test:8000',
|
||||
'api_key': 'test_key'
|
||||
}
|
||||
|
||||
@patch('aitbc_cli.commands.multimodal.httpx.Client')
|
||||
def test_capabilities_success(self, mock_client):
|
||||
"""Test successful capabilities listing"""
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.json.return_value = {
|
||||
'modalities': ['text', 'image', 'audio'],
|
||||
'models': ['blip', 'clip', 'whisper'],
|
||||
'gpu_acceleration': True
|
||||
}
|
||||
mock_client.return_value.__enter__.return_value.get.return_value = mock_response
|
||||
|
||||
result = self.runner.invoke(multimodal, [
|
||||
'capabilities',
|
||||
'multimodal_agent_123'
|
||||
], obj={'config': self.config, 'output_format': 'json'})
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert 'text' in result.output
|
||||
assert 'blip' in result.output
|
||||
|
||||
@patch('aitbc_cli.commands.multimodal.httpx.Client')
|
||||
def test_test_modality_success(self, mock_client):
|
||||
"""Test successful individual modality testing"""
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.json.return_value = {
|
||||
'modality': 'image',
|
||||
'test_result': 'passed',
|
||||
'performance': {'accuracy': 0.95, 'latency': 150}
|
||||
}
|
||||
mock_client.return_value.__enter__.return_value.post.return_value = mock_response
|
||||
|
||||
result = self.runner.invoke(multimodal, [
|
||||
'test',
|
||||
'multimodal_agent_123',
|
||||
'--modality', 'image'
|
||||
], obj={'config': self.config, 'output_format': 'json'})
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert 'passed' in result.output
|
||||
assert '0.95' in result.output
|
||||
437
tests/cli/test_openclaw_commands.py
Normal file
437
tests/cli/test_openclaw_commands.py
Normal file
@@ -0,0 +1,437 @@
|
||||
"""Tests for OpenClaw integration commands"""
|
||||
|
||||
import pytest
|
||||
import json
|
||||
from unittest.mock import Mock, patch
|
||||
from click.testing import CliRunner
|
||||
from aitbc_cli.commands.openclaw import openclaw, deploy, monitor, edge, routing, ecosystem
|
||||
|
||||
|
||||
class TestDeployCommands:
|
||||
"""Test agent deployment operations commands"""
|
||||
|
||||
def setup_method(self):
|
||||
"""Setup test environment"""
|
||||
self.runner = CliRunner()
|
||||
self.config = {
|
||||
'coordinator_url': 'http://test:8000',
|
||||
'api_key': 'test_key'
|
||||
}
|
||||
|
||||
@patch('aitbc_cli.commands.openclaw.httpx.Client')
|
||||
def test_deploy_success(self, mock_client):
|
||||
"""Test successful agent deployment"""
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 202
|
||||
mock_response.json.return_value = {
|
||||
'id': 'deployment_123',
|
||||
'agent_id': 'agent_123',
|
||||
'region': 'us-west',
|
||||
'status': 'deploying'
|
||||
}
|
||||
mock_client.return_value.__enter__.return_value.post.return_value = mock_response
|
||||
|
||||
result = self.runner.invoke(deploy, [
|
||||
'deploy',
|
||||
'agent_123',
|
||||
'--region', 'us-west',
|
||||
'--instances', '3',
|
||||
'--instance-type', 'standard',
|
||||
'--auto-scale'
|
||||
], obj={'config': self.config, 'output_format': 'json'})
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert 'deployment_123' in result.output
|
||||
|
||||
@patch('aitbc_cli.commands.openclaw.httpx.Client')
|
||||
def test_scale_success(self, mock_client):
|
||||
"""Test successful deployment scaling"""
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.json.return_value = {
|
||||
'deployment_id': 'deployment_123',
|
||||
'instances': 5,
|
||||
'auto_scale': True,
|
||||
'status': 'scaled'
|
||||
}
|
||||
mock_client.return_value.__enter__.return_value.post.return_value = mock_response
|
||||
|
||||
result = self.runner.invoke(deploy, [
|
||||
'scale',
|
||||
'deployment_123',
|
||||
'--instances', '5',
|
||||
'--auto-scale',
|
||||
'--min-instances', '2',
|
||||
'--max-instances', '10'
|
||||
], obj={'config': self.config, 'output_format': 'json'})
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert 'scaled' in result.output
|
||||
|
||||
@patch('aitbc_cli.commands.openclaw.httpx.Client')
|
||||
def test_deploy_optimize_success(self, mock_client):
|
||||
"""Test successful deployment optimization"""
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.json.return_value = {
|
||||
'deployment_id': 'deployment_123',
|
||||
'optimization_completed': True,
|
||||
'objective': 'cost',
|
||||
'improvements': {'cost_reduction': 15, 'performance_impact': 2}
|
||||
}
|
||||
mock_client.return_value.__enter__.return_value.post.return_value = mock_response
|
||||
|
||||
result = self.runner.invoke(deploy, [
|
||||
'optimize',
|
||||
'deployment_123',
|
||||
'--objective', 'cost'
|
||||
], obj={'config': self.config, 'output_format': 'json'})
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert 'optimization_completed' in result.output
|
||||
|
||||
|
||||
class TestMonitorCommands:
|
||||
"""Test OpenClaw monitoring operations commands"""
|
||||
|
||||
def setup_method(self):
|
||||
"""Setup test environment"""
|
||||
self.runner = CliRunner()
|
||||
self.config = {
|
||||
'coordinator_url': 'http://test:8000',
|
||||
'api_key': 'test_key'
|
||||
}
|
||||
|
||||
@patch('aitbc_cli.commands.openclaw.httpx.Client')
|
||||
def test_monitor_success(self, mock_client):
|
||||
"""Test successful deployment monitoring"""
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.json.return_value = {
|
||||
'deployment_id': 'deployment_123',
|
||||
'status': 'running',
|
||||
'instances': 3,
|
||||
'metrics': {
|
||||
'latency': 85,
|
||||
'cost': 0.45,
|
||||
'throughput': 1200
|
||||
}
|
||||
}
|
||||
mock_client.return_value.__enter__.return_value.get.return_value = mock_response
|
||||
|
||||
result = self.runner.invoke(monitor, [
|
||||
'monitor',
|
||||
'deployment_123',
|
||||
'--metrics', 'latency,cost'
|
||||
], obj={'config': self.config, 'output_format': 'json'})
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert '85' in result.output
|
||||
assert '0.45' in result.output
|
||||
|
||||
@patch('aitbc_cli.commands.openclaw.httpx.Client')
|
||||
def test_status_success(self, mock_client):
|
||||
"""Test successful deployment status retrieval"""
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.json.return_value = {
|
||||
'deployment_id': 'deployment_123',
|
||||
'status': 'healthy',
|
||||
'uptime': '99.9%',
|
||||
'last_health_check': '2026-02-24T10:30:00Z'
|
||||
}
|
||||
mock_client.return_value.__enter__.return_value.get.return_value = mock_response
|
||||
|
||||
result = self.runner.invoke(monitor, [
|
||||
'status',
|
||||
'deployment_123'
|
||||
], obj={'config': self.config, 'output_format': 'json'})
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert 'healthy' in result.output
|
||||
|
||||
|
||||
class TestEdgeCommands:
|
||||
"""Test edge computing operations commands"""
|
||||
|
||||
def setup_method(self):
|
||||
"""Setup test environment"""
|
||||
self.runner = CliRunner()
|
||||
self.config = {
|
||||
'coordinator_url': 'http://test:8000',
|
||||
'api_key': 'test_key'
|
||||
}
|
||||
|
||||
@patch('aitbc_cli.commands.openclaw.httpx.Client')
|
||||
def test_edge_deploy_success(self, mock_client):
|
||||
"""Test successful edge deployment"""
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 202
|
||||
mock_response.json.return_value = {
|
||||
'id': 'edge_deployment_123',
|
||||
'agent_id': 'agent_123',
|
||||
'locations': ['us-west', 'eu-central'],
|
||||
'strategy': 'latency',
|
||||
'status': 'deploying'
|
||||
}
|
||||
mock_client.return_value.__enter__.return_value.post.return_value = mock_response
|
||||
|
||||
result = self.runner.invoke(edge, [
|
||||
'deploy',
|
||||
'agent_123',
|
||||
'--locations', 'us-west,eu-central',
|
||||
'--strategy', 'latency',
|
||||
'--replicas', '2'
|
||||
], obj={'config': self.config, 'output_format': 'json'})
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert 'edge_deployment_123' in result.output
|
||||
|
||||
@patch('aitbc_cli.commands.openclaw.httpx.Client')
|
||||
def test_edge_resources_success(self, mock_client):
|
||||
"""Test successful edge resources listing"""
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.json.return_value = {
|
||||
'locations': {
|
||||
'us-west': {'cpu_usage': 45, 'memory_usage': 60, 'available': True},
|
||||
'eu-central': {'cpu_usage': 30, 'memory_usage': 40, 'available': True}
|
||||
},
|
||||
'total_capacity': {'cpu': 1000, 'memory': '2TB'}
|
||||
}
|
||||
mock_client.return_value.__enter__.return_value.get.return_value = mock_response
|
||||
|
||||
result = self.runner.invoke(edge, [
|
||||
'resources',
|
||||
'--location', 'us-west'
|
||||
], obj={'config': self.config, 'output_format': 'json'})
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert '45' in result.output
|
||||
assert '60' in result.output
|
||||
|
||||
@patch('aitbc_cli.commands.openclaw.httpx.Client')
|
||||
def test_edge_optimize_success(self, mock_client):
|
||||
"""Test successful edge optimization"""
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.json.return_value = {
|
||||
'deployment_id': 'edge_deployment_123',
|
||||
'optimization_completed': True,
|
||||
'latency_target_ms': 100,
|
||||
'actual_latency_ms': 85,
|
||||
'cost_budget': 1.0,
|
||||
'actual_cost': 0.85
|
||||
}
|
||||
mock_client.return_value.__enter__.return_value.post.return_value = mock_response
|
||||
|
||||
result = self.runner.invoke(edge, [
|
||||
'optimize',
|
||||
'edge_deployment_123',
|
||||
'--latency-target', '100',
|
||||
'--cost-budget', '1.0'
|
||||
], obj={'config': self.config, 'output_format': 'json'})
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert '85' in result.output
|
||||
|
||||
@patch('aitbc_cli.commands.openclaw.httpx.Client')
|
||||
def test_edge_compliance_success(self, mock_client):
|
||||
"""Test successful edge compliance check"""
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.json.return_value = {
|
||||
'deployment_id': 'edge_deployment_123',
|
||||
'compliance_status': 'compliant',
|
||||
'standards': {
|
||||
'gdpr': {'compliant': True, 'score': 95},
|
||||
'hipaa': {'compliant': True, 'score': 92}
|
||||
},
|
||||
'last_check': '2026-02-24T10:00:00Z'
|
||||
}
|
||||
mock_client.return_value.__enter__.return_value.get.return_value = mock_response
|
||||
|
||||
result = self.runner.invoke(edge, [
|
||||
'compliance',
|
||||
'edge_deployment_123',
|
||||
'--standards', 'gdpr,hipaa'
|
||||
], obj={'config': self.config, 'output_format': 'json'})
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert 'compliant' in result.output
|
||||
assert '95' in result.output
|
||||
|
||||
|
||||
class TestRoutingCommands:
|
||||
"""Test agent skill routing commands"""
|
||||
|
||||
def setup_method(self):
|
||||
"""Setup test environment"""
|
||||
self.runner = CliRunner()
|
||||
self.config = {
|
||||
'coordinator_url': 'http://test:8000',
|
||||
'api_key': 'test_key'
|
||||
}
|
||||
|
||||
@patch('aitbc_cli.commands.openclaw.httpx.Client')
|
||||
def test_routing_optimize_success(self, mock_client):
|
||||
"""Test successful routing optimization"""
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.json.return_value = {
|
||||
'deployment_id': 'deployment_123',
|
||||
'routing_optimized': True,
|
||||
'algorithm': 'skill-based',
|
||||
'improvements': {
|
||||
'response_time': -20,
|
||||
'skill_match_accuracy': 15
|
||||
}
|
||||
}
|
||||
mock_client.return_value.__enter__.return_value.post.return_value = mock_response
|
||||
|
||||
result = self.runner.invoke(routing, [
|
||||
'optimize',
|
||||
'deployment_123',
|
||||
'--algorithm', 'skill-based',
|
||||
'--weights', '0.5,0.3,0.2'
|
||||
], obj={'config': self.config, 'output_format': 'json'})
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert 'routing_optimized' in result.output
|
||||
|
||||
@patch('aitbc_cli.commands.openclaw.httpx.Client')
|
||||
def test_routing_status_success(self, mock_client):
|
||||
"""Test successful routing status retrieval"""
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.json.return_value = {
|
||||
'deployment_id': 'deployment_123',
|
||||
'routing_algorithm': 'load-balanced',
|
||||
'active_routes': 15,
|
||||
'average_response_time': 120,
|
||||
'skill_match_rate': 0.87
|
||||
}
|
||||
mock_client.return_value.__enter__.return_value.get.return_value = mock_response
|
||||
|
||||
result = self.runner.invoke(routing, [
|
||||
'status',
|
||||
'deployment_123'
|
||||
], obj={'config': self.config, 'output_format': 'json'})
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert '120' in result.output
|
||||
assert '0.87' in result.output
|
||||
|
||||
|
||||
class TestEcosystemCommands:
|
||||
"""Test OpenClaw ecosystem development commands"""
|
||||
|
||||
def setup_method(self):
|
||||
"""Setup test environment"""
|
||||
self.runner = CliRunner()
|
||||
self.config = {
|
||||
'coordinator_url': 'http://test:8000',
|
||||
'api_key': 'test_key'
|
||||
}
|
||||
|
||||
@patch('aitbc_cli.commands.openclaw.httpx.Client')
|
||||
def test_ecosystem_create_success(self, mock_client):
|
||||
"""Test successful ecosystem solution creation"""
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 201
|
||||
mock_response.json.return_value = {
|
||||
'id': 'solution_123',
|
||||
'name': 'Test Solution',
|
||||
'type': 'agent',
|
||||
'status': 'created'
|
||||
}
|
||||
mock_client.return_value.__enter__.return_value.post.return_value = mock_response
|
||||
|
||||
with self.runner.isolated_filesystem():
|
||||
with open('package.zip', 'wb') as f:
|
||||
f.write(b'fake package data')
|
||||
|
||||
result = self.runner.invoke(ecosystem, [
|
||||
'create',
|
||||
'--name', 'Test Solution',
|
||||
'--type', 'agent',
|
||||
'--description', 'Test description',
|
||||
'--package', 'package.zip'
|
||||
], obj={'config': self.config, 'output_format': 'json'})
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert 'solution_123' in result.output
|
||||
|
||||
@patch('aitbc_cli.commands.openclaw.httpx.Client')
|
||||
def test_ecosystem_list_success(self, mock_client):
|
||||
"""Test successful ecosystem solution listing"""
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.json.return_value = [
|
||||
{'id': 'solution_1', 'name': 'Solution 1', 'type': 'agent'},
|
||||
{'id': 'solution_2', 'name': 'Solution 2', 'type': 'workflow'}
|
||||
]
|
||||
mock_client.return_value.__enter__.return_value.get.return_value = mock_response
|
||||
|
||||
result = self.runner.invoke(ecosystem, [
|
||||
'list',
|
||||
'--type', 'agent',
|
||||
'--limit', '10'
|
||||
], obj={'config': self.config, 'output_format': 'json'})
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert 'solution_1' in result.output
|
||||
|
||||
@patch('aitbc_cli.commands.openclaw.httpx.Client')
|
||||
def test_ecosystem_install_success(self, mock_client):
|
||||
"""Test successful ecosystem solution installation"""
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.json.return_value = {
|
||||
'solution_id': 'solution_123',
|
||||
'installation_completed': True,
|
||||
'status': 'installed',
|
||||
'installation_path': '/opt/openclaw/solutions/solution_123'
|
||||
}
|
||||
mock_client.return_value.__enter__.return_value.post.return_value = mock_response
|
||||
|
||||
result = self.runner.invoke(ecosystem, [
|
||||
'install',
|
||||
'solution_123'
|
||||
], obj={'config': self.config, 'output_format': 'json'})
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert 'installed' in result.output
|
||||
|
||||
|
||||
class TestOpenClawUtilities:
|
||||
"""Test OpenClaw utility commands"""
|
||||
|
||||
def setup_method(self):
|
||||
"""Setup test environment"""
|
||||
self.runner = CliRunner()
|
||||
self.config = {
|
||||
'coordinator_url': 'http://test:8000',
|
||||
'api_key': 'test_key'
|
||||
}
|
||||
|
||||
@patch('aitbc_cli.commands.openclaw.httpx.Client')
|
||||
def test_terminate_success(self, mock_client):
|
||||
"""Test successful deployment termination"""
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.json.return_value = {
|
||||
'deployment_id': 'deployment_123',
|
||||
'terminated': True,
|
||||
'status': 'terminated',
|
||||
'termination_time': '2026-02-24T11:00:00Z'
|
||||
}
|
||||
mock_client.return_value.__enter__.return_value.delete.return_value = mock_response
|
||||
|
||||
result = self.runner.invoke(openclaw, [
|
||||
'terminate',
|
||||
'deployment_123'
|
||||
], obj={'config': self.config, 'output_format': 'json'})
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert 'terminated' in result.output
|
||||
361
tests/cli/test_optimize_commands.py
Normal file
361
tests/cli/test_optimize_commands.py
Normal file
@@ -0,0 +1,361 @@
|
||||
"""Tests for autonomous optimization commands"""
|
||||
|
||||
import pytest
|
||||
import json
|
||||
from unittest.mock import Mock, patch
|
||||
from click.testing import CliRunner
|
||||
from aitbc_cli.commands.optimize import optimize, self_opt, predict, tune
|
||||
|
||||
|
||||
class TestSelfOptCommands:
|
||||
"""Test self-optimization operations commands"""
|
||||
|
||||
def setup_method(self):
|
||||
"""Setup test environment"""
|
||||
self.runner = CliRunner()
|
||||
self.config = {
|
||||
'coordinator_url': 'http://test:8000',
|
||||
'api_key': 'test_key'
|
||||
}
|
||||
|
||||
@patch('aitbc_cli.commands.optimize.httpx.Client')
|
||||
def test_self_opt_enable_success(self, mock_client):
|
||||
"""Test successful self-optimization enable"""
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.json.return_value = {
|
||||
'agent_id': 'agent_123',
|
||||
'optimization_enabled': True,
|
||||
'mode': 'auto-tune',
|
||||
'scope': 'full'
|
||||
}
|
||||
mock_client.return_value.__enter__.return_value.post.return_value = mock_response
|
||||
|
||||
result = self.runner.invoke(self_opt, [
|
||||
'enable',
|
||||
'agent_123',
|
||||
'--mode', 'auto-tune',
|
||||
'--scope', 'full',
|
||||
'--aggressiveness', 'moderate'
|
||||
], obj={'config': self.config, 'output_format': 'json'})
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert 'optimization_enabled' in result.output
|
||||
|
||||
@patch('aitbc_cli.commands.optimize.httpx.Client')
|
||||
def test_self_opt_status_success(self, mock_client):
|
||||
"""Test successful optimization status retrieval"""
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.json.return_value = {
|
||||
'agent_id': 'agent_123',
|
||||
'status': 'optimizing',
|
||||
'progress': 65,
|
||||
'metrics': {
|
||||
'performance': 0.85,
|
||||
'cost': 0.45
|
||||
}
|
||||
}
|
||||
mock_client.return_value.__enter__.return_value.get.return_value = mock_response
|
||||
|
||||
result = self.runner.invoke(self_opt, [
|
||||
'status',
|
||||
'agent_123',
|
||||
'--metrics', 'performance,cost'
|
||||
], obj={'config': self.config, 'output_format': 'json'})
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert '65' in result.output
|
||||
assert '0.85' in result.output
|
||||
|
||||
@patch('aitbc_cli.commands.optimize.httpx.Client')
|
||||
def test_self_opt_objectives_success(self, mock_client):
|
||||
"""Test successful optimization objectives setting"""
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.json.return_value = {
|
||||
'agent_id': 'agent_123',
|
||||
'objectives_set': True,
|
||||
'targets': {
|
||||
'latency': '100ms',
|
||||
'cost': '0.5'
|
||||
}
|
||||
}
|
||||
mock_client.return_value.__enter__.return_value.post.return_value = mock_response
|
||||
|
||||
result = self.runner.invoke(self_opt, [
|
||||
'objectives',
|
||||
'agent_123',
|
||||
'--targets', 'latency:100ms,cost:0.5',
|
||||
'--priority', 'balanced'
|
||||
], obj={'config': self.config, 'output_format': 'json'})
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert 'objectives_set' in result.output
|
||||
|
||||
@patch('aitbc_cli.commands.optimize.httpx.Client')
|
||||
def test_self_opt_recommendations_success(self, mock_client):
|
||||
"""Test successful recommendations retrieval"""
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.json.return_value = {
|
||||
'recommendations': [
|
||||
{
|
||||
'id': 'rec_1',
|
||||
'priority': 'high',
|
||||
'category': 'performance',
|
||||
'description': 'Increase GPU memory allocation'
|
||||
},
|
||||
{
|
||||
'id': 'rec_2',
|
||||
'priority': 'medium',
|
||||
'category': 'cost',
|
||||
'description': 'Optimize batch size'
|
||||
}
|
||||
]
|
||||
}
|
||||
mock_client.return_value.__enter__.return_value.get.return_value = mock_response
|
||||
|
||||
result = self.runner.invoke(self_opt, [
|
||||
'recommendations',
|
||||
'agent_123',
|
||||
'--priority', 'high',
|
||||
'--category', 'performance'
|
||||
], obj={'config': self.config, 'output_format': 'json'})
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert 'rec_1' in result.output
|
||||
assert 'high' in result.output
|
||||
|
||||
|
||||
class TestPredictCommands:
|
||||
"""Test predictive operations commands"""
|
||||
|
||||
def setup_method(self):
|
||||
"""Setup test environment"""
|
||||
self.runner = CliRunner()
|
||||
self.config = {
|
||||
'coordinator_url': 'http://test:8000',
|
||||
'api_key': 'test_key'
|
||||
}
|
||||
|
||||
@patch('aitbc_cli.commands.optimize.httpx.Client')
|
||||
def test_predict_resources_success(self, mock_client):
|
||||
"""Test successful resource prediction"""
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.json.return_value = {
|
||||
'agent_id': 'agent_123',
|
||||
'predictions': {
|
||||
'gpu': {'predicted': 2, 'confidence': 0.92},
|
||||
'memory': {'predicted': '16GB', 'confidence': 0.88}
|
||||
},
|
||||
'horizon_hours': 24
|
||||
}
|
||||
mock_client.return_value.__enter__.return_value.post.return_value = mock_response
|
||||
|
||||
result = self.runner.invoke(predict, [
|
||||
'predict',
|
||||
'agent_123',
|
||||
'--horizon', '24',
|
||||
'--resources', 'gpu,memory',
|
||||
'--confidence', '0.8'
|
||||
], obj={'config': self.config, 'output_format': 'json'})
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert '2' in result.output
|
||||
assert '0.92' in result.output
|
||||
|
||||
@patch('aitbc_cli.commands.optimize.httpx.Client')
|
||||
def test_autoscale_success(self, mock_client):
|
||||
"""Test successful auto-scaling configuration"""
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.json.return_value = {
|
||||
'agent_id': 'agent_123',
|
||||
'autoscale_configured': True,
|
||||
'policy': 'cost-efficiency',
|
||||
'min_instances': 1,
|
||||
'max_instances': 10
|
||||
}
|
||||
mock_client.return_value.__enter__.return_value.post.return_value = mock_response
|
||||
|
||||
result = self.runner.invoke(predict, [
|
||||
'autoscale',
|
||||
'agent_123',
|
||||
'--policy', 'cost-efficiency',
|
||||
'--min-instances', '1',
|
||||
'--max-instances', '10'
|
||||
], obj={'config': self.config, 'output_format': 'json'})
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert 'autoscale_configured' in result.output
|
||||
|
||||
@patch('aitbc_cli.commands.optimize.httpx.Client')
|
||||
def test_forecast_success(self, mock_client):
|
||||
"""Test successful performance forecasting"""
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.json.return_value = {
|
||||
'agent_id': 'agent_123',
|
||||
'metric': 'throughput',
|
||||
'forecast': [
|
||||
{'timestamp': '2026-02-25T00:00:00Z', 'value': 1000, 'confidence': 0.95},
|
||||
{'timestamp': '2026-02-26T00:00:00Z', 'value': 1050, 'confidence': 0.92}
|
||||
],
|
||||
'period_days': 7
|
||||
}
|
||||
mock_client.return_value.__enter__.return_value.post.return_value = mock_response
|
||||
|
||||
result = self.runner.invoke(predict, [
|
||||
'forecast',
|
||||
'agent_123',
|
||||
'--metric', 'throughput',
|
||||
'--period', '7',
|
||||
'--granularity', 'day'
|
||||
], obj={'config': self.config, 'output_format': 'json'})
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert '1000' in result.output
|
||||
assert '0.95' in result.output
|
||||
|
||||
|
||||
class TestTuneCommands:
|
||||
"""Test auto-tuning operations commands"""
|
||||
|
||||
def setup_method(self):
|
||||
"""Setup test environment"""
|
||||
self.runner = CliRunner()
|
||||
self.config = {
|
||||
'coordinator_url': 'http://test:8000',
|
||||
'api_key': 'test_key'
|
||||
}
|
||||
|
||||
@patch('aitbc_cli.commands.optimize.httpx.Client')
|
||||
def test_tune_auto_success(self, mock_client):
|
||||
"""Test successful auto-tuning start"""
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 202
|
||||
mock_response.json.return_value = {
|
||||
'id': 'tuning_123',
|
||||
'agent_id': 'agent_123',
|
||||
'status': 'started',
|
||||
'iterations': 100
|
||||
}
|
||||
mock_client.return_value.__enter__.return_value.post.return_value = mock_response
|
||||
|
||||
result = self.runner.invoke(tune, [
|
||||
'auto',
|
||||
'agent_123',
|
||||
'--parameters', 'learning_rate,batch_size',
|
||||
'--objective', 'performance',
|
||||
'--iterations', '100'
|
||||
], obj={'config': self.config, 'output_format': 'json'})
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert 'tuning_123' in result.output
|
||||
|
||||
@patch('aitbc_cli.commands.optimize.httpx.Client')
|
||||
def test_tune_status_success(self, mock_client):
|
||||
"""Test successful tuning status retrieval"""
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.json.return_value = {
|
||||
'id': 'tuning_123',
|
||||
'status': 'running',
|
||||
'progress': 45,
|
||||
'current_iteration': 45,
|
||||
'total_iterations': 100,
|
||||
'best_score': 0.87
|
||||
}
|
||||
mock_client.return_value.__enter__.return_value.get.return_value = mock_response
|
||||
|
||||
result = self.runner.invoke(tune, [
|
||||
'status',
|
||||
'tuning_123'
|
||||
], obj={'config': self.config, 'output_format': 'json'})
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert '45' in result.output
|
||||
assert '0.87' in result.output
|
||||
|
||||
@patch('aitbc_cli.commands.optimize.httpx.Client')
|
||||
def test_tune_results_success(self, mock_client):
|
||||
"""Test successful tuning results retrieval"""
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.json.return_value = {
|
||||
'tuning_id': 'tuning_123',
|
||||
'status': 'completed',
|
||||
'best_parameters': {
|
||||
'learning_rate': 0.001,
|
||||
'batch_size': 32
|
||||
},
|
||||
'best_score': 0.92,
|
||||
'iterations_completed': 100
|
||||
}
|
||||
mock_client.return_value.__enter__.return_value.get.return_value = mock_response
|
||||
|
||||
result = self.runner.invoke(tune, [
|
||||
'results',
|
||||
'tuning_123'
|
||||
], obj={'config': self.config, 'output_format': 'json'})
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert '0.92' in result.output
|
||||
assert '0.001' in result.output
|
||||
|
||||
|
||||
class TestOptimizeUtilities:
|
||||
"""Test optimization utility commands"""
|
||||
|
||||
def setup_method(self):
|
||||
"""Setup test environment"""
|
||||
self.runner = CliRunner()
|
||||
self.config = {
|
||||
'coordinator_url': 'http://test:8000',
|
||||
'api_key': 'test_key'
|
||||
}
|
||||
|
||||
@patch('aitbc_cli.commands.optimize.httpx.Client')
|
||||
def test_optimize_disable_success(self, mock_client):
|
||||
"""Test successful optimization disable"""
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.json.return_value = {
|
||||
'agent_id': 'agent_123',
|
||||
'optimization_disabled': True,
|
||||
'status': 'disabled'
|
||||
}
|
||||
mock_client.return_value.__enter__.return_value.post.return_value = mock_response
|
||||
|
||||
result = self.runner.invoke(optimize, [
|
||||
'disable',
|
||||
'agent_123'
|
||||
], obj={'config': self.config, 'output_format': 'json'})
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert 'optimization_disabled' in result.output
|
||||
|
||||
@patch('aitbc_cli.commands.optimize.httpx.Client')
|
||||
def test_self_opt_apply_success(self, mock_client):
|
||||
"""Test successful recommendation application"""
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.json.return_value = {
|
||||
'agent_id': 'agent_123',
|
||||
'recommendation_id': 'rec_1',
|
||||
'applied': True,
|
||||
'status': 'applied'
|
||||
}
|
||||
mock_client.return_value.__enter__.return_value.post.return_value = mock_response
|
||||
|
||||
result = self.runner.invoke(self_opt, [
|
||||
'apply',
|
||||
'agent_123',
|
||||
'--recommendation-id', 'rec_1',
|
||||
'--confirm'
|
||||
], obj={'config': self.config, 'output_format': 'json'})
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert 'applied' in result.output
|
||||
140
tests/cli/test_swarm_commands.py
Normal file
140
tests/cli/test_swarm_commands.py
Normal file
@@ -0,0 +1,140 @@
|
||||
"""Tests for swarm intelligence commands"""
|
||||
|
||||
import pytest
|
||||
import json
|
||||
from unittest.mock import Mock, patch
|
||||
from click.testing import CliRunner
|
||||
from aitbc_cli.commands.swarm import swarm
|
||||
|
||||
|
||||
class TestSwarmCommands:
|
||||
"""Test swarm intelligence and collective optimization commands"""
|
||||
|
||||
def setup_method(self):
|
||||
"""Setup test environment"""
|
||||
self.runner = CliRunner()
|
||||
self.config = {
|
||||
'coordinator_url': 'http://test:8000',
|
||||
'api_key': 'test_key'
|
||||
}
|
||||
|
||||
@patch('aitbc_cli.commands.swarm.httpx.Client')
|
||||
def test_swarm_join_success(self, mock_client):
|
||||
"""Test successful swarm joining"""
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 201
|
||||
mock_response.json.return_value = {
|
||||
'swarm_id': 'swarm_123',
|
||||
'role': 'load-balancer',
|
||||
'capability': 'resource-optimization',
|
||||
'status': 'joined'
|
||||
}
|
||||
mock_client.return_value.__enter__.return_value.post.return_value = mock_response
|
||||
|
||||
result = self.runner.invoke(swarm, [
|
||||
'join',
|
||||
'--role', 'load-balancer',
|
||||
'--capability', 'resource-optimization',
|
||||
'--priority', 'high'
|
||||
], obj={'config': self.config, 'output_format': 'json'})
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert 'swarm_123' in result.output
|
||||
|
||||
@patch('aitbc_cli.commands.swarm.httpx.Client')
|
||||
def test_swarm_coordinate_success(self, mock_client):
|
||||
"""Test successful swarm coordination"""
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 202
|
||||
mock_response.json.return_value = {
|
||||
'task_id': 'task_123',
|
||||
'task': 'network-optimization',
|
||||
'collaborators': 10,
|
||||
'status': 'coordinating'
|
||||
}
|
||||
mock_client.return_value.__enter__.return_value.post.return_value = mock_response
|
||||
|
||||
result = self.runner.invoke(swarm, [
|
||||
'coordinate',
|
||||
'--task', 'network-optimization',
|
||||
'--collaborators', '10',
|
||||
'--strategy', 'consensus'
|
||||
], obj={'config': self.config, 'output_format': 'json'})
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert 'task_123' in result.output
|
||||
|
||||
@patch('aitbc_cli.commands.swarm.httpx.Client')
|
||||
def test_swarm_list_success(self, mock_client):
|
||||
"""Test successful swarm listing"""
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.json.return_value = [
|
||||
{
|
||||
'swarm_id': 'swarm_1',
|
||||
'role': 'load-balancer',
|
||||
'status': 'active',
|
||||
'members': 5
|
||||
},
|
||||
{
|
||||
'swarm_id': 'swarm_2',
|
||||
'role': 'resource-optimizer',
|
||||
'status': 'active',
|
||||
'members': 3
|
||||
}
|
||||
]
|
||||
mock_client.return_value.__enter__.return_value.get.return_value = mock_response
|
||||
|
||||
result = self.runner.invoke(swarm, [
|
||||
'list',
|
||||
'--status', 'active',
|
||||
'--limit', '10'
|
||||
], obj={'config': self.config, 'output_format': 'json'})
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert 'swarm_1' in result.output
|
||||
|
||||
@patch('aitbc_cli.commands.swarm.httpx.Client')
|
||||
def test_swarm_status_success(self, mock_client):
|
||||
"""Test successful swarm task status retrieval"""
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.json.return_value = {
|
||||
'task_id': 'task_123',
|
||||
'status': 'running',
|
||||
'progress': 65,
|
||||
'active_collaborators': 8,
|
||||
'total_collaborators': 10
|
||||
}
|
||||
mock_client.return_value.__enter__.return_value.get.return_value = mock_response
|
||||
|
||||
result = self.runner.invoke(swarm, [
|
||||
'status',
|
||||
'task_123'
|
||||
], obj={'config': self.config, 'output_format': 'json'})
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert '65' in result.output
|
||||
assert '8' in result.output
|
||||
|
||||
@patch('aitbc_cli.commands.swarm.httpx.Client')
|
||||
def test_swarm_consensus_success(self, mock_client):
|
||||
"""Test successful swarm consensus achievement"""
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.json.return_value = {
|
||||
'task_id': 'task_123',
|
||||
'consensus_reached': True,
|
||||
'consensus_threshold': 0.7,
|
||||
'actual_consensus': 0.85
|
||||
}
|
||||
mock_client.return_value.__enter__.return_value.post.return_value = mock_response
|
||||
|
||||
result = self.runner.invoke(swarm, [
|
||||
'consensus',
|
||||
'task_123',
|
||||
'--consensus-threshold', '0.7'
|
||||
], obj={'config': self.config, 'output_format': 'json'})
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert 'True' in result.output
|
||||
@@ -97,7 +97,22 @@ class TestWalletCommands:
|
||||
assert result.exit_code == 0
|
||||
assert wallet_path.exists()
|
||||
|
||||
data = json.loads(result.output)
|
||||
# Strip ANSI color codes from output before JSON parsing
|
||||
import re
|
||||
ansi_escape = re.compile(r'\x1b(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])')
|
||||
clean_output = ansi_escape.sub('', result.output)
|
||||
|
||||
# Extract JSON from the cleaned output
|
||||
first_brace = clean_output.find('{')
|
||||
last_brace = clean_output.rfind('}')
|
||||
|
||||
if first_brace != -1 and last_brace != -1 and last_brace > first_brace:
|
||||
json_part = clean_output[first_brace:last_brace+1]
|
||||
data = json.loads(json_part)
|
||||
else:
|
||||
# Fallback to original behavior if no JSON found
|
||||
data = json.loads(clean_output)
|
||||
|
||||
assert data['balance'] == 0.0
|
||||
assert 'address' in data
|
||||
|
||||
|
||||
Reference in New Issue
Block a user