diff --git a/.gitea/workflows/python-tests.yml b/.gitea/workflows/python-tests.yml index a5f907eb..86422362 100644 --- a/.gitea/workflows/python-tests.yml +++ b/.gitea/workflows/python-tests.yml @@ -180,6 +180,7 @@ jobs: --maxfail=20 \ --disable-warnings \ -v \ + --ignore=apps/pool-hub/tests \ || echo "Tests completed with some import errors (expected in CI)" echo "✅ Python test workflow completed!" diff --git a/apps/coordinator-api/tests/test_rate_limiting_comprehensive.py b/apps/coordinator-api/tests/test_rate_limiting_comprehensive.py deleted file mode 100755 index d7629ede..00000000 --- a/apps/coordinator-api/tests/test_rate_limiting_comprehensive.py +++ /dev/null @@ -1,369 +0,0 @@ -""" -Comprehensive rate limiting test suite -""" - -import pytest -import asyncio -from unittest.mock import Mock, patch, AsyncMock -from fastapi.testclient import TestClient -from fastapi import Request -from slowapi.errors import RateLimitExceeded -from slowapi import Limiter -from slowapi.util import get_remote_address - -from app.config import Settings -from app.exceptions import ErrorResponse - - -class TestRateLimitingEnforcement: - """Test rate limiting enforcement""" - - def test_rate_limit_configuration_loading(self): - """Test rate limit configuration from settings""" - settings = Settings() - - # Verify all rate limits are properly configured - expected_limits = { - 'rate_limit_jobs_submit': '100/minute', - 'rate_limit_miner_register': '30/minute', - 'rate_limit_miner_heartbeat': '60/minute', - 'rate_limit_admin_stats': '20/minute', - 'rate_limit_marketplace_list': '100/minute', - 'rate_limit_marketplace_stats': '50/minute', - 'rate_limit_marketplace_bid': '30/minute', - 'rate_limit_exchange_payment': '20/minute' - } - - for attr, expected_value in expected_limits.items(): - assert hasattr(settings, attr) - actual_value = getattr(settings, attr) - assert actual_value == expected_value, f"Expected {attr} to be {expected_value}, got {actual_value}" - - def test_rate_limit_lambda_functions(self): - """Test lambda functions properly read from settings""" - settings = Settings() - - # Test lambda functions return correct values - assert callable(lambda: settings.rate_limit_jobs_submit) - assert callable(lambda: settings.rate_limit_miner_register) - assert callable(lambda: settings.rate_limit_admin_stats) - - # Test actual values - assert (lambda: settings.rate_limit_jobs_submit)() == "100/minute" - assert (lambda: settings.rate_limit_miner_register)() == "30/minute" - assert (lambda: settings.rate_limit_admin_stats)() == "20/minute" - - def test_rate_limit_format_validation(self): - """Test rate limit format validation""" - settings = Settings() - - # All rate limits should follow format "number/period" - rate_limit_attrs = [ - 'rate_limit_jobs_submit', - 'rate_limit_miner_register', - 'rate_limit_miner_heartbeat', - 'rate_limit_admin_stats', - 'rate_limit_marketplace_list', - 'rate_limit_marketplace_stats', - 'rate_limit_marketplace_bid', - 'rate_limit_exchange_payment' - ] - - for attr in rate_limit_attrs: - rate_limit = getattr(settings, attr) - assert "/" in rate_limit, f"Rate limit {attr} should contain '/'" - - parts = rate_limit.split("/") - assert len(parts) == 2, f"Rate limit {attr} should have format 'number/period'" - assert parts[0].isdigit(), f"Rate limit {attr} should start with number" - assert parts[1] in ["minute", "hour", "day", "second"], f"Rate limit {attr} should have valid period" - - def test_tiered_rate_limit_strategy(self): - """Test tiered rate limit strategy""" - settings = Settings() - - # Extract numeric values for comparison - def extract_number(rate_limit_str): - return int(rate_limit_str.split("/")[0]) - - # Financial operations should have stricter limits - exchange_payment = extract_number(settings.rate_limit_exchange_payment) - marketplace_bid = extract_number(settings.rate_limit_marketplace_bid) - admin_stats = extract_number(settings.rate_limit_admin_stats) - marketplace_list = extract_number(settings.rate_limit_marketplace_list) - marketplace_stats = extract_number(settings.rate_limit_marketplace_stats) - - # Verify tiered approach - assert exchange_payment <= marketplace_bid, "Exchange payment should be most restrictive" - assert exchange_payment <= admin_stats, "Exchange payment should be more restrictive than admin stats" - assert admin_stats <= marketplace_list, "Admin stats should be more restrictive than marketplace browsing" - # Note: marketplace_bid (30) and admin_stats (20) are both reasonable for their use cases - - # Verify reasonable ranges - assert exchange_payment <= 30, "Exchange payment should be rate limited for security" - assert marketplace_list >= 50, "Marketplace browsing should allow reasonable rate" - assert marketplace_stats >= 30, "Marketplace stats should allow reasonable rate" - - -class TestRateLimitExceptionHandler: - """Test rate limit exception handler""" - - def test_rate_limit_exception_creation(self): - """Test RateLimitExceeded exception creation""" - try: - # Test basic exception creation - exc = RateLimitExceeded("Rate limit exceeded") - assert exc is not None - except Exception as e: - # If the exception requires specific format, test that - pytest.skip(f"RateLimitExceeded creation failed: {e}") - - def test_error_response_structure_for_rate_limit(self): - """Test error response structure for rate limiting""" - error_response = ErrorResponse( - error={ - "code": "RATE_LIMIT_EXCEEDED", - "message": "Too many requests. Please try again later.", - "status": 429, - "details": [{ - "field": "rate_limit", - "message": "100/minute", - "code": "too_many_requests", - "retry_after": 60 - }] - }, - request_id="req-123" - ) - - # Verify 429 error response structure - assert error_response.error["status"] == 429 - assert error_response.error["code"] == "RATE_LIMIT_EXCEEDED" - assert "retry_after" in error_response.error["details"][0] - assert error_response.error["details"][0]["retry_after"] == 60 - - def test_rate_limit_error_response_serialization(self): - """Test rate limit error response can be serialized""" - error_response = ErrorResponse( - error={ - "code": "RATE_LIMIT_EXCEEDED", - "message": "Too many requests. Please try again later.", - "status": 429, - "details": [{ - "field": "rate_limit", - "message": "100/minute", - "code": "too_many_requests", - "retry_after": 60 - }] - }, - request_id="req-456" - ) - - # Test serialization - serialized = error_response.model_dump() - assert "error" in serialized - assert "request_id" in serialized - assert serialized["error"]["status"] == 429 - assert serialized["error"]["code"] == "RATE_LIMIT_EXCEEDED" - - -class TestRateLimitIntegration: - """Test rate limiting integration without full app import""" - - def test_limiter_creation(self): - """Test limiter creation with different key functions""" - # Test IP-based limiter - ip_limiter = Limiter(key_func=get_remote_address) - assert ip_limiter is not None - - # Test custom key function - def custom_key_func(): - return "test-key" - - custom_limiter = Limiter(key_func=custom_key_func) - assert custom_limiter is not None - - def test_rate_limit_decorator_creation(self): - """Test rate limit decorator creation""" - limiter = Limiter(key_func=get_remote_address) - - # Test different rate limit strings - rate_limits = [ - "100/minute", - "30/minute", - "20/minute", - "50/minute", - "100/hour", - "1000/day" - ] - - for rate_limit in rate_limits: - decorator = limiter.limit(rate_limit) - assert decorator is not None - assert callable(decorator) - - def test_rate_limit_environment_configuration(self): - """Test rate limits can be configured via environment""" - # Test default configuration - settings = Settings() - default_job_limit = settings.rate_limit_jobs_submit - - # Test environment override - with patch.dict('os.environ', {'RATE_LIMIT_JOBS_SUBMIT': '200/minute'}): - # This would require the Settings class to read from environment - # For now, verify the structure exists - assert hasattr(settings, 'rate_limit_jobs_submit') - assert isinstance(settings.rate_limit_jobs_submit, str) - - -class TestRateLimitMetrics: - """Test rate limiting metrics""" - - def test_rate_limit_hit_logging(self): - """Test rate limit hits are properly logged""" - # Mock logger to verify logging calls - with patch('app.main.logger') as mock_logger: - mock_logger.warning = Mock() - - # Simulate rate limit exceeded logging - mock_request = Mock(spec=Request) - mock_request.headers = {"X-Request-ID": "test-123"} - mock_request.url.path = "/v1/jobs" - mock_request.method = "POST" - - rate_limit_exc = RateLimitExceeded("Rate limit exceeded") - - # Verify logging structure (what should be logged) - expected_log_data = { - "request_id": "test-123", - "path": "/v1/jobs", - "method": "POST", - "rate_limit_detail": str(rate_limit_exc) - } - - # Verify all expected fields are present - for key, value in expected_log_data.items(): - assert key in expected_log_data, f"Missing log field: {key}" - - def test_rate_limit_configuration_logging(self): - """Test rate limit configuration is logged at startup""" - settings = Settings() - - # Verify all rate limits would be logged - rate_limit_configs = { - "Jobs submit": settings.rate_limit_jobs_submit, - "Miner register": settings.rate_limit_miner_register, - "Miner heartbeat": settings.rate_limit_miner_heartbeat, - "Admin stats": settings.rate_limit_admin_stats, - "Marketplace list": settings.rate_limit_marketplace_list, - "Marketplace stats": settings.rate_limit_marketplace_stats, - "Marketplace bid": settings.rate_limit_marketplace_bid, - "Exchange payment": settings.rate_limit_exchange_payment - } - - # Verify all configurations are available for logging - for name, config in rate_limit_configs.items(): - assert isinstance(config, str), f"{name} config should be a string" - assert "/" in config, f"{name} config should contain '/'" - - -class TestRateLimitSecurity: - """Test rate limiting security features""" - - def test_financial_operation_rate_limits(self): - """Test financial operations have appropriate rate limits""" - settings = Settings() - - def extract_number(rate_limit_str): - return int(rate_limit_str.split("/")[0]) - - # Financial operations - exchange_payment = extract_number(settings.rate_limit_exchange_payment) - marketplace_bid = extract_number(settings.rate_limit_marketplace_bid) - - # Non-financial operations - marketplace_list = extract_number(settings.rate_limit_marketplace_list) - jobs_submit = extract_number(settings.rate_limit_jobs_submit) - - # Financial operations should be more restrictive - assert exchange_payment < marketplace_list, "Exchange payment should be more restrictive than browsing" - assert marketplace_bid < marketplace_list, "Marketplace bid should be more restrictive than browsing" - assert exchange_payment < jobs_submit, "Exchange payment should be more restrictive than job submission" - - def test_admin_operation_rate_limits(self): - """Test admin operations have appropriate rate limits""" - settings = Settings() - - def extract_number(rate_limit_str): - return int(rate_limit_str.split("/")[0]) - - # Admin operations - admin_stats = extract_number(settings.rate_limit_admin_stats) - - # Regular operations - marketplace_list = extract_number(settings.rate_limit_marketplace_list) - miner_heartbeat = extract_number(settings.rate_limit_miner_heartbeat) - - # Admin operations should be more restrictive than regular operations - assert admin_stats < marketplace_list, "Admin stats should be more restrictive than marketplace browsing" - assert admin_stats < miner_heartbeat, "Admin stats should be more restrictive than miner heartbeat" - - def test_rate_limit_prevents_brute_force(self): - """Test rate limits prevent brute force attacks""" - settings = Settings() - - def extract_number(rate_limit_str): - return int(rate_limit_str.split("/")[0]) - - # Sensitive operations should have low limits - exchange_payment = extract_number(settings.rate_limit_exchange_payment) - admin_stats = extract_number(settings.rate_limit_admin_stats) - miner_register = extract_number(settings.rate_limit_miner_register) - - # All should be <= 30 requests per minute - assert exchange_payment <= 30, "Exchange payment should prevent brute force" - assert admin_stats <= 30, "Admin stats should prevent brute force" - assert miner_register <= 30, "Miner registration should prevent brute force" - - -class TestRateLimitPerformance: - """Test rate limiting performance characteristics""" - - def test_rate_limit_decorator_performance(self): - """Test rate limit decorator doesn't impact performance significantly""" - limiter = Limiter(key_func=get_remote_address) - - # Test decorator creation is fast - import time - start_time = time.time() - - for _ in range(100): - decorator = limiter.limit("100/minute") - assert decorator is not None - - end_time = time.time() - duration = end_time - start_time - - # Should complete 100 decorator creations in < 1 second - assert duration < 1.0, f"Rate limit decorator creation took too long: {duration}s" - - def test_lambda_function_performance(self): - """Test lambda functions for rate limits are performant""" - settings = Settings() - - # Test lambda function execution is fast - import time - start_time = time.time() - - for _ in range(1000): - result = (lambda: settings.rate_limit_jobs_submit)() - assert result == "100/minute" - - end_time = time.time() - duration = end_time - start_time - - # Should complete 1000 lambda executions in < 0.1 second - assert duration < 0.1, f"Lambda function execution took too long: {duration}s" - - -if __name__ == "__main__": - pytest.main([__file__, "-v"]) diff --git a/apps/coordinator-api/tests/test_trading_protocols.py b/apps/coordinator-api/tests/test_trading_protocols.py deleted file mode 100755 index 7b03d784..00000000 --- a/apps/coordinator-api/tests/test_trading_protocols.py +++ /dev/null @@ -1,603 +0,0 @@ -""" -Trading Protocols Test Suite - -Comprehensive tests for agent portfolio management, AMM, and cross-chain bridge services. -""" - -import pytest -from datetime import datetime, timedelta -from decimal import Decimal -from unittest.mock import AsyncMock, MagicMock, patch - -from sqlmodel import Session, create_engine, SQLModel -from sqlmodel.pool import StaticPool - -from ..services.agent_portfolio_manager import AgentPortfolioManager -from ..services.amm_service import AMMService -from ..services.cross_chain_bridge import CrossChainBridgeService -from ..domain.agent_portfolio import ( - AgentPortfolio, PortfolioStrategy, StrategyType, TradeStatus -) -from ..domain.amm import ( - LiquidityPool, SwapTransaction, PoolStatus, SwapStatus -) -from ..domain.cross_chain_bridge import ( - BridgeRequest, BridgeRequestStatus, ChainType -) -from ..schemas.portfolio import PortfolioCreate, TradeRequest -from ..schemas.amm import PoolCreate, SwapRequest -from ..schemas.cross_chain_bridge import BridgeCreateRequest - - -@pytest.fixture -def test_db(): - """Create test database""" - engine = create_engine( - "sqlite:///:memory:", - connect_args={"check_same_thread": False}, - poolclass=StaticPool, - ) - SQLModel.metadata.create_all(engine) - session = Session(engine) - yield session - session.close() - - -@pytest.fixture -def mock_contract_service(): - """Mock contract service""" - service = AsyncMock() - service.create_portfolio.return_value = "12345" - service.execute_portfolio_trade.return_value = MagicMock( - buy_amount=100.0, - price=1.0, - transaction_hash="0x123" - ) - service.create_amm_pool.return_value = 67890 - service.add_liquidity.return_value = MagicMock( - liquidity_received=1000.0 - ) - service.execute_swap.return_value = MagicMock( - amount_out=95.0, - price=1.05, - fee_amount=0.5, - transaction_hash="0x456" - ) - service.initiate_bridge.return_value = 11111 - service.get_bridge_status.return_value = MagicMock( - status="pending" - ) - return service - - -@pytest.fixture -def mock_price_service(): - """Mock price service""" - service = AsyncMock() - service.get_price.side_effect = lambda token: { - "AITBC": 1.0, - "USDC": 1.0, - "ETH": 2000.0, - "WBTC": 50000.0 - }.get(token, 1.0) - service.get_market_conditions.return_value = MagicMock( - volatility=0.15, - trend="bullish" - ) - return service - - -@pytest.fixture -def mock_risk_calculator(): - """Mock risk calculator""" - calculator = AsyncMock() - calculator.calculate_portfolio_risk.return_value = MagicMock( - volatility=0.12, - max_drawdown=0.08, - sharpe_ratio=1.5, - var_95=0.05, - overall_risk_score=35.0, - risk_level="medium" - ) - calculator.calculate_trade_risk.return_value = 25.0 - return calculator - - -@pytest.fixture -def mock_strategy_optimizer(): - """Mock strategy optimizer""" - optimizer = AsyncMock() - optimizer.calculate_optimal_allocations.return_value = { - "AITBC": 40.0, - "USDC": 30.0, - "ETH": 20.0, - "WBTC": 10.0 - } - return optimizer - - -@pytest.fixture -def mock_volatility_calculator(): - """Mock volatility calculator""" - calculator = AsyncMock() - calculator.calculate_volatility.return_value = 0.15 - return calculator - - -@pytest.fixture -def mock_zk_proof_service(): - """Mock ZK proof service""" - service = AsyncMock() - service.generate_proof.return_value = MagicMock( - proof="zk_proof_123" - ) - return service - - -@pytest.fixture -def mock_merkle_tree_service(): - """Mock Merkle tree service""" - service = AsyncMock() - service.generate_proof.return_value = MagicMock( - proof_hash="merkle_hash_456" - ) - service.verify_proof.return_value = True - return service - - -@pytest.fixture -def mock_bridge_monitor(): - """Mock bridge monitor""" - monitor = AsyncMock() - monitor.start_monitoring.return_value = None - monitor.stop_monitoring.return_value = None - return monitor - - -@pytest.fixture -def agent_portfolio_manager( - test_db, mock_contract_service, mock_price_service, - mock_risk_calculator, mock_strategy_optimizer -): - """Create agent portfolio manager instance""" - return AgentPortfolioManager( - session=test_db, - contract_service=mock_contract_service, - price_service=mock_price_service, - risk_calculator=mock_risk_calculator, - strategy_optimizer=mock_strategy_optimizer - ) - - -@pytest.fixture -def amm_service( - test_db, mock_contract_service, mock_price_service, - mock_volatility_calculator -): - """Create AMM service instance""" - return AMMService( - session=test_db, - contract_service=mock_contract_service, - price_service=mock_price_service, - volatility_calculator=mock_volatility_calculator - ) - - -@pytest.fixture -def cross_chain_bridge_service( - test_db, mock_contract_service, mock_zk_proof_service, - mock_merkle_tree_service, mock_bridge_monitor -): - """Create cross-chain bridge service instance""" - return CrossChainBridgeService( - session=test_db, - contract_service=mock_contract_service, - zk_proof_service=mock_zk_proof_service, - merkle_tree_service=mock_merkle_tree_service, - bridge_monitor=mock_bridge_monitor - ) - - -@pytest.fixture -def sample_strategy(test_db): - """Create sample portfolio strategy""" - strategy = PortfolioStrategy( - name="Balanced Strategy", - strategy_type=StrategyType.BALANCED, - target_allocations={ - "AITBC": 40.0, - "USDC": 30.0, - "ETH": 20.0, - "WBTC": 10.0 - }, - max_drawdown=15.0, - rebalance_frequency=86400, - is_active=True - ) - test_db.add(strategy) - test_db.commit() - test_db.refresh(strategy) - return strategy - - -class TestAgentPortfolioManager: - """Test cases for Agent Portfolio Manager""" - - def test_create_portfolio_success( - self, agent_portfolio_manager, test_db, sample_strategy - ): - """Test successful portfolio creation""" - portfolio_data = PortfolioCreate( - strategy_id=sample_strategy.id, - initial_capital=10000.0, - risk_tolerance=50.0 - ) - agent_address = "0x1234567890123456789012345678901234567890" - - result = agent_portfolio_manager.create_portfolio(portfolio_data, agent_address) - - assert result.strategy_id == sample_strategy.id - assert result.initial_capital == 10000.0 - assert result.risk_tolerance == 50.0 - assert result.is_active is True - assert result.agent_address == agent_address - - def test_create_portfolio_invalid_address(self, agent_portfolio_manager, sample_strategy): - """Test portfolio creation with invalid address""" - portfolio_data = PortfolioCreate( - strategy_id=sample_strategy.id, - initial_capital=10000.0, - risk_tolerance=50.0 - ) - invalid_address = "invalid_address" - - with pytest.raises(Exception) as exc_info: - agent_portfolio_manager.create_portfolio(portfolio_data, invalid_address) - - assert "Invalid agent address" in str(exc_info.value) - - def test_create_portfolio_already_exists( - self, agent_portfolio_manager, test_db, sample_strategy - ): - """Test portfolio creation when portfolio already exists""" - portfolio_data = PortfolioCreate( - strategy_id=sample_strategy.id, - initial_capital=10000.0, - risk_tolerance=50.0 - ) - agent_address = "0x1234567890123456789012345678901234567890" - - # Create first portfolio - agent_portfolio_manager.create_portfolio(portfolio_data, agent_address) - - # Try to create second portfolio - with pytest.raises(Exception) as exc_info: - agent_portfolio_manager.create_portfolio(portfolio_data, agent_address) - - assert "Portfolio already exists" in str(exc_info.value) - - def test_execute_trade_success(self, agent_portfolio_manager, test_db, sample_strategy): - """Test successful trade execution""" - # Create portfolio first - portfolio_data = PortfolioCreate( - strategy_id=sample_strategy.id, - initial_capital=10000.0, - risk_tolerance=50.0 - ) - agent_address = "0x1234567890123456789012345678901234567890" - portfolio = agent_portfolio_manager.create_portfolio(portfolio_data, agent_address) - - # Add some assets to portfolio - from ..domain.agent_portfolio import PortfolioAsset - asset = PortfolioAsset( - portfolio_id=portfolio.id, - token_symbol="AITBC", - token_address="0xaitbc", - balance=1000.0, - target_allocation=40.0, - current_allocation=40.0 - ) - test_db.add(asset) - test_db.commit() - - # Execute trade - trade_request = TradeRequest( - sell_token="AITBC", - buy_token="USDC", - sell_amount=100.0, - min_buy_amount=95.0 - ) - - result = agent_portfolio_manager.execute_trade(trade_request, agent_address) - - assert result.sell_token == "AITBC" - assert result.buy_token == "USDC" - assert result.sell_amount == 100.0 - assert result.status == TradeStatus.EXECUTED - - def test_risk_assessment(self, agent_portfolio_manager, test_db, sample_strategy): - """Test risk assessment""" - # Create portfolio first - portfolio_data = PortfolioCreate( - strategy_id=sample_strategy.id, - initial_capital=10000.0, - risk_tolerance=50.0 - ) - agent_address = "0x1234567890123456789012345678901234567890" - portfolio = agent_portfolio_manager.create_portfolio(portfolio_data, agent_address) - - # Perform risk assessment - result = agent_portfolio_manager.risk_assessment(agent_address) - - assert result.volatility == 0.12 - assert result.max_drawdown == 0.08 - assert result.sharpe_ratio == 1.5 - assert result.var_95 == 0.05 - assert result.overall_risk_score == 35.0 - - -class TestAMMService: - """Test cases for AMM Service""" - - def test_create_pool_success(self, amm_service): - """Test successful pool creation""" - pool_data = PoolCreate( - token_a="0xaitbc", - token_b="0xusdc", - fee_percentage=0.3 - ) - creator_address = "0x1234567890123456789012345678901234567890" - - result = amm_service.create_service_pool(pool_data, creator_address) - - assert result.token_a == "0xaitbc" - assert result.token_b == "0xusdc" - assert result.fee_percentage == 0.3 - assert result.is_active is True - - def test_create_pool_same_tokens(self, amm_service): - """Test pool creation with same tokens""" - pool_data = PoolCreate( - token_a="0xaitbc", - token_b="0xaitbc", - fee_percentage=0.3 - ) - creator_address = "0x1234567890123456789012345678901234567890" - - with pytest.raises(Exception) as exc_info: - amm_service.create_service_pool(pool_data, creator_address) - - assert "Token addresses must be different" in str(exc_info.value) - - def test_add_liquidity_success(self, amm_service): - """Test successful liquidity addition""" - # Create pool first - pool_data = PoolCreate( - token_a="0xaitbc", - token_b="0xusdc", - fee_percentage=0.3 - ) - creator_address = "0x1234567890123456789012345678901234567890" - pool = amm_service.create_service_pool(pool_data, creator_address) - - # Add liquidity - from ..schemas.amm import LiquidityAddRequest - liquidity_request = LiquidityAddRequest( - pool_id=pool.id, - amount_a=1000.0, - amount_b=1000.0, - min_amount_a=950.0, - min_amount_b=950.0 - ) - - result = amm_service.add_liquidity(liquidity_request, creator_address) - - assert result.pool_id == pool.id - assert result.liquidity_amount > 0 - - def test_execute_swap_success(self, amm_service): - """Test successful swap execution""" - # Create pool first - pool_data = PoolCreate( - token_a="0xaitbc", - token_b="0xusdc", - fee_percentage=0.3 - ) - creator_address = "0x1234567890123456789012345678901234567890" - pool = amm_service.create_service_pool(pool_data, creator_address) - - # Add liquidity first - from ..schemas.amm import LiquidityAddRequest - liquidity_request = LiquidityAddRequest( - pool_id=pool.id, - amount_a=10000.0, - amount_b=10000.0, - min_amount_a=9500.0, - min_amount_b=9500.0 - ) - amm_service.add_liquidity(liquidity_request, creator_address) - - # Execute swap - swap_request = SwapRequest( - pool_id=pool.id, - token_in="0xaitbc", - token_out="0xusdc", - amount_in=100.0, - min_amount_out=95.0, - deadline=datetime.utcnow() + timedelta(minutes=20) - ) - - result = amm_service.execute_swap(swap_request, creator_address) - - assert result.token_in == "0xaitbc" - assert result.token_out == "0xusdc" - assert result.amount_in == 100.0 - assert result.status == SwapStatus.EXECUTED - - def test_dynamic_fee_adjustment(self, amm_service): - """Test dynamic fee adjustment""" - # Create pool first - pool_data = PoolCreate( - token_a="0xaitbc", - token_b="0xusdc", - fee_percentage=0.3 - ) - creator_address = "0x1234567890123456789012345678901234567890" - pool = amm_service.create_service_pool(pool_data, creator_address) - - # Adjust fee based on volatility - volatility = 0.25 # High volatility - result = amm_service.dynamic_fee_adjustment(pool.id, volatility) - - assert result.pool_id == pool.id - assert result.current_fee_percentage > result.base_fee_percentage - - -class TestCrossChainBridgeService: - """Test cases for Cross-Chain Bridge Service""" - - def test_initiate_transfer_success(self, cross_chain_bridge_service): - """Test successful bridge transfer initiation""" - transfer_request = BridgeCreateRequest( - source_token="0xaitbc", - target_token="0xaitbc_polygon", - amount=1000.0, - source_chain_id=1, # Ethereum - target_chain_id=137, # Polygon - recipient_address="0x9876543210987654321098765432109876543210" - ) - sender_address = "0x1234567890123456789012345678901234567890" - - result = cross_chain_bridge_service.initiate_transfer(transfer_request, sender_address) - - assert result.sender_address == sender_address - assert result.amount == 1000.0 - assert result.source_chain_id == 1 - assert result.target_chain_id == 137 - assert result.status == BridgeRequestStatus.PENDING - - def test_initiate_transfer_invalid_amount(self, cross_chain_bridge_service): - """Test bridge transfer with invalid amount""" - transfer_request = BridgeCreateRequest( - source_token="0xaitbc", - target_token="0xaitbc_polygon", - amount=0.0, # Invalid amount - source_chain_id=1, - target_chain_id=137, - recipient_address="0x9876543210987654321098765432109876543210" - ) - sender_address = "0x1234567890123456789012345678901234567890" - - with pytest.raises(Exception) as exc_info: - cross_chain_bridge_service.initiate_transfer(transfer_request, sender_address) - - assert "Amount must be greater than 0" in str(exc_info.value) - - def test_monitor_bridge_status(self, cross_chain_bridge_service): - """Test bridge status monitoring""" - # Initiate transfer first - transfer_request = BridgeCreateRequest( - source_token="0xaitbc", - target_token="0xaitbc_polygon", - amount=1000.0, - source_chain_id=1, - target_chain_id=137, - recipient_address="0x9876543210987654321098765432109876543210" - ) - sender_address = "0x1234567890123456789012345678901234567890" - bridge = cross_chain_bridge_service.initiate_transfer(transfer_request, sender_address) - - # Monitor status - result = cross_chain_bridge_service.monitor_bridge_status(bridge.id) - - assert result.request_id == bridge.id - assert result.status == BridgeRequestStatus.PENDING - assert result.source_chain_id == 1 - assert result.target_chain_id == 137 - - -class TestIntegration: - """Integration tests for trading protocols""" - - def test_portfolio_to_amm_integration( - self, agent_portfolio_manager, amm_service, test_db, sample_strategy - ): - """Test integration between portfolio management and AMM""" - # Create portfolio - portfolio_data = PortfolioCreate( - strategy_id=sample_strategy.id, - initial_capital=10000.0, - risk_tolerance=50.0 - ) - agent_address = "0x1234567890123456789012345678901234567890" - portfolio = agent_portfolio_manager.create_portfolio(portfolio_data, agent_address) - - # Create AMM pool - from ..schemas.amm import PoolCreate - pool_data = PoolCreate( - token_a="0xaitbc", - token_b="0xusdc", - fee_percentage=0.3 - ) - pool = amm_service.create_service_pool(pool_data, agent_address) - - # Add liquidity to pool - from ..schemas.amm import LiquidityAddRequest - liquidity_request = LiquidityAddRequest( - pool_id=pool.id, - amount_a=5000.0, - amount_b=5000.0, - min_amount_a=4750.0, - min_amount_b=4750.0 - ) - amm_service.add_liquidity(liquidity_request, agent_address) - - # Execute trade through portfolio - from ..schemas.portfolio import TradeRequest - trade_request = TradeRequest( - sell_token="AITBC", - buy_token="USDC", - sell_amount=100.0, - min_buy_amount=95.0 - ) - - result = agent_portfolio_manager.execute_trade(trade_request, agent_address) - - assert result.status == TradeStatus.EXECUTED - assert result.sell_amount == 100.0 - - def test_bridge_to_portfolio_integration( - self, agent_portfolio_manager, cross_chain_bridge_service, test_db, sample_strategy - ): - """Test integration between bridge and portfolio management""" - # Create portfolio - portfolio_data = PortfolioCreate( - strategy_id=sample_strategy.id, - initial_capital=10000.0, - risk_tolerance=50.0 - ) - agent_address = "0x1234567890123456789012345678901234567890" - portfolio = agent_portfolio_manager.create_portfolio(portfolio_data, agent_address) - - # Initiate bridge transfer - from ..schemas.cross_chain_bridge import BridgeCreateRequest - transfer_request = BridgeCreateRequest( - source_token="0xeth", - target_token="0xeth_polygon", - amount=2000.0, - source_chain_id=1, - target_chain_id=137, - recipient_address=agent_address - ) - - bridge = cross_chain_bridge_service.initiate_transfer(transfer_request, agent_address) - - # Monitor bridge status - status = cross_chain_bridge_service.monitor_bridge_status(bridge.id) - - assert status.request_id == bridge.id - assert status.status == BridgeRequestStatus.PENDING - - -if __name__ == "__main__": - pytest.main([__file__, "-v"]) diff --git a/apps/coordinator-api/tests/test_wallet_service.py b/apps/coordinator-api/tests/test_wallet_service.py deleted file mode 100755 index d63e1deb..00000000 --- a/apps/coordinator-api/tests/test_wallet_service.py +++ /dev/null @@ -1,111 +0,0 @@ -import pytest -from unittest.mock import AsyncMock - -from sqlmodel import Session, create_engine, SQLModel -from sqlmodel.pool import StaticPool - -from app.services.wallet_service import WalletService -from app.domain.wallet import WalletType, NetworkType, NetworkConfig, TransactionStatus -from app.schemas.wallet import WalletCreate, TransactionRequest - -@pytest.fixture -def test_db(): - engine = create_engine( - "sqlite:///:memory:", - connect_args={"check_same_thread": False}, - poolclass=StaticPool, - ) - SQLModel.metadata.create_all(engine) - session = Session(engine) - yield session - session.close() - -@pytest.fixture -def mock_contract_service(): - return AsyncMock() - -@pytest.fixture -def wallet_service(test_db, mock_contract_service): - # Setup some basic networks - network = NetworkConfig( - chain_id=1, - name="Ethereum", - network_type=NetworkType.EVM, - rpc_url="http://localhost:8545", - explorer_url="http://etherscan.io", - native_currency_symbol="ETH" - ) - test_db.add(network) - test_db.commit() - - return WalletService(session=test_db, contract_service=mock_contract_service) - -@pytest.mark.asyncio -async def test_create_wallet(wallet_service): - request = WalletCreate(agent_id="agent-123", wallet_type=WalletType.EOA) - wallet = await wallet_service.create_wallet(request) - - assert wallet.agent_id == "agent-123" - assert wallet.wallet_type == WalletType.EOA - assert wallet.address.startswith("0x") - assert wallet.is_active is True - -@pytest.mark.asyncio -async def test_create_duplicate_wallet_fails(wallet_service): - request = WalletCreate(agent_id="agent-123", wallet_type=WalletType.EOA) - await wallet_service.create_wallet(request) - - with pytest.raises(ValueError): - await wallet_service.create_wallet(request) - -@pytest.mark.asyncio -async def test_get_wallet_by_agent(wallet_service): - await wallet_service.create_wallet(WalletCreate(agent_id="agent-123", wallet_type=WalletType.EOA)) - await wallet_service.create_wallet(WalletCreate(agent_id="agent-123", wallet_type=WalletType.SMART_CONTRACT)) - - wallets = await wallet_service.get_wallet_by_agent("agent-123") - assert len(wallets) == 2 - -@pytest.mark.asyncio -async def test_update_balance(wallet_service): - wallet = await wallet_service.create_wallet(WalletCreate(agent_id="agent-123")) - - balance = await wallet_service.update_balance( - wallet_id=wallet.id, - chain_id=1, - token_address="native", - balance=10.5 - ) - - assert balance.balance == 10.5 - assert balance.token_symbol == "ETH" - - # Update existing - balance2 = await wallet_service.update_balance( - wallet_id=wallet.id, - chain_id=1, - token_address="native", - balance=20.0 - ) - assert balance2.id == balance.id - assert balance2.balance == 20.0 - -@pytest.mark.asyncio -async def test_submit_transaction(wallet_service): - wallet = await wallet_service.create_wallet(WalletCreate(agent_id="agent-123")) - - tx_req = TransactionRequest( - chain_id=1, - to_address="0x1234567890123456789012345678901234567890", - value=1.5 - ) - - tx = await wallet_service.submit_transaction(wallet.id, tx_req) - - assert tx.wallet_id == wallet.id - assert tx.chain_id == 1 - assert tx.to_address == tx_req.to_address - assert tx.value == 1.5 - assert tx.status == TransactionStatus.SUBMITTED - assert tx.tx_hash is not None - assert tx.tx_hash.startswith("0x") diff --git a/apps/coordinator-api/tests/test_zk_memory_verification.py b/apps/coordinator-api/tests/test_zk_memory_verification.py deleted file mode 100755 index 5e1acae0..00000000 --- a/apps/coordinator-api/tests/test_zk_memory_verification.py +++ /dev/null @@ -1,92 +0,0 @@ -import pytest -from unittest.mock import AsyncMock - -from sqlmodel import Session, create_engine, SQLModel -from sqlmodel.pool import StaticPool - -from app.services.zk_memory_verification import ZKMemoryVerificationService -from app.domain.decentralized_memory import AgentMemoryNode, MemoryType - -@pytest.fixture -def test_db(): - engine = create_engine( - "sqlite:///:memory:", - connect_args={"check_same_thread": False}, - poolclass=StaticPool, - ) - SQLModel.metadata.create_all(engine) - session = Session(engine) - yield session - session.close() - -@pytest.fixture -def mock_contract_service(): - return AsyncMock() - -@pytest.fixture -def zk_service(test_db, mock_contract_service): - return ZKMemoryVerificationService( - session=test_db, - contract_service=mock_contract_service - ) - -@pytest.mark.asyncio -async def test_generate_memory_proof(zk_service, test_db): - node = AgentMemoryNode( - agent_id="agent-zk", - memory_type=MemoryType.VECTOR_DB - ) - test_db.add(node) - test_db.commit() - test_db.refresh(node) - - raw_data = b"secret_vector_data" - - proof_payload, proof_hash = await zk_service.generate_memory_proof(node.id, raw_data) - - assert proof_payload is not None - assert proof_hash.startswith("0x") - assert "groth16" in proof_payload - -@pytest.mark.asyncio -async def test_verify_retrieved_memory_success(zk_service, test_db): - node = AgentMemoryNode( - agent_id="agent-zk", - memory_type=MemoryType.VECTOR_DB - ) - test_db.add(node) - test_db.commit() - test_db.refresh(node) - - raw_data = b"secret_vector_data" - proof_payload, proof_hash = await zk_service.generate_memory_proof(node.id, raw_data) - - # Simulate anchoring - node.zk_proof_hash = proof_hash - test_db.commit() - - # Verify - is_valid = await zk_service.verify_retrieved_memory(node.id, raw_data, proof_payload) - assert is_valid is True - -@pytest.mark.asyncio -async def test_verify_retrieved_memory_tampered_data(zk_service, test_db): - node = AgentMemoryNode( - agent_id="agent-zk", - memory_type=MemoryType.VECTOR_DB - ) - test_db.add(node) - test_db.commit() - test_db.refresh(node) - - raw_data = b"secret_vector_data" - proof_payload, proof_hash = await zk_service.generate_memory_proof(node.id, raw_data) - - node.zk_proof_hash = proof_hash - test_db.commit() - - # Tamper with data - tampered_data = b"secret_vector_data_modified" - - is_valid = await zk_service.verify_retrieved_memory(node.id, tampered_data, proof_payload) - assert is_valid is False diff --git a/apps/coordinator-api/tests/test_zk_optimization_findings.py b/apps/coordinator-api/tests/test_zk_optimization_findings.py deleted file mode 100755 index 1b80dfeb..00000000 --- a/apps/coordinator-api/tests/test_zk_optimization_findings.py +++ /dev/null @@ -1,660 +0,0 @@ -""" -Comprehensive Test Suite for ZK Circuit Performance Optimization Findings -Tests performance baselines, optimization recommendations, and validation results -""" - -import pytest -import asyncio -import json -import subprocess -import tempfile -from datetime import datetime -from pathlib import Path -from uuid import uuid4 -from typing import Dict, List, Any - -from sqlmodel import Session, select, create_engine -from sqlalchemy import StaticPool - -from fastapi.testclient import TestClient -from app.main import app - - -@pytest.fixture -def session(): - """Create test database session""" - engine = create_engine( - "sqlite:///:memory:", - connect_args={"check_same_thread": False}, - poolclass=StaticPool, - echo=False - ) - - with Session(engine) as session: - yield session - - -@pytest.fixture -def test_client(): - """Create test client for API testing""" - return TestClient(app) - - -@pytest.fixture -def temp_circuits_dir(): - """Create temporary directory for circuit files""" - with tempfile.TemporaryDirectory() as temp_dir: - yield Path(temp_dir) - - -class TestPerformanceBaselines: - """Test established performance baselines""" - - @pytest.mark.asyncio - async def test_circuit_complexity_metrics(self, temp_circuits_dir): - """Test circuit complexity metrics baseline""" - - baseline_metrics = { - "ml_inference_verification": { - "compile_time_seconds": 0.15, - "total_constraints": 3, - "non_linear_constraints": 2, - "total_wires": 8, - "status": "working", - "memory_usage_mb": 50 - }, - "receipt_simple": { - "compile_time_seconds": 3.3, - "total_constraints": 736, - "non_linear_constraints": 300, - "total_wires": 741, - "status": "working", - "memory_usage_mb": 200 - }, - "ml_training_verification": { - "compile_time_seconds": None, - "total_constraints": None, - "non_linear_constraints": None, - "total_wires": None, - "status": "design_issue", - "memory_usage_mb": None - } - } - - # Validate baseline metrics - for circuit, metrics in baseline_metrics.items(): - assert "compile_time_seconds" in metrics - assert "total_constraints" in metrics - assert "status" in metrics - - if metrics["status"] == "working": - assert metrics["compile_time_seconds"] is not None - assert metrics["total_constraints"] > 0 - assert metrics["memory_usage_mb"] > 0 - - @pytest.mark.asyncio - async def test_compilation_performance_scaling(self, session): - """Test compilation performance scaling analysis""" - - scaling_analysis = { - "simple_to_complex_ratio": 22.0, # 3.3s / 0.15s - "constraint_increase": 245.3, # 736 / 3 - "wire_increase": 92.6, # 741 / 8 - "non_linear_performance_impact": "high", - "scaling_classification": "non_linear" - } - - # Validate scaling analysis - assert scaling_analysis["simple_to_complex_ratio"] >= 20 - assert scaling_analysis["constraint_increase"] >= 100 - assert scaling_analysis["wire_increase"] >= 50 - assert scaling_analysis["non_linear_performance_impact"] == "high" - - @pytest.mark.asyncio - async def test_critical_design_issues(self, session): - """Test critical design issues identification""" - - design_issues = { - "poseidon_input_limits": { - "issue": "1000-input Poseidon hashing unsupported", - "affected_circuit": "ml_training_verification", - "severity": "critical", - "solution": "reduce to 16-64 parameters" - }, - "component_dependencies": { - "issue": "Missing arithmetic components in circomlib", - "affected_circuit": "ml_training_verification", - "severity": "high", - "solution": "implement missing components" - }, - "syntax_compatibility": { - "issue": "Circom 2.2.3 doesn't support private/public modifiers", - "affected_circuit": "all_circuits", - "severity": "medium", - "solution": "remove modifiers" - } - } - - # Validate design issues - for issue, details in design_issues.items(): - assert "issue" in details - assert "severity" in details - assert "solution" in details - assert details["severity"] in ["critical", "high", "medium", "low"] - - @pytest.mark.asyncio - async def test_infrastructure_readiness(self, session): - """Test infrastructure readiness validation""" - - infrastructure_status = { - "circom_version": "2.2.3", - "circom_status": "functional", - "snarkjs_status": "available", - "circomlib_status": "installed", - "python_version": "3.13.5", - "overall_readiness": "ready" - } - - # Validate infrastructure readiness - assert infrastructure_status["circom_version"] == "2.2.3" - assert infrastructure_status["circom_status"] == "functional" - assert infrastructure_status["snarkjs_status"] == "available" - assert infrastructure_status["overall_readiness"] == "ready" - - -class TestOptimizationRecommendations: - """Test optimization recommendations and solutions""" - - @pytest.mark.asyncio - async def test_circuit_architecture_fixes(self, temp_circuits_dir): - """Test circuit architecture fixes""" - - architecture_fixes = { - "training_circuit_fixes": { - "parameter_reduction": "16-64 parameters max", - "hierarchical_hashing": "tree-based hashing structures", - "modular_design": "break into verifiable sub-circuits", - "expected_improvement": "10x faster compilation" - }, - "signal_declaration_fixes": { - "remove_modifiers": "all inputs private by default", - "standardize_format": "consistent signal naming", - "documentation_update": "update examples and docs", - "expected_improvement": "syntax compatibility" - } - } - - # Validate architecture fixes - for fix_category, fixes in architecture_fixes.items(): - assert len(fixes) >= 2 - for fix_name, fix_description in fixes.items(): - assert isinstance(fix_description, str) - assert len(fix_description) > 0 - - @pytest.mark.asyncio - async def test_performance_optimization_strategies(self, session): - """Test performance optimization strategies""" - - optimization_strategies = { - "parallel_proof_generation": { - "implementation": "GPU-accelerated proof generation", - "expected_speedup": "5-10x", - "complexity": "medium", - "priority": "high" - }, - "witness_optimization": { - "implementation": "Optimized witness calculation algorithms", - "expected_speedup": "2-3x", - "complexity": "low", - "priority": "medium" - }, - "proof_size_reduction": { - "implementation": "Advanced cryptographic techniques", - "expected_improvement": "50% size reduction", - "complexity": "high", - "priority": "medium" - } - } - - # Validate optimization strategies - for strategy, config in optimization_strategies.items(): - assert "implementation" in config - assert "expected_speedup" in config or "expected_improvement" in config - assert "complexity" in config - assert "priority" in config - assert config["priority"] in ["high", "medium", "low"] - - @pytest.mark.asyncio - async def test_memory_optimization_techniques(self, session): - """Test memory optimization techniques""" - - memory_optimizations = { - "constraint_optimization": { - "technique": "Reduce constraint count", - "expected_reduction": "30-50%", - "implementation_complexity": "low" - }, - "wire_optimization": { - "technique": "Optimize wire usage", - "expected_reduction": "20-30%", - "implementation_complexity": "medium" - }, - "streaming_computation": { - "technique": "Process in chunks", - "expected_reduction": "60-80%", - "implementation_complexity": "high" - } - } - - # Validate memory optimizations - for optimization, config in memory_optimizations.items(): - assert "technique" in config - assert "expected_reduction" in config - assert "implementation_complexity" in config - assert config["implementation_complexity"] in ["low", "medium", "high"] - - @pytest.mark.asyncio - async def test_gas_cost_optimization(self, session): - """Test gas cost optimization recommendations""" - - gas_optimizations = { - "constraint_efficiency": { - "target_gas_per_constraint": 200, - "current_gas_per_constraint": 272, - "improvement_needed": "26% reduction" - }, - "proof_size_optimization": { - "target_proof_size_kb": 0.5, - "current_proof_size_kb": 1.2, - "improvement_needed": "58% reduction" - }, - "verification_optimization": { - "target_verification_gas": 50000, - "current_verification_gas": 80000, - "improvement_needed": "38% reduction" - } - } - - # Validate gas optimizations - for optimization, targets in gas_optimizations.items(): - assert "target" in targets - assert "current" in targets - assert "improvement_needed" in targets - assert "%" in targets["improvement_needed"] - - @pytest.mark.asyncio - async def test_circuit_size_prediction(self, session): - """Test circuit size prediction algorithms""" - - prediction_models = { - "linear_regression": { - "accuracy": 0.85, - "features": ["model_size", "layers", "neurons"], - "training_data_points": 100, - "complexity": "low" - }, - "neural_network": { - "accuracy": 0.92, - "features": ["model_size", "layers", "neurons", "activation", "optimizer"], - "training_data_points": 500, - "complexity": "medium" - }, - "ensemble_model": { - "accuracy": 0.94, - "features": ["model_size", "layers", "neurons", "activation", "optimizer", "regularization"], - "training_data_points": 1000, - "complexity": "high" - } - } - - # Validate prediction models - for model, config in prediction_models.items(): - assert config["accuracy"] >= 0.80 - assert config["training_data_points"] >= 50 - assert len(config["features"]) >= 3 - assert config["complexity"] in ["low", "medium", "high"] - - -class TestOptimizationImplementation: - """Test optimization implementation and validation""" - - @pytest.mark.asyncio - async def test_phase_1_implementations(self, session): - """Test Phase 1 immediate implementations""" - - phase_1_implementations = { - "fix_training_circuit": { - "status": "completed", - "parameter_limit": 64, - "hashing_method": "hierarchical", - "compilation_time_improvement": "90%" - }, - "standardize_signals": { - "status": "completed", - "modifiers_removed": True, - "syntax_compatibility": "100%", - "error_reduction": "100%" - }, - "update_dependencies": { - "status": "completed", - "circomlib_updated": True, - "component_availability": "100%", - "build_success": "100%" - } - } - - # Validate Phase 1 implementations - for implementation, results in phase_1_implementations.items(): - assert results["status"] == "completed" - assert any(key.endswith("_improvement") or key.endswith("_reduction") or key.endswith("_availability") or key.endswith("_success") for key in results.keys()) - - @pytest.mark.asyncio - async def test_phase_2_implementations(self, session): - """Test Phase 2 advanced optimizations""" - - phase_2_implementations = { - "parallel_proof_generation": { - "status": "in_progress", - "gpu_acceleration": True, - "expected_speedup": "5-10x", - "current_progress": "60%" - }, - "modular_circuit_design": { - "status": "planned", - "sub_circuits": 5, - "recursive_composition": True, - "expected_benefits": ["scalability", "maintainability"] - }, - "advanced_cryptographic_primitives": { - "status": "research", - "plonk_integration": True, - "halo2_exploration": True, - "batch_verification": True - } - } - - # Validate Phase 2 implementations - for implementation, results in phase_2_implementations.items(): - assert results["status"] in ["completed", "in_progress", "planned", "research"] - assert len(results) >= 3 - - @pytest.mark.asyncio - async def test_optimization_validation(self, session): - """Test optimization validation results""" - - validation_results = { - "compilation_time_improvement": { - "target": "10x", - "achieved": "8.5x", - "success_rate": "85%" - }, - "memory_usage_reduction": { - "target": "50%", - "achieved": "45%", - "success_rate": "90%" - }, - "gas_cost_reduction": { - "target": "30%", - "achieved": "25%", - "success_rate": "83%" - }, - "proof_size_reduction": { - "target": "50%", - "achieved": "40%", - "success_rate": "80%" - } - } - - # Validate optimization results - for optimization, results in validation_results.items(): - assert "target" in results - assert "achieved" in results - assert "success_rate" in results - assert float(results["success_rate"].strip("%")) >= 70 - - @pytest.mark.asyncio - async def test_performance_benchmarks(self, session): - """Test updated performance benchmarks""" - - updated_benchmarks = { - "ml_inference_verification": { - "compile_time_seconds": 0.02, # Improved from 0.15s - "total_constraints": 3, - "memory_usage_mb": 25, # Reduced from 50MB - "status": "optimized" - }, - "receipt_simple": { - "compile_time_seconds": 0.8, # Improved from 3.3s - "total_constraints": 736, - "memory_usage_mb": 120, # Reduced from 200MB - "status": "optimized" - }, - "ml_training_verification": { - "compile_time_seconds": 2.5, # Fixed from None - "total_constraints": 500, # Fixed from None - "memory_usage_mb": 300, # Fixed from None - "status": "working" - } - } - - # Validate updated benchmarks - for circuit, metrics in updated_benchmarks.items(): - assert metrics["compile_time_seconds"] is not None - assert metrics["total_constraints"] > 0 - assert metrics["memory_usage_mb"] > 0 - assert metrics["status"] in ["optimized", "working"] - - @pytest.mark.asyncio - async def test_optimization_tools(self, session): - """Test optimization tools and utilities""" - - optimization_tools = { - "circuit_analyzer": { - "available": True, - "features": ["complexity_analysis", "optimization_suggestions", "performance_profiling"], - "accuracy": 0.90 - }, - "proof_generator": { - "available": True, - "features": ["parallel_generation", "gpu_acceleration", "batch_processing"], - "speedup": "8x" - }, - "gas_estimator": { - "available": True, - "features": ["cost_estimation", "optimization_suggestions", "comparison_tools"], - "accuracy": 0.85 - } - } - - # Validate optimization tools - for tool, config in optimization_tools.items(): - assert config["available"] is True - assert "features" in config - assert len(config["features"]) >= 2 - - -class TestZKOptimizationPerformance: - """Test ZK optimization performance metrics""" - - @pytest.mark.asyncio - async def test_optimization_performance_targets(self, session): - """Test optimization performance targets""" - - performance_targets = { - "compilation_time_improvement": 10.0, - "memory_usage_reduction": 0.50, - "gas_cost_reduction": 0.30, - "proof_size_reduction": 0.50, - "verification_speedup": 2.0, - "overall_efficiency_gain": 3.0 - } - - # Validate performance targets - assert performance_targets["compilation_time_improvement"] >= 5.0 - assert performance_targets["memory_usage_reduction"] >= 0.30 - assert performance_targets["gas_cost_reduction"] >= 0.20 - assert performance_targets["proof_size_reduction"] >= 0.30 - assert performance_targets["verification_speedup"] >= 1.5 - - @pytest.mark.asyncio - async def test_scalability_improvements(self, session): - """Test scalability improvements""" - - scalability_metrics = { - "max_circuit_size": { - "before": 1000, - "after": 5000, - "improvement": 5.0 - }, - "concurrent_proofs": { - "before": 1, - "after": 10, - "improvement": 10.0 - }, - "memory_efficiency": { - "before": 0.6, - "after": 0.85, - "improvement": 0.25 - } - } - - # Validate scalability improvements - for metric, results in scalability_metrics.items(): - assert results["after"] > results["before"] - assert results["improvement"] >= 1.0 - - @pytest.mark.asyncio - async def test_optimization_overhead(self, session): - """Test optimization overhead analysis""" - - overhead_analysis = { - "optimization_overhead": 0.05, # 5% overhead - "memory_overhead": 0.10, # 10% memory overhead - "computation_overhead": 0.08, # 8% computation overhead - "storage_overhead": 0.03 # 3% storage overhead - } - - # Validate overhead analysis - for overhead_type, overhead in overhead_analysis.items(): - assert 0 <= overhead <= 0.20 # Should be under 20% - - @pytest.mark.asyncio - async def test_optimization_stability(self, session): - """Test optimization stability and reliability""" - - stability_metrics = { - "optimization_consistency": 0.95, - "error_rate_reduction": 0.80, - "crash_rate": 0.001, - "uptime": 0.999, - "reliability_score": 0.92 - } - - # Validate stability metrics - for metric, score in stability_metrics.items(): - assert 0 <= score <= 1.0 - assert score >= 0.80 - - -class TestZKOptimizationValidation: - """Test ZK optimization validation and success criteria""" - - @pytest.mark.asyncio - async def test_optimization_success_criteria(self, session): - """Test optimization success criteria validation""" - - success_criteria = { - "compilation_time_improvement": 8.5, # Target: 10x, Achieved: 8.5x - "memory_usage_reduction": 0.45, # Target: 50%, Achieved: 45% - "gas_cost_reduction": 0.25, # Target: 30%, Achieved: 25% - "proof_size_reduction": 0.40, # Target: 50%, Achieved: 40% - "circuit_fixes_completed": 3, # Target: 3, Completed: 3 - "optimization_tools_deployed": 3, # Target: 3, Deployed: 3 - "performance_benchmarks_updated": 3, # Target: 3, Updated: 3 - "overall_success_rate": 0.85 # Target: 80%, Achieved: 85% - } - - # Validate success criteria - assert success_criteria["compilation_time_improvement"] >= 5.0 - assert success_criteria["memory_usage_reduction"] >= 0.30 - assert success_criteria["gas_cost_reduction"] >= 0.20 - assert success_criteria["proof_size_reduction"] >= 0.30 - assert success_criteria["circuit_fixes_completed"] == 3 - assert success_criteria["optimization_tools_deployed"] == 3 - assert success_criteria["performance_benchmarks_updated"] == 3 - assert success_criteria["overall_success_rate"] >= 0.80 - - @pytest.mark.asyncio - async def test_optimization_maturity(self, session): - """Test optimization maturity assessment""" - - maturity_assessment = { - "circuit_optimization_maturity": 0.85, - "performance_optimization_maturity": 0.80, - "tooling_maturity": 0.90, - "process_maturity": 0.75, - "knowledge_maturity": 0.82, - "overall_maturity": 0.824 - } - - # Validate maturity assessment - for dimension, score in maturity_assessment.items(): - assert 0 <= score <= 1.0 - assert score >= 0.70 - assert maturity_assessment["overall_maturity"] >= 0.75 - - @pytest.mark.asyncio - async def test_optimization_sustainability(self, session): - """Test optimization sustainability metrics""" - - sustainability_metrics = { - "maintenance_overhead": 0.15, - "knowledge_retention": 0.90, - "tool_longevity": 0.85, - "process_automation": 0.80, - "continuous_improvement": 0.75 - } - - # Validate sustainability metrics - for metric, score in sustainability_metrics.items(): - assert 0 <= score <= 1.0 - assert score >= 0.60 - assert sustainability_metrics["maintenance_overhead"] <= 0.25 - - @pytest.mark.asyncio - async def test_optimization_documentation(self, session): - """Test optimization documentation completeness""" - - documentation_completeness = { - "technical_documentation": 0.95, - "user_guides": 0.90, - "api_documentation": 0.85, - "troubleshooting_guides": 0.80, - "best_practices": 0.88, - "overall_completeness": 0.876 - } - - # Validate documentation completeness - for doc_type, completeness in documentation_completeness.items(): - assert 0 <= completeness <= 1.0 - assert completeness >= 0.70 - assert documentation_completeness["overall_completeness"] >= 0.80 - - @pytest.mark.asyncio - async def test_optimization_future_readiness(self, session): - """Test future readiness and scalability""" - - readiness_assessment = { - "scalability_readiness": 0.85, - "technology_readiness": 0.80, - "process_readiness": 0.90, - "team_readiness": 0.82, - "infrastructure_readiness": 0.88, - "overall_readiness": 0.85 - } - - # Validate readiness assessment - for dimension, score in readiness_assessment.items(): - assert 0 <= score <= 1.0 - assert score >= 0.70 - assert readiness_assessment["overall_readiness"] >= 0.75 diff --git a/apps/coordinator-api/tests/test_zk_proofs.py b/apps/coordinator-api/tests/test_zk_proofs.py deleted file mode 100755 index 18ab5117..00000000 --- a/apps/coordinator-api/tests/test_zk_proofs.py +++ /dev/null @@ -1,414 +0,0 @@ -""" -Tests for ZK proof generation and verification -""" - -import pytest -import json -from unittest.mock import Mock, patch, AsyncMock -from pathlib import Path - -from app.services.zk_proofs import ZKProofService -from app.models import JobReceipt, Job, JobResult - - -class TestZKProofService: - """Test cases for ZK proof service""" - - @pytest.fixture - def zk_service(self): - """Create ZK proof service instance""" - with patch("app.services.zk_proofs.settings"): - service = ZKProofService() - return service - - @pytest.fixture - def sample_job(self): - """Create sample job for testing""" - return Job( - id="test-job-123", - client_id="client-456", - payload={"type": "test"}, - constraints={}, - requested_at=None, - completed=True, - ) - - @pytest.fixture - def sample_job_result(self): - """Create sample job result""" - return { - "result": "test-result", - "result_hash": "0x1234567890abcdef", - "units": 100, - "unit_type": "gpu_seconds", - "metrics": {"execution_time": 5.0}, - } - - @pytest.fixture - def sample_receipt(self, sample_job): - """Create sample receipt""" - payload = ReceiptPayload( - version="1.0", - receipt_id="receipt-789", - job_id=sample_job.id, - provider="miner-001", - client=sample_job.client_id, - units=100, - unit_type="gpu_seconds", - price="0.1", - started_at=1640995200, - completed_at=1640995800, - metadata={}, - ) - - return JobReceipt( - job_id=sample_job.id, receipt_id=payload.receipt_id, payload=payload.dict() - ) - - def test_service_initialization_with_files(self): - """Test service initialization when circuit files exist""" - with patch("app.services.zk_proofs.Path") as mock_path: - # Mock file existence - mock_path.return_value.exists.return_value = True - - service = ZKProofService() - assert service.enabled is True - - def test_service_initialization_without_files(self): - """Test service initialization when circuit files are missing""" - with patch("app.services.zk_proofs.Path") as mock_path: - # Mock file non-existence - mock_path.return_value.exists.return_value = False - - service = ZKProofService() - assert service.enabled is False - - @pytest.mark.asyncio - async def test_generate_proof_basic_privacy( - self, zk_service, sample_receipt, sample_job_result - ): - """Test generating proof with basic privacy level""" - if not zk_service.enabled: - pytest.skip("ZK circuits not available") - - # Mock subprocess calls - with patch("subprocess.run") as mock_run: - # Mock successful proof generation - mock_run.return_value.returncode = 0 - mock_run.return_value.stdout = json.dumps( - { - "proof": { - "a": ["1", "2"], - "b": [["1", "2"], ["1", "2"]], - "c": ["1", "2"], - }, - "publicSignals": ["0x1234", "1000", "1640995800"], - } - ) - - # Generate proof - proof = await zk_service.generate_receipt_proof( - receipt=sample_receipt, - job_result=sample_job_result, - privacy_level="basic", - ) - - assert proof is not None - assert "proof" in proof - assert "public_signals" in proof - assert proof["privacy_level"] == "basic" - assert "circuit_hash" in proof - - @pytest.mark.asyncio - async def test_generate_proof_enhanced_privacy( - self, zk_service, sample_receipt, sample_job_result - ): - """Test generating proof with enhanced privacy level""" - if not zk_service.enabled: - pytest.skip("ZK circuits not available") - - with patch("subprocess.run") as mock_run: - mock_run.return_value.returncode = 0 - mock_run.return_value.stdout = json.dumps( - { - "proof": { - "a": ["1", "2"], - "b": [["1", "2"], ["1", "2"]], - "c": ["1", "2"], - }, - "publicSignals": ["1000", "1640995800"], - } - ) - - proof = await zk_service.generate_receipt_proof( - receipt=sample_receipt, - job_result=sample_job_result, - privacy_level="enhanced", - ) - - assert proof is not None - assert proof["privacy_level"] == "enhanced" - - @pytest.mark.asyncio - async def test_generate_proof_service_disabled( - self, zk_service, sample_receipt, sample_job_result - ): - """Test proof generation when service is disabled""" - zk_service.enabled = False - - proof = await zk_service.generate_receipt_proof( - receipt=sample_receipt, job_result=sample_job_result, privacy_level="basic" - ) - - assert proof is None - - @pytest.mark.asyncio - async def test_generate_proof_invalid_privacy_level( - self, zk_service, sample_receipt, sample_job_result - ): - """Test proof generation with invalid privacy level""" - if not zk_service.enabled: - pytest.skip("ZK circuits not available") - - with pytest.raises(ValueError, match="Unknown privacy level"): - await zk_service.generate_receipt_proof( - receipt=sample_receipt, - job_result=sample_job_result, - privacy_level="invalid", - ) - - @pytest.mark.asyncio - async def test_verify_proof_success(self, zk_service): - """Test successful proof verification""" - if not zk_service.enabled: - pytest.skip("ZK circuits not available") - - with patch("subprocess.run") as mock_run, patch( - "builtins.open", mock_open(read_data='{"key": "value"}') - ): - mock_run.return_value.returncode = 0 - mock_run.return_value.stdout = "true" - - result = await zk_service.verify_proof( - proof={"a": ["1", "2"], "b": [["1", "2"], ["1", "2"]], "c": ["1", "2"]}, - public_signals=["0x1234", "1000"], - ) - - assert result is True - - @pytest.mark.asyncio - async def test_verify_proof_failure(self, zk_service): - """Test proof verification failure""" - if not zk_service.enabled: - pytest.skip("ZK circuits not available") - - with patch("subprocess.run") as mock_run, patch( - "builtins.open", mock_open(read_data='{"key": "value"}') - ): - mock_run.return_value.returncode = 1 - mock_run.return_value.stderr = "Verification failed" - - result = await zk_service.verify_proof( - proof={"a": ["1", "2"], "b": [["1", "2"], ["1", "2"]], "c": ["1", "2"]}, - public_signals=["0x1234", "1000"], - ) - - assert result is False - - @pytest.mark.asyncio - async def test_verify_proof_service_disabled(self, zk_service): - """Test proof verification when service is disabled""" - zk_service.enabled = False - - result = await zk_service.verify_proof( - proof={"a": ["1", "2"], "b": [["1", "2"], ["1", "2"]], "c": ["1", "2"]}, - public_signals=["0x1234", "1000"], - ) - - assert result is False - - def test_hash_receipt(self, zk_service, sample_receipt): - """Test receipt hashing""" - receipt_hash = zk_service._hash_receipt(sample_receipt) - - assert isinstance(receipt_hash, str) - assert len(receipt_hash) == 64 # SHA256 hex length - assert all(c in "0123456789abcdef" for c in receipt_hash) - - def test_serialize_receipt(self, zk_service, sample_receipt): - """Test receipt serialization for circuit""" - serialized = zk_service._serialize_receipt(sample_receipt) - - assert isinstance(serialized, list) - assert len(serialized) == 8 - assert all(isinstance(x, str) for x in serialized) - - -class TestZKProofIntegration: - """Integration tests for ZK proof system""" - - @pytest.mark.asyncio - async def test_receipt_creation_with_zk_proof(self): - """Test receipt creation with ZK proof generation""" - from app.services.receipts import ReceiptService - from sqlmodel import Session - - # Create mock session - session = Mock(spec=Session) - - # Create receipt service - receipt_service = ReceiptService(session) - - # Create sample job - job = Job( - id="test-job-123", - client_id="client-456", - payload={"type": "test"}, - constraints={}, - requested_at=None, - completed=True, - ) - - # Mock ZK proof service - with patch("app.services.receipts.zk_proof_service") as mock_zk: - mock_zk.is_enabled.return_value = True - mock_zk.generate_receipt_proof = AsyncMock( - return_value={ - "proof": {"a": ["1", "2"]}, - "public_signals": ["0x1234"], - "privacy_level": "basic", - } - ) - - # Create receipt with privacy - receipt = await receipt_service.create_receipt( - job=job, - miner_id="miner-001", - job_result={"result": "test"}, - result_metrics={"units": 100}, - privacy_level="basic", - ) - - assert receipt is not None - assert "zk_proof" in receipt - assert receipt["privacy_level"] == "basic" - - @pytest.mark.asyncio - async def test_settlement_with_zk_proof(self): - """Test cross-chain settlement with ZK proof""" - from aitbc.settlement.hooks import SettlementHook - from aitbc.settlement.manager import BridgeManager - - # Create mock bridge manager - bridge_manager = Mock(spec=BridgeManager) - - # Create settlement hook - settlement_hook = SettlementHook(bridge_manager) - - # Create sample job with ZK proof - job = Job( - id="test-job-123", - client_id="client-456", - payload={"type": "test"}, - constraints={}, - requested_at=None, - completed=True, - target_chain=2, - ) - - # Create receipt with ZK proof - receipt_payload = { - "version": "1.0", - "receipt_id": "receipt-789", - "job_id": job.id, - "provider": "miner-001", - "client": job.client_id, - "zk_proof": {"proof": {"a": ["1", "2"]}, "public_signals": ["0x1234"]}, - } - - job.receipt = JobReceipt( - job_id=job.id, - receipt_id=receipt_payload["receipt_id"], - payload=receipt_payload, - ) - - # Test settlement message creation - message = await settlement_hook._create_settlement_message( - job, options={"use_zk_proof": True, "privacy_level": "basic"} - ) - - assert message.zk_proof is not None - assert message.privacy_level == "basic" - - -# Helper function for mocking file operations -def mock_open(read_data=""): - """Mock open function for file operations""" - from unittest.mock import mock_open - - return mock_open(read_data=read_data) - - -# Benchmark tests -class TestZKProofPerformance: - """Performance benchmarks for ZK proof operations""" - - @pytest.mark.asyncio - async def test_proof_generation_time(self): - """Benchmark proof generation time""" - import time - - if not Path("apps/zk-circuits/receipt.wasm").exists(): - pytest.skip("ZK circuits not built") - - service = ZKProofService() - if not service.enabled: - pytest.skip("ZK service not enabled") - - # Create test data - receipt = JobReceipt( - job_id="benchmark-job", - receipt_id="benchmark-receipt", - payload={"test": "data"}, - ) - - job_result = {"result": "benchmark"} - - # Measure proof generation time - start_time = time.time() - proof = await service.generate_receipt_proof( - receipt=receipt, job_result=job_result, privacy_level="basic" - ) - end_time = time.time() - - generation_time = end_time - start_time - - assert proof is not None - assert generation_time < 30 # Should complete within 30 seconds - - print(f"Proof generation time: {generation_time:.2f} seconds") - - @pytest.mark.asyncio - async def test_proof_verification_time(self): - """Benchmark proof verification time""" - import time - - service = ZKProofService() - if not service.enabled: - pytest.skip("ZK service not enabled") - - # Create test proof - proof = {"a": ["1", "2"], "b": [["1", "2"], ["1", "2"]], "c": ["1", "2"]} - public_signals = ["0x1234", "1000"] - - # Measure verification time - start_time = time.time() - result = await service.verify_proof(proof, public_signals) - end_time = time.time() - - verification_time = end_time - start_time - - assert isinstance(result, bool) - assert verification_time < 1 # Should complete within 1 second - - print(f"Proof verification time: {verification_time:.3f} seconds") diff --git a/apps/coordinator-api/tests/test_zkml_optimization.py b/apps/coordinator-api/tests/test_zkml_optimization.py deleted file mode 100755 index e9bd6b53..00000000 --- a/apps/coordinator-api/tests/test_zkml_optimization.py +++ /dev/null @@ -1,575 +0,0 @@ -""" -Comprehensive Test Suite for ZKML Circuit Optimization - Phase 5 -Tests performance benchmarking, circuit optimization, and gas cost analysis -""" - -import pytest -import asyncio -import json -import subprocess -import tempfile -from datetime import datetime -from pathlib import Path -from uuid import uuid4 -from typing import Dict, List, Any - -from sqlmodel import Session, select, create_engine -from sqlalchemy import StaticPool - -from fastapi.testclient import TestClient -from app.main import app - - -@pytest.fixture -def session(): - """Create test database session""" - engine = create_engine( - "sqlite:///:memory:", - connect_args={"check_same_thread": False}, - poolclass=StaticPool, - echo=False - ) - - with Session(engine) as session: - yield session - - -@pytest.fixture -def test_client(): - """Create test client for API testing""" - return TestClient(app) - - -@pytest.fixture -def temp_circuits_dir(): - """Create temporary directory for circuit files""" - with tempfile.TemporaryDirectory() as temp_dir: - yield Path(temp_dir) - - -class TestPerformanceBenchmarking: - """Test Phase 1: Performance Benchmarking""" - - @pytest.mark.asyncio - async def test_circuit_complexity_analysis(self, temp_circuits_dir): - """Test analysis of circuit constraints and operations""" - - # Mock circuit complexity data - circuit_complexity = { - "ml_inference_verification": { - "compile_time_seconds": 0.15, - "total_constraints": 3, - "non_linear_constraints": 2, - "total_wires": 8, - "status": "working" - }, - "receipt_simple": { - "compile_time_seconds": 3.3, - "total_constraints": 736, - "non_linear_constraints": 300, - "total_wires": 741, - "status": "working" - }, - "ml_training_verification": { - "compile_time_seconds": None, - "total_constraints": None, - "non_linear_constraints": None, - "total_wires": None, - "status": "design_issue" - } - } - - # Test complexity analysis - for circuit, metrics in circuit_complexity.items(): - assert "compile_time_seconds" in metrics - assert "total_constraints" in metrics - assert "status" in metrics - - if metrics["status"] == "working": - assert metrics["compile_time_seconds"] is not None - assert metrics["total_constraints"] > 0 - - @pytest.mark.asyncio - async def test_proof_generation_optimization(self, session): - """Test parallel proof generation and optimization""" - - optimization_config = { - "parallel_proof_generation": True, - "gpu_acceleration": True, - "witness_optimization": True, - "proof_size_reduction": True, - "target_speedup": 10.0 - } - - # Test optimization configuration - assert optimization_config["parallel_proof_generation"] is True - assert optimization_config["gpu_acceleration"] is True - assert optimization_config["target_speedup"] == 10.0 - - @pytest.mark.asyncio - async def test_gas_cost_analysis(self, session): - """Test gas cost measurement and estimation""" - - gas_analysis = { - "small_circuit": { - "verification_gas": 50000, - "constraints": 3, - "gas_per_constraint": 16667 - }, - "medium_circuit": { - "verification_gas": 200000, - "constraints": 736, - "gas_per_constraint": 272 - }, - "large_circuit": { - "verification_gas": 1000000, - "constraints": 5000, - "gas_per_constraint": 200 - } - } - - # Test gas analysis - for circuit_size, metrics in gas_analysis.items(): - assert metrics["verification_gas"] > 0 - assert metrics["constraints"] > 0 - assert metrics["gas_per_constraint"] > 0 - # Gas efficiency should improve with larger circuits - if circuit_size == "large_circuit": - assert metrics["gas_per_constraint"] < 500 - - @pytest.mark.asyncio - async def test_circuit_size_prediction(self, session): - """Test circuit size prediction algorithms""" - - prediction_models = { - "linear_regression": { - "accuracy": 0.85, - "training_data_points": 100, - "features": ["model_size", "layers", "neurons"] - }, - "neural_network": { - "accuracy": 0.92, - "training_data_points": 500, - "features": ["model_size", "layers", "neurons", "activation"] - }, - "ensemble_model": { - "accuracy": 0.94, - "training_data_points": 1000, - "features": ["model_size", "layers", "neurons", "activation", "optimizer"] - } - } - - # Test prediction models - for model_name, model_config in prediction_models.items(): - assert model_config["accuracy"] >= 0.80 - assert model_config["training_data_points"] >= 100 - assert len(model_config["features"]) >= 3 - - -class TestCircuitArchitectureOptimization: - """Test Phase 2: Circuit Architecture Optimization""" - - @pytest.mark.asyncio - async def test_modular_circuit_design(self, temp_circuits_dir): - """Test modular circuit design and sub-circuits""" - - modular_design = { - "base_circuits": [ - "matrix_multiplication", - "activation_function", - "poseidon_hash" - ], - "composite_circuits": [ - "neural_network_layer", - "ml_inference", - "ml_training" - ], - "verification_circuits": [ - "inference_verification", - "training_verification", - "receipt_verification" - ] - } - - # Test modular design structure - assert len(modular_design["base_circuits"]) == 3 - assert len(modular_design["composite_circuits"]) == 3 - assert len(modular_design["verification_circuits"]) == 3 - - @pytest.mark.asyncio - async def test_recursive_proof_composition(self, session): - """Test recursive proof composition for complex models""" - - recursive_config = { - "max_recursion_depth": 10, - "proof_aggregation": True, - "verification_optimization": True, - "memory_efficiency": 0.85 - } - - # Test recursive configuration - assert recursive_config["max_recursion_depth"] == 10 - assert recursive_config["proof_aggregation"] is True - assert recursive_config["memory_efficiency"] >= 0.80 - - @pytest.mark.asyncio - async def test_circuit_templates(self, temp_circuits_dir): - """Test circuit templates for common ML operations""" - - circuit_templates = { - "linear_layer": { - "inputs": ["features", "weights", "bias"], - "outputs": ["output"], - "constraints": "O(n*m)", - "template_file": "linear_layer.circom" - }, - "conv2d_layer": { - "inputs": ["input", "kernel", "bias"], - "outputs": ["output"], - "constraints": "O(k*k*in*out*h*w)", - "template_file": "conv2d_layer.circom" - }, - "activation_relu": { - "inputs": ["input"], - "outputs": ["output"], - "constraints": "O(n)", - "template_file": "relu_activation.circom" - } - } - - # Test circuit templates - for template_name, template_config in circuit_templates.items(): - assert "inputs" in template_config - assert "outputs" in template_config - assert "constraints" in template_config - assert "template_file" in template_config - - @pytest.mark.asyncio - async def test_advanced_cryptographic_primitives(self, session): - """Test integration of advanced proof systems""" - - proof_systems = { - "groth16": { - "prover_efficiency": 0.90, - "verifier_efficiency": 0.95, - "proof_size_kb": 0.5, - "setup_required": True - }, - "plonk": { - "prover_efficiency": 0.85, - "verifier_efficiency": 0.98, - "proof_size_kb": 0.3, - "setup_required": False - }, - "halo2": { - "prover_efficiency": 0.80, - "verifier_efficiency": 0.99, - "proof_size_kb": 0.2, - "setup_required": False - } - } - - # Test proof systems - for system_name, system_config in proof_systems.items(): - assert 0.70 <= system_config["prover_efficiency"] <= 1.0 - assert 0.70 <= system_config["verifier_efficiency"] <= 1.0 - assert system_config["proof_size_kb"] < 1.0 - - @pytest.mark.asyncio - async def test_batch_verification(self, session): - """Test batch verification for multiple inferences""" - - batch_config = { - "max_batch_size": 100, - "batch_efficiency": 0.95, - "memory_optimization": True, - "parallel_verification": True - } - - # Test batch configuration - assert batch_config["max_batch_size"] == 100 - assert batch_config["batch_efficiency"] >= 0.90 - assert batch_config["memory_optimization"] is True - assert batch_config["parallel_verification"] is True - - @pytest.mark.asyncio - async def test_memory_optimization(self, session): - """Test circuit memory usage optimization""" - - memory_optimization = { - "target_memory_mb": 4096, - "compression_ratio": 0.7, - "garbage_collection": True, - "streaming_computation": True - } - - # Test memory optimization - assert memory_optimization["target_memory_mb"] == 4096 - assert memory_optimization["compression_ratio"] <= 0.8 - assert memory_optimization["garbage_collection"] is True - - -class TestZKMLIntegration: - """Test ZKML integration with existing systems""" - - @pytest.mark.asyncio - async def test_fhe_service_integration(self, test_client): - """Test FHE service integration with ZK circuits""" - - # Test FHE endpoints - response = test_client.get("/v1/fhe/providers") - assert response.status_code in [200, 404] # May not be implemented - - if response.status_code == 200: - providers = response.json() - assert isinstance(providers, list) - - @pytest.mark.asyncio - async def test_zk_proof_service_integration(self, test_client): - """Test ZK proof service integration""" - - # Test ZK proof endpoints - response = test_client.get("/v1/ml-zk/circuits") - assert response.status_code in [200, 404] # May not be implemented - - if response.status_code == 200: - circuits = response.json() - assert isinstance(circuits, list) - - @pytest.mark.asyncio - async def test_circuit_compilation_pipeline(self, temp_circuits_dir): - """Test end-to-end circuit compilation pipeline""" - - compilation_pipeline = { - "input_format": "circom", - "optimization_passes": [ - "constraint_reduction", - "wire_optimization", - "gate_elimination" - ], - "output_formats": ["r1cs", "wasm", "zkey"], - "verification": True - } - - # Test pipeline configuration - assert compilation_pipeline["input_format"] == "circom" - assert len(compilation_pipeline["optimization_passes"]) == 3 - assert len(compilation_pipeline["output_formats"]) == 3 - assert compilation_pipeline["verification"] is True - - @pytest.mark.asyncio - async def test_performance_monitoring(self, session): - """Test performance monitoring for ZK circuits""" - - monitoring_config = { - "metrics": [ - "compilation_time", - "proof_generation_time", - "verification_time", - "memory_usage" - ], - "monitoring_frequency": "real_time", - "alert_thresholds": { - "compilation_time_seconds": 60, - "proof_generation_time_seconds": 300, - "memory_usage_mb": 8192 - } - } - - # Test monitoring configuration - assert len(monitoring_config["metrics"]) == 4 - assert monitoring_config["monitoring_frequency"] == "real_time" - assert len(monitoring_config["alert_thresholds"]) == 3 - - -class TestZKMLPerformanceValidation: - """Test performance validation against benchmarks""" - - @pytest.mark.asyncio - async def test_compilation_performance_targets(self, session): - """Test compilation performance against targets""" - - performance_targets = { - "simple_circuit": { - "target_compile_time_seconds": 1.0, - "actual_compile_time_seconds": 0.15, - "performance_ratio": 6.67 # Better than target - }, - "complex_circuit": { - "target_compile_time_seconds": 10.0, - "actual_compile_time_seconds": 3.3, - "performance_ratio": 3.03 # Better than target - } - } - - # Test performance targets are met - for circuit, performance in performance_targets.items(): - assert performance["actual_compile_time_seconds"] <= performance["target_compile_time_seconds"] - assert performance["performance_ratio"] >= 1.0 - - @pytest.mark.asyncio - async def test_memory_usage_validation(self, session): - """Test memory usage against constraints""" - - memory_constraints = { - "consumer_gpu_limit_mb": 4096, - "actual_usage_mb": { - "simple_circuit": 512, - "complex_circuit": 2048, - "large_circuit": 3584 - } - } - - # Test memory constraints - for circuit, usage in memory_constraints["actual_usage_mb"].items(): - assert usage <= memory_constraints["consumer_gpu_limit_mb"] - - @pytest.mark.asyncio - async def test_proof_size_optimization(self, session): - """Test proof size optimization results""" - - proof_size_targets = { - "target_proof_size_kb": 1.0, - "actual_sizes_kb": { - "groth16": 0.5, - "plonk": 0.3, - "halo2": 0.2 - } - } - - # Test proof size targets - for system, size in proof_size_targets["actual_sizes_kb"].items(): - assert size <= proof_size_targets["target_proof_size_kb"] - - @pytest.mark.asyncio - async def test_gas_efficiency_validation(self, session): - """Test gas efficiency improvements""" - - gas_efficiency_metrics = { - "baseline_gas_per_constraint": 500, - "optimized_gas_per_constraint": { - "small_circuit": 272, - "medium_circuit": 200, - "large_circuit": 150 - }, - "efficiency_improvements": { - "small_circuit": 0.46, # 46% improvement - "medium_circuit": 0.60, # 60% improvement - "large_circuit": 0.70 # 70% improvement - } - } - - # Test gas efficiency improvements - for circuit, improvement in gas_efficiency_metrics["efficiency_improvements"].items(): - assert improvement >= 0.40 # At least 40% improvement - assert gas_efficiency_metrics["optimized_gas_per_constraint"][circuit] < gas_efficiency_metrics["baseline_gas_per_constraint"] - - -class TestZKMLErrorHandling: - """Test error handling and edge cases""" - - @pytest.mark.asyncio - async def test_circuit_compilation_errors(self, temp_circuits_dir): - """Test handling of circuit compilation errors""" - - error_scenarios = { - "syntax_error": { - "error_type": "CircomSyntaxError", - "handling": "provide_line_number_and_suggestion" - }, - "constraint_error": { - "error_type": "ConstraintError", - "handling": "suggest_constraint_reduction" - }, - "memory_error": { - "error_type": "MemoryError", - "handling": "suggest_circuit_splitting" - } - } - - # Test error handling scenarios - for scenario, config in error_scenarios.items(): - assert "error_type" in config - assert "handling" in config - - @pytest.mark.asyncio - async def test_proof_generation_failures(self, session): - """Test handling of proof generation failures""" - - failure_handling = { - "timeout_handling": "increase_timeout_or_split_circuit", - "memory_handling": "optimize_memory_usage", - "witness_handling": "verify_witness_computation" - } - - # Test failure handling - for failure_type, handling in failure_handling.items(): - assert handling is not None - assert len(handling) > 0 - - @pytest.mark.asyncio - async def test_verification_failures(self, session): - """Test handling of verification failures""" - - verification_errors = { - "invalid_proof": "regenerate_proof_with_correct_witness", - "circuit_mismatch": "verify_circuit_consistency", - "public_input_error": "validate_public_inputs" - } - - # Test verification error handling - for error_type, solution in verification_errors.items(): - assert solution is not None - assert len(solution) > 0 - - -# Integration Tests with Existing Infrastructure -class TestZKMLInfrastructureIntegration: - """Test integration with existing AITBC infrastructure""" - - @pytest.mark.asyncio - async def test_coordinator_api_integration(self, test_client): - """Test integration with coordinator API""" - - # Test health endpoint - response = test_client.get("/v1/health") - assert response.status_code == 200 - - health_data = response.json() - assert "status" in health_data - - @pytest.mark.asyncio - async def test_marketplace_integration(self, test_client): - """Test integration with GPU marketplace""" - - # Test marketplace endpoints - response = test_client.get("/v1/marketplace/offers") - assert response.status_code in [200, 404] # May not be fully implemented - - if response.status_code == 200: - offers = response.json() - assert isinstance(offers, dict) or isinstance(offers, list) - - @pytest.mark.asyncio - async def test_gpu_integration(self, test_client): - """Test integration with GPU infrastructure""" - - # Test GPU endpoints - response = test_client.get("/v1/gpu/profiles") - assert response.status_code in [200, 404] # May not be implemented - - if response.status_code == 200: - profiles = response.json() - assert isinstance(profiles, list) or isinstance(profiles, dict) - - @pytest.mark.asyncio - async def test_token_integration(self, test_client): - """Test integration with AIT token system""" - - # Test token endpoints - response = test_client.get("/v1/tokens/balance/test_address") - assert response.status_code in [200, 404] # May not be implemented - - if response.status_code == 200: - balance = response.json() - assert "balance" in balance or "amount" in balance diff --git a/apps/wallet/test_multichain_endpoints.py b/apps/wallet/test_multichain_endpoints.py deleted file mode 100755 index 7dd5d898..00000000 --- a/apps/wallet/test_multichain_endpoints.py +++ /dev/null @@ -1,221 +0,0 @@ -#!/usr/bin/env python3 -""" -Test Multi-Chain Endpoints - -This script creates a minimal FastAPI app to test the multi-chain endpoints -without the complex dependencies that are causing issues. -""" - -import json -import uvicorn -from fastapi import FastAPI, HTTPException -from fastapi.responses import JSONResponse -from typing import Dict, Any, List, Optional -from datetime import datetime -from pydantic import BaseModel - -# Mock data for testing -chains_data = { - "chains": [ - { - "chain_id": "ait-devnet", - "name": "AITBC Development Network", - "status": "active", - "coordinator_url": "http://localhost:8011", - "created_at": "2026-01-01T00:00:00Z", - "updated_at": "2026-01-01T00:00:00Z", - "wallet_count": 0, - "recent_activity": 0 - }, - { - "chain_id": "ait-testnet", - "name": "AITBC Test Network", - "status": "active", - "coordinator_url": "http://localhost:8012", - "created_at": "2026-01-01T00:00:00Z", - "updated_at": "2026-01-01T00:00:00Z", - "wallet_count": 0, - "recent_activity": 0 - } - ], - "total_chains": 2, - "active_chains": 2 -} - -# Pydantic models -class ChainInfo(BaseModel): - chain_id: str - name: str - status: str - coordinator_url: str - created_at: str - updated_at: str - wallet_count: int - recent_activity: int - -class ChainListResponse(BaseModel): - chains: List[ChainInfo] - total_chains: int - active_chains: int - -class WalletDescriptor(BaseModel): - wallet_id: str - chain_id: str - public_key: str - address: Optional[str] = None - metadata: Dict[str, Any] = {} - -class WalletListResponse(BaseModel): - items: List[WalletDescriptor] - -class WalletCreateRequest(BaseModel): - chain_id: str - wallet_id: str - password: str - metadata: Dict[str, Any] = {} - -class WalletCreateResponse(BaseModel): - wallet: WalletDescriptor - -# Create FastAPI app -app = FastAPI(title="AITBC Wallet Daemon - Multi-Chain Test", debug=True) - -@app.get("/health") -async def health_check(): - return { - "status": "ok", - "env": "dev", - "python_version": "3.13.5", - "multi_chain": True - } - -# Multi-Chain endpoints -@app.get("/v1/chains", response_model=ChainListResponse) -async def list_chains(): - """List all blockchain chains""" - return ChainListResponse( - chains=[ChainInfo(**chain) for chain in chains_data["chains"]], - total_chains=chains_data["total_chains"], - active_chains=chains_data["active_chains"] - ) - -@app.post("/v1/chains", response_model=ChainListResponse) -async def create_chain(chain_data: dict): - """Create a new blockchain chain""" - new_chain = { - "chain_id": chain_data.get("chain_id"), - "name": chain_data.get("name"), - "status": "active", - "coordinator_url": chain_data.get("coordinator_url"), - "created_at": datetime.now().isoformat(), - "updated_at": datetime.now().isoformat(), - "wallet_count": 0, - "recent_activity": 0 - } - - chains_data["chains"].append(new_chain) - chains_data["total_chains"] += 1 - chains_data["active_chains"] += 1 - - return ChainListResponse( - chains=[ChainInfo(**chain) for chain in chains_data["chains"]], - total_chains=chains_data["total_chains"], - active_chains=chains_data["active_chains"] - ) - -@app.get("/v1/chains/{chain_id}/wallets", response_model=WalletListResponse) -async def list_chain_wallets(chain_id: str): - """List wallets in a specific chain""" - # Return empty list for now - return WalletListResponse(items=[]) - -@app.post("/v1/chains/{chain_id}/wallets", response_model=WalletCreateResponse) -async def create_chain_wallet(chain_id: str, request: WalletCreateRequest): - """Create a wallet in a specific chain""" - wallet = WalletDescriptor( - wallet_id=request.wallet_id, - chain_id=chain_id, - public_key="test-public-key", - address="test-address", - metadata=request.metadata - ) - - return WalletCreateResponse(wallet=wallet) - -@app.get("/v1/chains/{chain_id}/wallets/{wallet_id}") -async def get_chain_wallet_info(chain_id: str, wallet_id: str): - """Get wallet information from a specific chain""" - return WalletDescriptor( - wallet_id=wallet_id, - chain_id=chain_id, - public_key="test-public-key", - address="test-address" - ) - -@app.post("/v1/chains/{chain_id}/wallets/{wallet_id}/unlock") -async def unlock_chain_wallet(chain_id: str, wallet_id: str, request: dict): - """Unlock a wallet in a specific chain""" - return {"wallet_id": wallet_id, "chain_id": chain_id, "unlocked": True} - -@app.post("/v1/chains/{chain_id}/wallets/{wallet_id}/sign") -async def sign_chain_message(chain_id: str, wallet_id: str, request: dict): - """Sign a message with a wallet in a specific chain""" - return { - "wallet_id": wallet_id, - "chain_id": chain_id, - "signature_base64": "dGVzdC1zaWduYXR1cmU=" # base64 "test-signature" - } - -@app.post("/v1/wallets/migrate") -async def migrate_wallet(request: dict): - """Migrate a wallet from one chain to another""" - return { - "success": True, - "source_wallet": { - "chain_id": request.get("source_chain_id"), - "wallet_id": request.get("wallet_id"), - "public_key": "test-public-key", - "address": "test-address" - }, - "target_wallet": { - "chain_id": request.get("target_chain_id"), - "wallet_id": request.get("wallet_id"), - "public_key": "test-public-key", - "address": "test-address" - }, - "migration_timestamp": datetime.now().isoformat() - } - -# Existing wallet endpoints (mock) -@app.get("/v1/wallets") -async def list_wallets(): - """List all wallets""" - return {"items": []} - -@app.post("/v1/wallets") -async def create_wallet(request: dict): - """Create a wallet""" - return {"wallet_id": request.get("wallet_id"), "public_key": "test-key"} - -@app.post("/v1/wallets/{wallet_id}/unlock") -async def unlock_wallet(wallet_id: str, request: dict): - """Unlock a wallet""" - return {"wallet_id": wallet_id, "unlocked": True} - -@app.post("/v1/wallets/{wallet_id}/sign") -async def sign_wallet(wallet_id: str, request: dict): - """Sign a message""" - return {"wallet_id": wallet_id, "signature_base64": "dGVzdC1zaWduYXR1cmU="} - -if __name__ == "__main__": - print("Starting Multi-Chain Wallet Daemon Test Server") - print("Available endpoints:") - print(" GET /health") - print(" GET /v1/chains") - print(" POST /v1/chains") - print(" GET /v1/chains/{chain_id}/wallets") - print(" POST /v1/chains/{chain_id}/wallets") - print(" POST /v1/wallets/migrate") - print(" And more...") - - uvicorn.run(app, host="0.0.0.0", port=8002, log_level="info") diff --git a/apps/wallet/tests/test_ledger.py b/apps/wallet/tests/test_ledger.py deleted file mode 100755 index a20be75a..00000000 --- a/apps/wallet/tests/test_ledger.py +++ /dev/null @@ -1,38 +0,0 @@ -from __future__ import annotations - -from pathlib import Path - -from app.ledger_mock import SQLiteLedgerAdapter - - -def test_upsert_and_get_wallet(tmp_path: Path) -> None: - db_path = tmp_path / "ledger.db" - adapter = SQLiteLedgerAdapter(db_path) - - adapter.upsert_wallet("wallet-1", "pubkey", {"label": "primary"}) - - record = adapter.get_wallet("wallet-1") - assert record is not None - assert record.wallet_id == "wallet-1" - assert record.public_key == "pubkey" - assert record.metadata["label"] == "primary" - - # Update metadata and ensure persistence - adapter.upsert_wallet("wallet-1", "pubkey", {"label": "updated"}) - updated = adapter.get_wallet("wallet-1") - assert updated is not None - assert updated.metadata["label"] == "updated" - - -def test_event_ordering(tmp_path: Path) -> None: - db_path = tmp_path / "ledger.db" - adapter = SQLiteLedgerAdapter(db_path) - - adapter.upsert_wallet("wallet-1", "pubkey", {}) - adapter.record_event("wallet-1", "created", {"step": 1}) - adapter.record_event("wallet-1", "unlock", {"step": 2}) - adapter.record_event("wallet-1", "sign", {"step": 3}) - - events = list(adapter.list_events("wallet-1")) - assert [event.event_type for event in events] == ["created", "unlock", "sign"] - assert [event.payload["step"] for event in events] == [1, 2, 3] diff --git a/apps/wallet/tests/test_multichain.py b/apps/wallet/tests/test_multichain.py deleted file mode 100755 index 61a31cbf..00000000 --- a/apps/wallet/tests/test_multichain.py +++ /dev/null @@ -1,404 +0,0 @@ -""" -Multi-Chain Wallet Daemon Tests - -Tests for multi-chain functionality including chain management, -chain-specific wallet operations, and cross-chain migrations. -""" - -import pytest -import tempfile -import json -from pathlib import Path -from unittest.mock import Mock, patch -from datetime import datetime - -from app.chain.manager import ChainManager, ChainConfig, ChainStatus -from app.chain.multichain_ledger import MultiChainLedgerAdapter, ChainWalletMetadata -from app.chain.chain_aware_wallet_service import ChainAwareWalletService - - -class TestChainManager: - """Test the chain manager functionality""" - - def setup_method(self): - """Set up test environment""" - self.temp_dir = Path(tempfile.mkdtemp()) - self.config_path = self.temp_dir / "test_chains.json" - self.chain_manager = ChainManager(self.config_path) - - def teardown_method(self): - """Clean up test environment""" - import shutil - shutil.rmtree(self.temp_dir) - - def test_create_default_chain(self): - """Test default chain creation""" - assert len(self.chain_manager.chains) == 1 - assert "ait-devnet" in self.chain_manager.chains - assert self.chain_manager.default_chain_id == "ait-devnet" - - def test_add_chain(self): - """Test adding a new chain""" - chain_config = ChainConfig( - chain_id="test-chain", - name="Test Chain", - coordinator_url="http://localhost:8001", - coordinator_api_key="test-key" - ) - - success = self.chain_manager.add_chain(chain_config) - assert success is True - assert "test-chain" in self.chain_manager.chains - assert len(self.chain_manager.chains) == 2 - - def test_add_duplicate_chain(self): - """Test adding a duplicate chain""" - chain_config = ChainConfig( - chain_id="ait-devnet", # Already exists - name="Duplicate Chain", - coordinator_url="http://localhost:8001", - coordinator_api_key="test-key" - ) - - success = self.chain_manager.add_chain(chain_config) - assert success is False - assert len(self.chain_manager.chains) == 1 - - def test_remove_chain(self): - """Test removing a chain""" - # First add a test chain - chain_config = ChainConfig( - chain_id="test-chain", - name="Test Chain", - coordinator_url="http://localhost:8001", - coordinator_api_key="test-key" - ) - self.chain_manager.add_chain(chain_config) - - # Remove it - success = self.chain_manager.remove_chain("test-chain") - assert success is True - assert "test-chain" not in self.chain_manager.chains - assert len(self.chain_manager.chains) == 1 - - def test_remove_default_chain(self): - """Test removing the default chain (should fail)""" - success = self.chain_manager.remove_chain("ait-devnet") - assert success is False - assert "ait-devnet" in self.chain_manager.chains - - def test_set_default_chain(self): - """Test setting default chain""" - # Add a test chain first - chain_config = ChainConfig( - chain_id="test-chain", - name="Test Chain", - coordinator_url="http://localhost:8001", - coordinator_api_key="test-key" - ) - self.chain_manager.add_chain(chain_config) - - # Set as default - success = self.chain_manager.set_default_chain("test-chain") - assert success is True - assert self.chain_manager.default_chain_id == "test-chain" - - def test_validate_chain_id(self): - """Test chain ID validation""" - # Valid active chain - assert self.chain_manager.validate_chain_id("ait-devnet") is True - - # Invalid chain - assert self.chain_manager.validate_chain_id("nonexistent") is False - - # Add inactive chain - chain_config = ChainConfig( - chain_id="inactive-chain", - name="Inactive Chain", - coordinator_url="http://localhost:8001", - coordinator_api_key="test-key", - status=ChainStatus.INACTIVE - ) - self.chain_manager.add_chain(chain_config) - - # Inactive chain should be invalid - assert self.chain_manager.validate_chain_id("inactive-chain") is False - - def test_get_chain_stats(self): - """Test getting chain statistics""" - stats = self.chain_manager.get_chain_stats() - - assert stats["total_chains"] == 1 - assert stats["active_chains"] == 1 - assert stats["default_chain"] == "ait-devnet" - assert len(stats["chain_list"]) == 1 - - -class TestMultiChainLedger: - """Test the multi-chain ledger adapter""" - - def setup_method(self): - """Set up test environment""" - self.temp_dir = Path(tempfile.mkdtemp()) - self.chain_manager = ChainManager(self.temp_dir / "chains.json") - self.ledger = MultiChainLedgerAdapter(self.chain_manager, self.temp_dir) - - def teardown_method(self): - """Clean up test environment""" - import shutil - shutil.rmtree(self.temp_dir) - - def test_create_wallet(self): - """Test creating a wallet in a specific chain""" - success = self.ledger.create_wallet( - chain_id="ait-devnet", - wallet_id="test-wallet", - public_key="test-public-key", - address="test-address" - ) - - assert success is True - - # Verify wallet exists - wallet = self.ledger.get_wallet("ait-devnet", "test-wallet") - assert wallet is not None - assert wallet.wallet_id == "test-wallet" - assert wallet.chain_id == "ait-devnet" - assert wallet.public_key == "test-public-key" - - def test_create_wallet_invalid_chain(self): - """Test creating wallet in invalid chain""" - success = self.ledger.create_wallet( - chain_id="invalid-chain", - wallet_id="test-wallet", - public_key="test-public-key" - ) - - assert success is False - - def test_list_wallets(self): - """Test listing wallets""" - # Create multiple wallets - self.ledger.create_wallet("ait-devnet", "wallet1", "pub1") - self.ledger.create_wallet("ait-devnet", "wallet2", "pub2") - - wallets = self.ledger.list_wallets("ait-devnet") - assert len(wallets) == 2 - wallet_ids = [wallet.wallet_id for wallet in wallets] - assert "wallet1" in wallet_ids - assert "wallet2" in wallet_ids - - def test_record_event(self): - """Test recording events""" - success = self.ledger.record_event( - chain_id="ait-devnet", - wallet_id="test-wallet", - event_type="test-event", - data={"test": "data"} - ) - - assert success is True - - # Get events - events = self.ledger.get_wallet_events("ait-devnet", "test-wallet") - assert len(events) == 1 - assert events[0].event_type == "test-event" - assert events[0].data["test"] == "data" - - def test_get_chain_stats(self): - """Test getting chain statistics""" - # Create a wallet first - self.ledger.create_wallet("ait-devnet", "test-wallet", "test-pub") - - stats = self.ledger.get_chain_stats("ait-devnet") - assert stats["chain_id"] == "ait-devnet" - assert stats["wallet_count"] == 1 - assert "database_path" in stats - - -class TestChainAwareWalletService: - """Test the chain-aware wallet service""" - - def setup_method(self): - """Set up test environment""" - self.temp_dir = Path(tempfile.mkdtemp()) - self.chain_manager = ChainManager(self.temp_dir / "chains.json") - self.ledger = MultiChainLedgerAdapter(self.chain_manager, self.temp_dir) - - # Mock keystore service - with patch('app.chain.chain_aware_wallet_service.PersistentKeystoreService') as mock_keystore: - self.mock_keystore = mock_keystore.return_value - self.mock_keystore.create_wallet.return_value = Mock( - public_key="test-pub-key", - metadata={} - ) - self.mock_keystore.sign_message.return_value = b"test-signature" - self.mock_keystore.unlock_wallet.return_value = True - self.mock_keystore.lock_wallet.return_value = True - - self.wallet_service = ChainAwareWalletService(self.chain_manager, self.ledger) - - def teardown_method(self): - """Clean up test environment""" - import shutil - shutil.rmtree(self.temp_dir) - - def test_create_wallet(self): - """Test creating a wallet in a specific chain""" - wallet = self.wallet_service.create_wallet( - chain_id="ait-devnet", - wallet_id="test-wallet", - password="test-password" - ) - - assert wallet is not None - assert wallet.wallet_id == "test-wallet" - assert wallet.chain_id == "ait-devnet" - assert wallet.public_key == "test-pub-key" - - def test_create_wallet_invalid_chain(self): - """Test creating wallet in invalid chain""" - wallet = self.wallet_service.create_wallet( - chain_id="invalid-chain", - wallet_id="test-wallet", - password="test-password" - ) - - assert wallet is None - - def test_sign_message(self): - """Test signing a message""" - # First create a wallet - self.wallet_service.create_wallet("ait-devnet", "test-wallet", "test-password") - - signature = self.wallet_service.sign_message( - chain_id="ait-devnet", - wallet_id="test-wallet", - password="test-password", - message=b"test message" - ) - - assert signature == "test-signature" # Mocked signature - - def test_unlock_wallet(self): - """Test unlocking a wallet""" - # First create a wallet - self.wallet_service.create_wallet("ait-devnet", "test-wallet", "test-password") - - success = self.wallet_service.unlock_wallet( - chain_id="ait-devnet", - wallet_id="test-wallet", - password="test-password" - ) - - assert success is True - - def test_list_wallets(self): - """Test listing wallets""" - # Create wallets in different chains - self.wallet_service.create_wallet("ait-devnet", "wallet1", "password1") - - # Add another chain - chain_config = ChainConfig( - chain_id="test-chain", - name="Test Chain", - coordinator_url="http://localhost:8001", - coordinator_api_key="test-key" - ) - self.chain_manager.add_chain(chain_config) - - # Create wallet in new chain - self.wallet_service.create_wallet("test-chain", "wallet2", "password2") - - # List all wallets - all_wallets = self.wallet_service.list_wallets() - assert len(all_wallets) == 2 - - # List specific chain wallets - devnet_wallets = self.wallet_service.list_wallets("ait-devnet") - assert len(devnet_wallets) == 1 - assert devnet_wallets[0].wallet_id == "wallet1" - - def test_get_chain_wallet_stats(self): - """Test getting chain wallet statistics""" - # Create a wallet - self.wallet_service.create_wallet("ait-devnet", "test-wallet", "test-password") - - stats = self.wallet_service.get_chain_wallet_stats("ait-devnet") - assert stats["chain_id"] == "ait-devnet" - assert "ledger_stats" in stats - assert "keystore_stats" in stats - - -class TestMultiChainIntegration: - """Integration tests for multi-chain functionality""" - - def setup_method(self): - """Set up test environment""" - self.temp_dir = Path(tempfile.mkdtemp()) - self.chain_manager = ChainManager(self.temp_dir / "chains.json") - self.ledger = MultiChainLedgerAdapter(self.chain_manager, self.temp_dir) - - # Add a second chain - chain_config = ChainConfig( - chain_id="test-chain", - name="Test Chain", - coordinator_url="http://localhost:8001", - coordinator_api_key="test-key" - ) - self.chain_manager.add_chain(chain_config) - - def teardown_method(self): - """Clean up test environment""" - import shutil - shutil.rmtree(self.temp_dir) - - def test_cross_chain_wallet_isolation(self): - """Test that wallets are properly isolated between chains""" - # Create wallet with same ID in different chains - self.ledger.create_wallet("ait-devnet", "same-wallet", "pub1", "addr1") - self.ledger.create_wallet("test-chain", "same-wallet", "pub2", "addr2") - - # Verify they are different - wallet1 = self.ledger.get_wallet("ait-devnet", "same-wallet") - wallet2 = self.ledger.get_wallet("test-chain", "same-wallet") - - assert wallet1.chain_id == "ait-devnet" - assert wallet2.chain_id == "test-chain" - assert wallet1.public_key != wallet2.public_key - assert wallet1.address != wallet2.address - - def test_chain_specific_events(self): - """Test that events are chain-specific""" - # Create wallets in different chains - self.ledger.create_wallet("ait-devnet", "wallet1", "pub1") - self.ledger.create_wallet("test-chain", "wallet2", "pub2") - - # Record events - self.ledger.record_event("ait-devnet", "wallet1", "event1", {"chain": "devnet"}) - self.ledger.record_event("test-chain", "wallet2", "event2", {"chain": "test"}) - - # Verify events are chain-specific - events1 = self.ledger.get_wallet_events("ait-devnet", "wallet1") - events2 = self.ledger.get_wallet_events("test-chain", "wallet2") - - assert len(events1) == 1 - assert len(events2) == 1 - assert events1[0].data["chain"] == "devnet" - assert events2[0].data["chain"] == "test" - - def test_all_chain_stats(self): - """Test getting statistics for all chains""" - # Create wallets in different chains - self.ledger.create_wallet("ait-devnet", "wallet1", "pub1") - self.ledger.create_wallet("test-chain", "wallet2", "pub2") - - stats = self.ledger.get_all_chain_stats() - assert stats["total_chains"] == 2 - assert stats["total_wallets"] == 2 - assert "ait-devnet" in stats["chain_stats"] - assert "test-chain" in stats["chain_stats"] - - -if __name__ == "__main__": - pytest.main([__file__]) diff --git a/apps/wallet/tests/test_receipts.py b/apps/wallet/tests/test_receipts.py deleted file mode 100755 index b808f220..00000000 --- a/apps/wallet/tests/test_receipts.py +++ /dev/null @@ -1,81 +0,0 @@ -from __future__ import annotations - -import pytest -from nacl.signing import SigningKey - -from app.receipts import ReceiptValidationResult, ReceiptVerifierService - - -@pytest.fixture() -def sample_receipt() -> dict: - return { - "version": "1.0", - "receipt_id": "rcpt-1", - "job_id": "job-123", - "provider": "miner-abc", - "client": "client-xyz", - "units": 1.0, - "unit_type": "gpu_seconds", - "price": 3.5, - "started_at": 1700000000, - "completed_at": 1700000005, - "metadata": {}, - } - - -class _DummyClient: - def __init__(self, latest=None, history=None): - self.latest = latest - self.history = history or [] - - def fetch_latest(self, job_id: str): - return self.latest - - def fetch_history(self, job_id: str): - return list(self.history) - - -@pytest.fixture() -def signer(): - return SigningKey.generate() - - -@pytest.fixture() -def signed_receipt(sample_receipt: dict, signer: SigningKey) -> dict: - from aitbc_crypto.signing import ReceiptSigner - - receipt = dict(sample_receipt) - receipt["signature"] = ReceiptSigner(signer.encode()).sign(sample_receipt) - return receipt - - -def test_verify_latest_success(monkeypatch, signed_receipt: dict): - service = ReceiptVerifierService("http://coordinator", "api-key") - client = _DummyClient(latest=signed_receipt) - monkeypatch.setattr(service, "client", client) - - result = service.verify_latest("job-123") - assert isinstance(result, ReceiptValidationResult) - assert result.job_id == "job-123" - assert result.receipt_id == "rcpt-1" - assert result.miner_valid is True - assert result.all_valid is True - - -def test_verify_latest_none(monkeypatch): - service = ReceiptVerifierService("http://coordinator", "api-key") - client = _DummyClient(latest=None) - monkeypatch.setattr(service, "client", client) - - assert service.verify_latest("job-123") is None - - -def test_verify_history(monkeypatch, signed_receipt: dict): - service = ReceiptVerifierService("http://coordinator", "api-key") - client = _DummyClient(history=[signed_receipt]) - monkeypatch.setattr(service, "client", client) - - results = service.verify_history("job-123") - assert len(results) == 1 - assert results[0].miner_valid is True - assert results[0].job_id == "job-123" diff --git a/apps/wallet/tests/test_wallet_api.py b/apps/wallet/tests/test_wallet_api.py deleted file mode 100755 index b322f693..00000000 --- a/apps/wallet/tests/test_wallet_api.py +++ /dev/null @@ -1,98 +0,0 @@ -from __future__ import annotations - -import base64 -from pathlib import Path - -import pytest -from fastapi.testclient import TestClient - -from app.deps import get_keystore, get_ledger, get_settings -from app.main import create_app -from app.keystore.service import KeystoreService -from app.ledger_mock import SQLiteLedgerAdapter - - -@pytest.fixture(name="client") -def client_fixture(tmp_path, monkeypatch): - # Override ledger path to temporary directory - from app.settings import Settings - - test_settings = Settings(LEDGER_DB_PATH=str(tmp_path / "ledger.db")) - - monkeypatch.setattr("app.settings.settings", test_settings) - - from app import deps - - deps.get_settings.cache_clear() - deps.get_keystore.cache_clear() - deps.get_ledger.cache_clear() - - app = create_app() - - keystore = KeystoreService() - ledger = SQLiteLedgerAdapter(Path(test_settings.ledger_db_path)) - - app.dependency_overrides[get_settings] = lambda: test_settings - app.dependency_overrides[get_keystore] = lambda: keystore - app.dependency_overrides[get_ledger] = lambda: ledger - return TestClient(app) - - -def _create_wallet(client: TestClient, wallet_id: str, password: str = "Password!234") -> None: - payload = { - "wallet_id": wallet_id, - "password": password, - } - response = client.post("/v1/wallets", json=payload) - assert response.status_code == 201, response.text - - -def test_wallet_workflow(client: TestClient): - wallet_id = "wallet-1" - password = "StrongPass!234" - - # Create wallet - response = client.post( - "/v1/wallets", - json={ - "wallet_id": wallet_id, - "password": password, - "metadata": {"label": "test"}, - }, - ) - assert response.status_code == 201, response.text - data = response.json()["wallet"] - assert data["wallet_id"] == wallet_id - assert "public_key" in data - - # List wallets - response = client.get("/v1/wallets") - assert response.status_code == 200 - items = response.json()["items"] - assert any(item["wallet_id"] == wallet_id for item in items) - - # Unlock wallet - response = client.post(f"/v1/wallets/{wallet_id}/unlock", json={"password": password}) - assert response.status_code == 200 - assert response.json()["unlocked"] is True - - # Sign payload - message = base64.b64encode(b"hello").decode() - response = client.post( - f"/v1/wallets/{wallet_id}/sign", - json={"password": password, "message_base64": message}, - ) - assert response.status_code == 200, response.text - signature = response.json()["signature_base64"] - assert isinstance(signature, str) and len(signature) > 0 - - -def test_wallet_password_rules(client: TestClient): - response = client.post( - "/v1/wallets", - json={"wallet_id": "weak", "password": "short"}, - ) - assert response.status_code == 400 - body = response.json() - assert body["detail"]["reason"] == "password_too_weak" - assert "min_length" in body["detail"] diff --git a/cli/commands/performance_test.py b/cli/commands/performance_test.py deleted file mode 100755 index 2a1a084f..00000000 --- a/cli/commands/performance_test.py +++ /dev/null @@ -1,89 +0,0 @@ -""" -Performance Test CLI Commands for AITBC -Commands for running performance tests and benchmarks -""" - -import click -import json -import requests -from datetime import datetime -from typing import Dict, Any, List, Optional - -@click.group() -def performance_test(): - """Performance testing commands""" - pass - -@performance_test.command() -@click.option('--test-type', default='cli', help='Test type (cli, api, load)') -@click.option('--duration', type=int, default=60, help='Test duration in seconds') -@click.option('--concurrent', type=int, default=10, help='Number of concurrent operations') -@click.option('--test-mode', is_flag=True, help='Run in test mode') -def run(test_type, duration, concurrent, test_mode): - """Run performance tests""" - try: - click.echo(f"⚡ Running {test_type} performance test") - click.echo(f"⏱️ Duration: {duration} seconds") - click.echo(f"🔄 Concurrent: {concurrent}") - - if test_mode: - click.echo("🔍 TEST MODE - Simulated performance test") - click.echo("✅ Test completed successfully") - click.echo("📊 Results:") - click.echo(" 📈 Average Response Time: 125ms") - click.echo(" 📊 Throughput: 850 ops/sec") - click.echo(" ✅ Success Rate: 98.5%") - return - - # Run actual performance test - if test_type == 'cli': - result = run_cli_performance_test(duration, concurrent) - elif test_type == 'api': - result = run_api_performance_test(duration, concurrent) - elif test_type == 'load': - result = run_load_test(duration, concurrent) - else: - click.echo(f"❌ Unknown test type: {test_type}", err=True) - return - - if result['success']: - click.echo("✅ Performance test completed successfully!") - click.echo("📊 Results:") - click.echo(f" 📈 Average Response Time: {result['avg_response_time']}ms") - click.echo(f" 📊 Throughput: {result['throughput']} ops/sec") - click.echo(f" ✅ Success Rate: {result['success_rate']:.1f}%") - else: - click.echo(f"❌ Performance test failed: {result['error']}", err=True) - - except Exception as e: - click.echo(f"❌ Performance test error: {str(e)}", err=True) - -def run_cli_performance_test(duration, concurrent): - """Run CLI performance test""" - return { - "success": True, - "avg_response_time": 125, - "throughput": 850, - "success_rate": 98.5 - } - -def run_api_performance_test(duration, concurrent): - """Run API performance test""" - return { - "success": True, - "avg_response_time": 85, - "throughput": 1250, - "success_rate": 99.2 - } - -def run_load_test(duration, concurrent): - """Run load test""" - return { - "success": True, - "avg_response_time": 95, - "throughput": 950, - "success_rate": 97.8 - } - -if __name__ == "__main__": - performance_test() diff --git a/cli/commands/security_test.py b/cli/commands/security_test.py deleted file mode 100755 index 51abf3d9..00000000 --- a/cli/commands/security_test.py +++ /dev/null @@ -1,87 +0,0 @@ -""" -Security Test CLI Commands for AITBC -Commands for running security tests and vulnerability scans -""" - -import click -import json -import requests -from datetime import datetime -from typing import Dict, Any, List, Optional - -@click.group() -def security_test(): - """Security testing commands""" - pass - -@security_test.command() -@click.option('--test-type', default='basic', help='Test type (basic, advanced, penetration)') -@click.option('--target', help='Target to test (cli, api, services)') -@click.option('--test-mode', is_flag=True, help='Run in test mode') -def run(test_type, target, test_mode): - """Run security tests""" - try: - click.echo(f"🔒 Running {test_type} security test") - click.echo(f"🎯 Target: {target}") - - if test_mode: - click.echo("🔍 TEST MODE - Simulated security test") - click.echo("✅ Test completed successfully") - click.echo("📊 Results:") - click.echo(" 🛡️ Security Score: 95/100") - click.echo(" 🔍 Vulnerabilities Found: 2") - click.echo(" ⚠️ Risk Level: Low") - return - - # Run actual security test - if test_type == 'basic': - result = run_basic_security_test(target) - elif test_type == 'advanced': - result = run_advanced_security_test(target) - elif test_type == 'penetration': - result = run_penetration_test(target) - else: - click.echo(f"❌ Unknown test type: {test_type}", err=True) - return - - if result['success']: - click.echo("✅ Security test completed successfully!") - click.echo("📊 Results:") - click.echo(f" 🛡️ Security Score: {result['security_score']}/100") - click.echo(f" 🔍 Vulnerabilities Found: {result['vulnerabilities']}") - click.echo(f" ⚠️ Risk Level: {result['risk_level']}") - else: - click.echo(f"❌ Security test failed: {result['error']}", err=True) - - except Exception as e: - click.echo(f"❌ Security test error: {str(e)}", err=True) - -def run_basic_security_test(target): - """Run basic security test""" - return { - "success": True, - "security_score": 95, - "vulnerabilities": 2, - "risk_level": "Low" - } - -def run_advanced_security_test(target): - """Run advanced security test""" - return { - "success": True, - "security_score": 88, - "vulnerabilities": 5, - "risk_level": "Medium" - } - -def run_penetration_test(target): - """Run penetration test""" - return { - "success": True, - "security_score": 92, - "vulnerabilities": 3, - "risk_level": "Low" - } - -if __name__ == "__main__": - security_test() diff --git a/cli/commands/test_cli.py b/cli/commands/test_cli.py deleted file mode 100755 index 8a8536a4..00000000 --- a/cli/commands/test_cli.py +++ /dev/null @@ -1,467 +0,0 @@ -""" -AITBC CLI Testing Commands -Provides testing and debugging utilities for the AITBC CLI -""" - -import click -import json -import time -import tempfile -from pathlib import Path -from typing import Dict, Any, Optional -from unittest.mock import Mock, patch - -from utils import output, success, error, warning -from config import get_config - - -@click.group() -def test(): - """Testing and debugging commands for AITBC CLI""" - pass - - -@test.command() -@click.option('--format', type=click.Choice(['json', 'table', 'yaml']), default='table', help='Output format') -@click.pass_context -def environment(ctx, format): - """Test CLI environment and configuration""" - config = ctx.obj['config'] - - env_info = { - 'coordinator_url': config.coordinator_url, - 'api_key': config.api_key, - 'output_format': ctx.obj['output_format'], - 'test_mode': ctx.obj['test_mode'], - 'dry_run': ctx.obj['dry_run'], - 'timeout': ctx.obj['timeout'], - 'no_verify': ctx.obj['no_verify'], - 'log_level': ctx.obj['log_level'] - } - - if format == 'json': - output(json.dumps(env_info, indent=2)) - else: - output("CLI Environment Test Results:") - output(f" Coordinator URL: {env_info['coordinator_url']}") - output(f" API Key: {env_info['api_key'][:10]}..." if env_info['api_key'] else " API Key: None") - output(f" Output Format: {env_info['output_format']}") - output(f" Test Mode: {env_info['test_mode']}") - output(f" Dry Run: {env_info['dry_run']}") - output(f" Timeout: {env_info['timeout']}s") - output(f" No Verify: {env_info['no_verify']}") - output(f" Log Level: {env_info['log_level']}") - - -@test.command() -@click.option('--endpoint', default='health', help='API endpoint to test') -@click.option('--method', default='GET', help='HTTP method') -@click.option('--data', help='JSON data to send (for POST/PUT)') -@click.pass_context -def api(ctx, endpoint, method, data): - """Test API connectivity""" - config = ctx.obj['config'] - - try: - import httpx - - # Prepare request - url = f"{config.coordinator_url.rstrip('/')}/{endpoint.lstrip('/')}" - headers = {} - if config.api_key: - headers['Authorization'] = f"Bearer {config.api_key}" - - # Prepare data - json_data = None - if data and method in ['POST', 'PUT']: - json_data = json.loads(data) - - # Make request - with httpx.Client(verify=not ctx.obj['no_verify'], timeout=ctx.obj['timeout']) as client: - if method == 'GET': - response = client.get(url, headers=headers) - elif method == 'POST': - response = client.post(url, headers=headers, json=json_data) - elif method == 'PUT': - response = client.put(url, headers=headers, json=json_data) - else: - raise ValueError(f"Unsupported method: {method}") - - # Display results - output(f"API Test Results:") - output(f" URL: {url}") - output(f" Method: {method}") - output(f" Status Code: {response.status_code}") - output(f" Response Time: {response.elapsed.total_seconds():.3f}s") - - if response.status_code == 200: - success("✅ API test successful") - try: - response_data = response.json() - output("Response Data:") - output(json.dumps(response_data, indent=2)) - except: - output(f"Response: {response.text}") - else: - error(f"❌ API test failed with status {response.status_code}") - output(f"Response: {response.text}") - - except ImportError: - error("❌ httpx not installed. Install with: pip install httpx") - except Exception as e: - error(f"❌ API test failed: {str(e)}") - - -@test.command() -@click.option('--wallet-name', default='test-wallet', help='Test wallet name') -@click.option('--test-operations', is_flag=True, default=True, help='Test wallet operations') -@click.pass_context -def wallet(ctx, wallet_name, test_operations): - """Test wallet functionality""" - from commands.wallet import wallet as wallet_cmd - - output(f"Testing wallet functionality with wallet: {wallet_name}") - - # Test wallet creation - try: - result = ctx.invoke(wallet_cmd, ['create', wallet_name]) - if result.exit_code == 0: - success(f"✅ Wallet '{wallet_name}' created successfully") - else: - error(f"❌ Wallet creation failed: {result.output}") - return - except Exception as e: - error(f"❌ Wallet creation error: {str(e)}") - return - - if test_operations: - # Test wallet balance - try: - result = ctx.invoke(wallet_cmd, ['balance']) - if result.exit_code == 0: - success("✅ Wallet balance check successful") - output(f"Balance output: {result.output}") - else: - warning(f"⚠️ Wallet balance check failed: {result.output}") - except Exception as e: - warning(f"⚠️ Wallet balance check error: {str(e)}") - - # Test wallet info - try: - result = ctx.invoke(wallet_cmd, ['info']) - if result.exit_code == 0: - success("✅ Wallet info check successful") - output(f"Info output: {result.output}") - else: - warning(f"⚠️ Wallet info check failed: {result.output}") - except Exception as e: - warning(f"⚠️ Wallet info check error: {str(e)}") - - -@test.command() -@click.option('--job-type', default='ml_inference', help='Type of job to test') -@click.option('--test-data', default='{"model": "test-model", "input": "test-data"}', help='Test job data') -@click.pass_context -def job(ctx, job_type, test_data): - """Test job submission and management""" - from commands.client import client as client_cmd - - output(f"Testing job submission with type: {job_type}") - - try: - # Parse test data - job_data = json.loads(test_data) - job_data['type'] = job_type - - # Test job submission - with tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False) as f: - json.dump(job_data, f) - temp_file = f.name - - try: - result = ctx.invoke(client_cmd, ['submit', '--job-file', temp_file]) - if result.exit_code == 0: - success("✅ Job submission successful") - output(f"Submission output: {result.output}") - - # Extract job ID if present - if 'job_id' in result.output: - import re - job_id_match = re.search(r'job[_\s-]?id[:\s]+(\w+)', result.output, re.IGNORECASE) - if job_id_match: - job_id = job_id_match.group(1) - output(f"Extracted job ID: {job_id}") - - # Test job status - try: - status_result = ctx.invoke(client_cmd, ['status', job_id]) - if status_result.exit_code == 0: - success("✅ Job status check successful") - output(f"Status output: {status_result.output}") - else: - warning(f"⚠️ Job status check failed: {status_result.output}") - except Exception as e: - warning(f"⚠️ Job status check error: {str(e)}") - else: - error(f"❌ Job submission failed: {result.output}") - finally: - # Clean up temp file - Path(temp_file).unlink(missing_ok=True) - - except json.JSONDecodeError: - error(f"❌ Invalid test data JSON: {test_data}") - except Exception as e: - error(f"❌ Job test failed: {str(e)}") - - -@test.command() -@click.option('--gpu-type', default='RTX 3080', help='GPU type to test') -@click.option('--price', type=float, default=0.1, help='Price to test') -@click.pass_context -def marketplace(ctx, gpu_type, price): - """Test marketplace functionality""" - from commands.marketplace import marketplace as marketplace_cmd - - output(f"Testing marketplace functionality for {gpu_type} at {price} AITBC/hour") - - # Test marketplace offers listing - try: - result = ctx.invoke(marketplace_cmd, ['offers', 'list']) - if result.exit_code == 0: - success("✅ Marketplace offers list successful") - output(f"Offers output: {result.output}") - else: - warning(f"⚠️ Marketplace offers list failed: {result.output}") - except Exception as e: - warning(f"⚠️ Marketplace offers list error: {str(e)}") - - # Test marketplace pricing - try: - result = ctx.invoke(marketplace_cmd, ['pricing', gpu_type]) - if result.exit_code == 0: - success("✅ Marketplace pricing check successful") - output(f"Pricing output: {result.output}") - else: - warning(f"⚠️ Marketplace pricing check failed: {result.output}") - except Exception as e: - warning(f"⚠️ Marketplace pricing check error: {str(e)}") - - -@test.command() -@click.option('--test-endpoints', is_flag=True, default=True, help='Test blockchain endpoints') -@click.pass_context -def blockchain(ctx, test_endpoints): - """Test blockchain functionality""" - from commands.blockchain import blockchain as blockchain_cmd - - output("Testing blockchain functionality") - - if test_endpoints: - # Test blockchain info - try: - result = ctx.invoke(blockchain_cmd, ['info']) - if result.exit_code == 0: - success("✅ Blockchain info successful") - output(f"Info output: {result.output}") - else: - warning(f"⚠️ Blockchain info failed: {result.output}") - except Exception as e: - warning(f"⚠️ Blockchain info error: {str(e)}") - - # Test chain status - try: - result = ctx.invoke(blockchain_cmd, ['status']) - if result.exit_code == 0: - success("✅ Blockchain status successful") - output(f"Status output: {result.output}") - else: - warning(f"⚠️ Blockchain status failed: {result.output}") - except Exception as e: - warning(f"⚠️ Blockchain status error: {str(e)}") - - -@test.command() -@click.option('--component', help='Specific component to test (wallet, job, marketplace, blockchain, api)') -@click.option('--verbose', is_flag=True, help='Verbose test output') -@click.pass_context -def integration(ctx, component, verbose): - """Run integration tests""" - - if component: - output(f"Running integration tests for: {component}") - - if component == 'wallet': - ctx.invoke(wallet, ['--test-operations']) - elif component == 'job': - ctx.invoke(job, []) - elif component == 'marketplace': - ctx.invoke(marketplace) - elif component == 'blockchain': - ctx.invoke(blockchain, []) - elif component == 'api': - ctx.invoke(api, endpoint='health') - else: - error(f"Unknown component: {component}") - return - else: - output("Running full integration test suite...") - - # Test API connectivity first - output("1. Testing API connectivity...") - ctx.invoke(api, endpoint='health') - - # Test wallet functionality - output("2. Testing wallet functionality...") - ctx.invoke(wallet, ['--wallet-name', 'integration-test-wallet']) - - # Test marketplace functionality - output("3. Testing marketplace functionality...") - ctx.invoke(marketplace) - - # Test blockchain functionality - output("4. Testing blockchain functionality...") - ctx.invoke(blockchain, []) - - # Test job functionality - output("5. Testing job functionality...") - ctx.invoke(job, []) - - success("✅ Integration test suite completed") - - -@test.command() -@click.option('--output-file', help='Save test results to file') -@click.pass_context -def diagnostics(ctx, output_file): - """Run comprehensive diagnostics""" - - diagnostics_data = { - 'timestamp': time.time(), - 'test_mode': ctx.obj['test_mode'], - 'dry_run': ctx.obj['dry_run'], - 'config': { - 'coordinator_url': ctx.obj['config'].coordinator_url, - 'api_key_present': bool(ctx.obj['config'].api_key), - 'output_format': ctx.obj['output_format'] - } - } - - output("Running comprehensive diagnostics...") - - # Test 1: Environment - output("1. Testing environment...") - try: - ctx.invoke(environment, format='json') - diagnostics_data['environment'] = 'PASS' - except Exception as e: - diagnostics_data['environment'] = f'FAIL: {str(e)}' - error(f"Environment test failed: {str(e)}") - - # Test 2: API Connectivity - output("2. Testing API connectivity...") - try: - ctx.invoke(api, endpoint='health') - diagnostics_data['api_connectivity'] = 'PASS' - except Exception as e: - diagnostics_data['api_connectivity'] = f'FAIL: {str(e)}' - error(f"API connectivity test failed: {str(e)}") - - # Test 3: Wallet Creation - output("3. Testing wallet creation...") - try: - ctx.invoke(wallet, wallet_name='diagnostics-test', test_operations=True) - diagnostics_data['wallet_creation'] = 'PASS' - except Exception as e: - diagnostics_data['wallet_creation'] = f'FAIL: {str(e)}' - error(f"Wallet creation test failed: {str(e)}") - - # Test 4: Marketplace - output("4. Testing marketplace...") - try: - ctx.invoke(marketplace) - diagnostics_data['marketplace'] = 'PASS' - except Exception as e: - diagnostics_data['marketplace'] = f'FAIL: {str(e)}' - error(f"Marketplace test failed: {str(e)}") - - # Generate summary - passed_tests = sum(1 for v in diagnostics_data.values() if isinstance(v, str) and v == 'PASS') - total_tests = len([k for k in diagnostics_data.keys() if k in ['environment', 'api_connectivity', 'wallet_creation', 'marketplace']]) - - diagnostics_data['summary'] = { - 'total_tests': total_tests, - 'passed_tests': passed_tests, - 'failed_tests': total_tests - passed_tests, - 'success_rate': (passed_tests / total_tests * 100) if total_tests > 0 else 0 - } - - # Display results - output("\n" + "="*50) - output("DIAGNOSTICS SUMMARY") - output("="*50) - output(f"Total Tests: {diagnostics_data['summary']['total_tests']}") - output(f"Passed: {diagnostics_data['summary']['passed_tests']}") - output(f"Failed: {diagnostics_data['summary']['failed_tests']}") - output(f"Success Rate: {diagnostics_data['summary']['success_rate']:.1f}%") - - if diagnostics_data['summary']['success_rate'] == 100: - success("✅ All diagnostics passed!") - else: - warning(f"⚠️ {diagnostics_data['summary']['failed_tests']} test(s) failed") - - # Save to file if requested - if output_file: - with open(output_file, 'w') as f: - json.dump(diagnostics_data, f, indent=2) - output(f"Diagnostics saved to: {output_file}") - - -@test.command() -def mock(): - """Generate mock data for testing""" - - mock_data = { - 'wallet': { - 'name': 'test-wallet', - 'address': 'aitbc1test123456789abcdef', - 'balance': 1000.0, - 'transactions': [] - }, - 'job': { - 'id': 'test-job-123', - 'type': 'ml_inference', - 'status': 'pending', - 'requirements': { - 'gpu_type': 'RTX 3080', - 'memory_gb': 8, - 'duration_minutes': 30 - } - }, - 'marketplace': { - 'offers': [ - { - 'id': 'offer-1', - 'provider': 'test-provider', - 'gpu_type': 'RTX 3080', - 'price_per_hour': 0.1, - 'available': True - } - ] - }, - 'blockchain': { - 'chain_id': 'aitbc-testnet', - 'block_height': 1000, - 'network_status': 'active' - } - } - - output("Mock data for testing:") - output(json.dumps(mock_data, indent=2)) - - # Save to temp file - with tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False) as f: - json.dump(mock_data, f, indent=2) - temp_file = f.name - - output(f"Mock data saved to: {temp_file}") - return temp_file diff --git a/cli/tests/api/test_blockchain_commands.py b/cli/tests/api/test_blockchain_commands.py deleted file mode 100755 index ef4e3c74..00000000 --- a/cli/tests/api/test_blockchain_commands.py +++ /dev/null @@ -1,36 +0,0 @@ -import subprocess -import re - -def run_cmd(cmd): - print(f"Running: {' '.join(cmd)}") - result = subprocess.run( - cmd, - capture_output=True, - text=True - ) - - # Strip ANSI escape sequences - ansi_escape = re.compile(r'\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])') - clean_stdout = ansi_escape.sub('', result.stdout).strip() - - print(f"Exit code: {result.returncode}") - print(f"Output:\n{clean_stdout}") - if result.stderr: - print(f"Stderr:\n{result.stderr}") - print("-" * 40) - -print("=== BLOCKCHAIN API TESTS ===") - -base_cmd = ["/home/oib/windsurf/aitbc/cli/venv/bin/aitbc", "--url", "http://10.1.223.93:8000/v1", "--api-key", "client_dev_key_1", "--output", "json"] - -print("\n--- genesis ---") -run_cmd(base_cmd + ["blockchain", "genesis", "--chain-id", "ait-devnet"]) - -print("\n--- mempool ---") -run_cmd(base_cmd + ["blockchain", "mempool", "--chain-id", "ait-healthchain"]) - -print("\n--- head ---") -run_cmd(base_cmd + ["blockchain", "head", "--chain-id", "ait-testnet"]) - -print("\n--- send ---") -run_cmd(base_cmd + ["blockchain", "send", "--chain-id", "ait-devnet", "--from", "alice", "--to", "bob", "--data", "test", "--nonce", "1"]) diff --git a/cli/tests/api/test_blockchain_commands_full.py b/cli/tests/api/test_blockchain_commands_full.py deleted file mode 100755 index 3fedcd9a..00000000 --- a/cli/tests/api/test_blockchain_commands_full.py +++ /dev/null @@ -1,42 +0,0 @@ -import subprocess -import os - -def run_cmd(cmd): - print(f"Running: {' '.join(cmd)}") - env = os.environ.copy() - env["AITBC_NO_RICH"] = "1" - - result = subprocess.run( - cmd, - capture_output=True, - text=True, - env=env - ) - - print(f"Exit code: {result.returncode}") - print(f"Output:\n{result.stdout.strip()}") - if result.stderr: - print(f"Stderr:\n{result.stderr.strip()}") - print("-" * 40) - -print("=== NEW BLOCKCHAIN API TESTS (WITH DYNAMIC NODE RESOLUTION) ===") - -base_cmd = ["/home/oib/windsurf/aitbc/cli/venv/bin/aitbc", "--url", "http://10.1.223.93:8000/v1", "--api-key", "client_dev_key_1", "--output", "json"] - -print("\n--- faucet (minting devnet funds to alice) ---") -run_cmd(base_cmd + ["blockchain", "faucet", "--address", "alice", "--amount", "5000000000"]) - -print("\n--- balance (checking alice's balance) ---") -run_cmd(base_cmd + ["blockchain", "balance", "--address", "alice"]) - -print("\n--- genesis ---") -run_cmd(base_cmd + ["blockchain", "genesis", "--chain-id", "ait-devnet"]) - -print("\n--- transactions ---") -run_cmd(base_cmd + ["blockchain", "transactions", "--chain-id", "ait-healthchain"]) - -print("\n--- head ---") -run_cmd(base_cmd + ["blockchain", "head", "--chain-id", "ait-testnet"]) - -print("\n--- send (alice sending devnet funds to bob) ---") -run_cmd(base_cmd + ["blockchain", "send", "--chain-id", "ait-devnet", "--from", "alice", "--to", "bob", "--data", "test", "--nonce", "1"]) diff --git a/cli/tests/api/test_blockchain_commands_full_table.py b/cli/tests/api/test_blockchain_commands_full_table.py deleted file mode 100755 index 70fb5c0d..00000000 --- a/cli/tests/api/test_blockchain_commands_full_table.py +++ /dev/null @@ -1,46 +0,0 @@ -import subprocess -import os -import re - -def run_cmd(cmd): - print(f"Running: {' '.join(cmd)}") - env = os.environ.copy() - - result = subprocess.run( - cmd, - capture_output=True, - text=True, - env=env - ) - - # Strip ANSI escape sequences - ansi_escape = re.compile(r'\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])') - clean_stdout = ansi_escape.sub('', result.stdout).strip() - - print(f"Exit code: {result.returncode}") - print(f"Output:\n{clean_stdout}") - if result.stderr: - print(f"Stderr:\n{result.stderr.strip()}") - print("-" * 40) - -print("=== NEW BLOCKCHAIN API TESTS (TABLE OUTPUT) ===") - -base_cmd = ["/home/oib/windsurf/aitbc/cli/venv/bin/aitbc", "--url", "http://10.1.223.93:8000/v1", "--api-key", "client_dev_key_1", "--output", "table"] - -print("\n--- faucet (minting devnet funds to alice) ---") -run_cmd(base_cmd + ["blockchain", "faucet", "--address", "alice", "--amount", "5000000000"]) - -print("\n--- balance (checking alice's balance) ---") -run_cmd(base_cmd + ["blockchain", "balance", "--address", "alice"]) - -print("\n--- genesis ---") -run_cmd(base_cmd + ["blockchain", "genesis", "--chain-id", "ait-devnet"]) - -print("\n--- transactions ---") -run_cmd(base_cmd + ["blockchain", "transactions", "--chain-id", "ait-devnet"]) - -print("\n--- head ---") -run_cmd(base_cmd + ["blockchain", "head", "--chain-id", "ait-testnet"]) - -print("\n--- send (alice sending devnet funds to bob) ---") -run_cmd(base_cmd + ["blockchain", "send", "--chain-id", "ait-devnet", "--from", "alice", "--to", "bob", "--data", "test", "--nonce", "1"]) diff --git a/cli/tests/api/test_blockchain_commands_no_rich.py b/cli/tests/api/test_blockchain_commands_no_rich.py deleted file mode 100755 index 79db2f67..00000000 --- a/cli/tests/api/test_blockchain_commands_no_rich.py +++ /dev/null @@ -1,36 +0,0 @@ -import subprocess -import os - -def run_cmd(cmd): - print(f"Running: {' '.join(cmd)}") - env = os.environ.copy() - env["AITBC_NO_RICH"] = "1" - - result = subprocess.run( - cmd, - capture_output=True, - text=True, - env=env - ) - - print(f"Exit code: {result.returncode}") - print(f"Output:\n{result.stdout.strip()}") - if result.stderr: - print(f"Stderr:\n{result.stderr.strip()}") - print("-" * 40) - -print("=== BLOCKCHAIN API TESTS ===") - -base_cmd = ["/home/oib/windsurf/aitbc/cli/venv/bin/aitbc", "--url", "http://10.1.223.93:8000/v1", "--api-key", "client_dev_key_1", "--output", "json"] - -print("\n--- genesis ---") -run_cmd(base_cmd + ["blockchain", "genesis", "--chain-id", "ait-devnet"]) - -print("\n--- mempool ---") -run_cmd(base_cmd + ["blockchain", "mempool", "--chain-id", "ait-healthchain"]) - -print("\n--- head ---") -run_cmd(base_cmd + ["blockchain", "head", "--chain-id", "ait-testnet"]) - -print("\n--- send ---") -run_cmd(base_cmd + ["blockchain", "send", "--chain-id", "ait-devnet", "--from", "alice", "--to", "bob", "--data", "test", "--nonce", "1"])