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:
oib
2026-02-24 18:41:08 +01:00
parent 24b3a37733
commit 825f157749
270 changed files with 66674 additions and 2027 deletions

View 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

View File

@@ -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

View 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

View 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

View 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

View 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

View 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

View File

@@ -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