refactor: clean up tests/ root — delete junk, sort into subdirs
Deleted (7 files): - test_discovery.py, test_windsurf_integration.py (trivial assert True stubs) - pytest_simple.ini (unused --collect-only config) - conftest_path.py (duplicate of conftest.py path setup) - conftest_fixtures.py, conftest_full.py (unused conftest variants) Moved to integration/ (6 files): - test_blockchain_final.py, test_blockchain_nodes.py, test_blockchain_simple.py - test_basic_integration.py, test_integration_simple.py, test_working_integration.py Moved to fixtures/: - mock_blockchain_node.py tests/ root now has only conftest.py and README.md.
This commit is contained in:
@@ -1,468 +0,0 @@
|
|||||||
"""
|
|
||||||
Comprehensive test fixtures for AITBC testing
|
|
||||||
"""
|
|
||||||
|
|
||||||
import pytest
|
|
||||||
import asyncio
|
|
||||||
import json
|
|
||||||
from datetime import datetime, timedelta
|
|
||||||
from typing import Dict, Any, Generator
|
|
||||||
from unittest.mock import Mock, AsyncMock
|
|
||||||
from fastapi.testclient import TestClient
|
|
||||||
from sqlalchemy import create_engine
|
|
||||||
from sqlalchemy.orm import sessionmaker
|
|
||||||
|
|
||||||
# Import all necessary modules
|
|
||||||
from apps.coordinator_api.src.app.main import app as coordinator_app
|
|
||||||
from apps.wallet_daemon.src.app.main import app as wallet_app
|
|
||||||
from apps.blockchain_node.src.aitbc_chain.node import BlockchainNode
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="session")
|
|
||||||
def event_loop():
|
|
||||||
"""Create an instance of the default event loop for the test session."""
|
|
||||||
loop = asyncio.get_event_loop_policy().new_event_loop()
|
|
||||||
yield loop
|
|
||||||
loop.close()
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def coordinator_client():
|
|
||||||
"""Create a test client for coordinator API"""
|
|
||||||
return TestClient(coordinator_app)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def wallet_client():
|
|
||||||
"""Create a test client for wallet daemon"""
|
|
||||||
return TestClient(wallet_app)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def blockchain_client():
|
|
||||||
"""Create a test client for blockchain node"""
|
|
||||||
node = BlockchainNode()
|
|
||||||
return TestClient(node.app)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def marketplace_client():
|
|
||||||
"""Create a test client for marketplace"""
|
|
||||||
from apps.marketplace.src.app.main import app as marketplace_app
|
|
||||||
return TestClient(marketplace_app)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def sample_tenant():
|
|
||||||
"""Create a sample tenant for testing"""
|
|
||||||
return {
|
|
||||||
"id": "tenant-123",
|
|
||||||
"name": "Test Tenant",
|
|
||||||
"created_at": datetime.utcnow(),
|
|
||||||
"status": "active"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def sample_user():
|
|
||||||
"""Create a sample user for testing"""
|
|
||||||
return {
|
|
||||||
"id": "user-123",
|
|
||||||
"email": "test@example.com",
|
|
||||||
"tenant_id": "tenant-123",
|
|
||||||
"role": "user",
|
|
||||||
"created_at": datetime.utcnow()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def sample_wallet_data():
|
|
||||||
"""Sample wallet creation data"""
|
|
||||||
return {
|
|
||||||
"name": "Test Wallet",
|
|
||||||
"type": "hd",
|
|
||||||
"currency": "AITBC"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def sample_wallet():
|
|
||||||
"""Sample wallet object"""
|
|
||||||
return {
|
|
||||||
"id": "wallet-123",
|
|
||||||
"address": "0x1234567890abcdef1234567890abcdef12345678",
|
|
||||||
"user_id": "user-123",
|
|
||||||
"balance": "1000.0",
|
|
||||||
"status": "active",
|
|
||||||
"created_at": datetime.utcnow()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def sample_job_data():
|
|
||||||
"""Sample job creation data"""
|
|
||||||
return {
|
|
||||||
"job_type": "ai_inference",
|
|
||||||
"parameters": {
|
|
||||||
"model": "gpt-4",
|
|
||||||
"prompt": "Test prompt",
|
|
||||||
"max_tokens": 100,
|
|
||||||
"temperature": 0.7
|
|
||||||
},
|
|
||||||
"priority": "normal",
|
|
||||||
"timeout": 300
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def sample_job():
|
|
||||||
"""Sample job object"""
|
|
||||||
return {
|
|
||||||
"id": "job-123",
|
|
||||||
"job_type": "ai_inference",
|
|
||||||
"status": "pending",
|
|
||||||
"tenant_id": "tenant-123",
|
|
||||||
"created_at": datetime.utcnow(),
|
|
||||||
"parameters": {
|
|
||||||
"model": "gpt-4",
|
|
||||||
"prompt": "Test prompt"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def sample_transaction():
|
|
||||||
"""Sample transaction object"""
|
|
||||||
return {
|
|
||||||
"hash": "0x1234567890abcdef",
|
|
||||||
"from": "0xsender1234567890",
|
|
||||||
"to": "0xreceiver1234567890",
|
|
||||||
"value": "1000",
|
|
||||||
"gas": "21000",
|
|
||||||
"gas_price": "20",
|
|
||||||
"nonce": 1,
|
|
||||||
"status": "pending"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def sample_block():
|
|
||||||
"""Sample block object"""
|
|
||||||
return {
|
|
||||||
"number": 100,
|
|
||||||
"hash": "0xblock1234567890",
|
|
||||||
"parent_hash": "0xparent0987654321",
|
|
||||||
"timestamp": datetime.utcnow(),
|
|
||||||
"transactions": [],
|
|
||||||
"validator": "0xvalidator123"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def sample_account():
|
|
||||||
"""Sample account object"""
|
|
||||||
return {
|
|
||||||
"address": "0xaccount1234567890",
|
|
||||||
"balance": "1000000",
|
|
||||||
"nonce": 25,
|
|
||||||
"code_hash": "0xempty"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def signed_receipt():
|
|
||||||
"""Sample signed receipt"""
|
|
||||||
return {
|
|
||||||
"job_id": "job-123",
|
|
||||||
"hash": "0xreceipt123456",
|
|
||||||
"signature": "sig789012345",
|
|
||||||
"miner_id": "miner-123",
|
|
||||||
"timestamp": datetime.utcnow().isoformat()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def sample_tenant_quota():
|
|
||||||
"""Sample tenant quota"""
|
|
||||||
return {
|
|
||||||
"tenant_id": "tenant-123",
|
|
||||||
"jobs_per_day": 1000,
|
|
||||||
"jobs_per_month": 30000,
|
|
||||||
"max_concurrent": 50,
|
|
||||||
"storage_gb": 100
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def validator_address():
|
|
||||||
"""Sample validator address"""
|
|
||||||
return "0xvalidator1234567890abcdef"
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def miner_address():
|
|
||||||
"""Sample miner address"""
|
|
||||||
return "0xminer1234567890abcdef"
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def sample_transactions():
|
|
||||||
"""List of sample transactions"""
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
"hash": "0xtx123",
|
|
||||||
"from": "0xaddr1",
|
|
||||||
"to": "0xaddr2",
|
|
||||||
"value": "100"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"hash": "0xtx456",
|
|
||||||
"from": "0xaddr3",
|
|
||||||
"to": "0xaddr4",
|
|
||||||
"value": "200"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def sample_block(sample_transactions):
|
|
||||||
"""Sample block with transactions"""
|
|
||||||
return {
|
|
||||||
"number": 100,
|
|
||||||
"hash": "0xblockhash123",
|
|
||||||
"parent_hash": "0xparenthash456",
|
|
||||||
"transactions": sample_transactions,
|
|
||||||
"timestamp": datetime.utcnow(),
|
|
||||||
"validator": "0xvalidator123"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def mock_database():
|
|
||||||
"""Mock database session"""
|
|
||||||
engine = create_engine("sqlite:///:memory:")
|
|
||||||
Session = sessionmaker(bind=engine)
|
|
||||||
session = Session()
|
|
||||||
yield session
|
|
||||||
session.close()
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def mock_redis():
|
|
||||||
"""Mock Redis client"""
|
|
||||||
from unittest.mock import Mock
|
|
||||||
redis_mock = Mock()
|
|
||||||
redis_mock.get.return_value = None
|
|
||||||
redis_mock.set.return_value = True
|
|
||||||
redis_mock.delete.return_value = 1
|
|
||||||
return redis_mock
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def mock_web3():
|
|
||||||
"""Mock Web3 instance"""
|
|
||||||
from unittest.mock import Mock
|
|
||||||
web3_mock = Mock()
|
|
||||||
web3_mock.eth.contract.return_value = Mock()
|
|
||||||
web3_mock.eth.get_balance.return_value = 1000000
|
|
||||||
web3_mock.eth.gas_price = 20
|
|
||||||
return web3_mock
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def browser():
|
|
||||||
"""Selenium WebDriver fixture for E2E tests"""
|
|
||||||
from selenium import webdriver
|
|
||||||
from selenium.webdriver.chrome.options import Options
|
|
||||||
|
|
||||||
options = Options()
|
|
||||||
options.add_argument("--headless")
|
|
||||||
options.add_argument("--no-sandbox")
|
|
||||||
options.add_argument("--disable-dev-shm-usage")
|
|
||||||
|
|
||||||
driver = webdriver.Chrome(options=options)
|
|
||||||
driver.implicitly_wait(10)
|
|
||||||
yield driver
|
|
||||||
driver.quit()
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def mobile_browser():
|
|
||||||
"""Mobile browser fixture for responsive testing"""
|
|
||||||
from selenium import webdriver
|
|
||||||
from selenium.webdriver.chrome.options import Options
|
|
||||||
|
|
||||||
options = Options()
|
|
||||||
options.add_argument("--headless")
|
|
||||||
options.add_argument("--no-sandbox")
|
|
||||||
options.add_argument("--disable-dev-shm-usage")
|
|
||||||
|
|
||||||
mobile_emulation = {
|
|
||||||
"deviceMetrics": {"width": 375, "height": 667, "pixelRatio": 2.0},
|
|
||||||
"userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 14_0 like Mac OS X)"
|
|
||||||
}
|
|
||||||
options.add_experimental_option("mobileEmulation", mobile_emulation)
|
|
||||||
|
|
||||||
driver = webdriver.Chrome(options=options)
|
|
||||||
driver.implicitly_wait(10)
|
|
||||||
yield driver
|
|
||||||
driver.quit()
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def base_url():
|
|
||||||
"""Base URL for E2E tests"""
|
|
||||||
return "http://localhost:8000"
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def mock_file_storage():
|
|
||||||
"""Mock file storage service"""
|
|
||||||
from unittest.mock import Mock
|
|
||||||
storage_mock = Mock()
|
|
||||||
storage_mock.upload.return_value = {"url": "http://example.com/file.txt"}
|
|
||||||
storage_mock.download.return_value = b"file content"
|
|
||||||
storage_mock.delete.return_value = True
|
|
||||||
return storage_mock
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def mock_email_service():
|
|
||||||
"""Mock email service"""
|
|
||||||
from unittest.mock import Mock
|
|
||||||
email_mock = Mock()
|
|
||||||
email_mock.send.return_value = {"message_id": "msg-123"}
|
|
||||||
email_mock.send_verification.return_value = {"token": "token-456"}
|
|
||||||
return email_mock
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def mock_notification_service():
|
|
||||||
"""Mock notification service"""
|
|
||||||
from unittest.mock import Mock
|
|
||||||
notification_mock = Mock()
|
|
||||||
notification_mock.send_push.return_value = True
|
|
||||||
notification_mock.send_webhook.return_value = {"status": "sent"}
|
|
||||||
return notification_mock
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def sample_api_key():
|
|
||||||
"""Sample API key"""
|
|
||||||
return {
|
|
||||||
"id": "key-123",
|
|
||||||
"key": "aitbc_test_key_1234567890",
|
|
||||||
"name": "Test API Key",
|
|
||||||
"permissions": ["read", "write"],
|
|
||||||
"created_at": datetime.utcnow()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def sample_service_listing():
|
|
||||||
"""Sample marketplace service listing"""
|
|
||||||
return {
|
|
||||||
"id": "service-123",
|
|
||||||
"name": "AI Inference Service",
|
|
||||||
"description": "High-performance AI inference",
|
|
||||||
"provider_id": "provider-123",
|
|
||||||
"pricing": {
|
|
||||||
"per_token": 0.0001,
|
|
||||||
"per_minute": 0.01
|
|
||||||
},
|
|
||||||
"capabilities": ["text-generation", "image-generation"],
|
|
||||||
"status": "active"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def sample_booking():
|
|
||||||
"""Sample booking object"""
|
|
||||||
return {
|
|
||||||
"id": "booking-123",
|
|
||||||
"service_id": "service-123",
|
|
||||||
"client_id": "client-123",
|
|
||||||
"status": "confirmed",
|
|
||||||
"start_time": datetime.utcnow() + timedelta(hours=1),
|
|
||||||
"end_time": datetime.utcnow() + timedelta(hours=2),
|
|
||||||
"total_cost": "10.0"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def mock_blockchain_node():
|
|
||||||
"""Mock blockchain node for testing"""
|
|
||||||
from unittest.mock import Mock
|
|
||||||
node_mock = Mock()
|
|
||||||
node_mock.start.return_value = {"status": "running"}
|
|
||||||
node_mock.stop.return_value = {"status": "stopped"}
|
|
||||||
node_mock.get_block.return_value = {"number": 100, "hash": "0x123"}
|
|
||||||
node_mock.submit_transaction.return_value = {"hash": "0xtx456"}
|
|
||||||
return node_mock
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def sample_zk_proof():
|
|
||||||
"""Sample zero-knowledge proof"""
|
|
||||||
return {
|
|
||||||
"proof": "zk_proof_123456",
|
|
||||||
"public_inputs": ["x", "y"],
|
|
||||||
"verification_key": "vk_789012"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def sample_confidential_data():
|
|
||||||
"""Sample confidential transaction data"""
|
|
||||||
return {
|
|
||||||
"encrypted_payload": "encrypted_data_123",
|
|
||||||
"commitment": "commitment_hash_456",
|
|
||||||
"nullifier": "nullifier_789",
|
|
||||||
"merkle_proof": {
|
|
||||||
"root": "root_hash",
|
|
||||||
"path": ["hash1", "hash2", "hash3"],
|
|
||||||
"indices": [0, 1, 0]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def mock_ipfs():
|
|
||||||
"""Mock IPFS client"""
|
|
||||||
from unittest.mock import Mock
|
|
||||||
ipfs_mock = Mock()
|
|
||||||
ipfs_mock.add.return_value = {"Hash": "QmHash123"}
|
|
||||||
ipfs_mock.cat.return_value = b"IPFS content"
|
|
||||||
ipfs_mock.pin.return_value = {"Pins": ["QmHash123"]}
|
|
||||||
return ipfs_mock
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(autouse=True)
|
|
||||||
def cleanup_mocks():
|
|
||||||
"""Cleanup after each test"""
|
|
||||||
yield
|
|
||||||
# Add any cleanup code here
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
# Performance testing fixtures
|
|
||||||
@pytest.fixture
|
|
||||||
def performance_metrics():
|
|
||||||
"""Collect performance metrics during test"""
|
|
||||||
import time
|
|
||||||
start_time = time.time()
|
|
||||||
yield {"start": start_time}
|
|
||||||
end_time = time.time()
|
|
||||||
return {"duration": end_time - start_time}
|
|
||||||
|
|
||||||
|
|
||||||
# Load testing fixtures
|
|
||||||
@pytest.fixture
|
|
||||||
def load_test_config():
|
|
||||||
"""Configuration for load testing"""
|
|
||||||
return {
|
|
||||||
"concurrent_users": 100,
|
|
||||||
"ramp_up_time": 30,
|
|
||||||
"test_duration": 300,
|
|
||||||
"target_rps": 50
|
|
||||||
}
|
|
||||||
@@ -1,473 +0,0 @@
|
|||||||
"""
|
|
||||||
Shared test configuration and fixtures for AITBC
|
|
||||||
"""
|
|
||||||
|
|
||||||
import asyncio
|
|
||||||
import pytest
|
|
||||||
import json
|
|
||||||
import tempfile
|
|
||||||
from datetime import datetime, timedelta
|
|
||||||
from typing import Dict, Any, Generator, AsyncGenerator
|
|
||||||
from unittest.mock import Mock, AsyncMock
|
|
||||||
from sqlalchemy import create_engine, event
|
|
||||||
from sqlalchemy.orm import sessionmaker, Session
|
|
||||||
from sqlalchemy.pool import StaticPool
|
|
||||||
from fastapi.testclient import TestClient
|
|
||||||
import redis
|
|
||||||
from cryptography.hazmat.primitives.asymmetric import ed25519
|
|
||||||
from cryptography.hazmat.primitives import serialization
|
|
||||||
|
|
||||||
# Import AITBC modules
|
|
||||||
from apps.coordinator_api.src.app.main import app as coordinator_app
|
|
||||||
from apps.coordinator_api.src.app.database import get_db
|
|
||||||
from apps.coordinator_api.src.app.models import Base
|
|
||||||
from apps.coordinator_api.src.app.models.multitenant import Tenant, TenantUser, TenantQuota
|
|
||||||
from apps.wallet_daemon.src.app.main import app as wallet_app
|
|
||||||
from packages.py.aitbc_crypto import sign_receipt, verify_receipt
|
|
||||||
from packages.py.aitbc_sdk import AITBCClient
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="session")
|
|
||||||
def event_loop():
|
|
||||||
"""Create an instance of the default event loop for the test session."""
|
|
||||||
loop = asyncio.get_event_loop_policy().new_event_loop()
|
|
||||||
yield loop
|
|
||||||
loop.close()
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="session")
|
|
||||||
def test_config():
|
|
||||||
"""Test configuration settings."""
|
|
||||||
return {
|
|
||||||
"database_url": "sqlite:///:memory:",
|
|
||||||
"redis_url": "redis://localhost:6379/1", # Use test DB
|
|
||||||
"test_tenant_id": "test-tenant-123",
|
|
||||||
"test_user_id": "test-user-456",
|
|
||||||
"test_api_key": "test-api-key-789",
|
|
||||||
"coordinator_url": "http://localhost:8001",
|
|
||||||
"wallet_url": "http://localhost:8002",
|
|
||||||
"blockchain_url": "http://localhost:8545",
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="session")
|
|
||||||
def test_engine(test_config):
|
|
||||||
"""Create a test database engine."""
|
|
||||||
engine = create_engine(
|
|
||||||
test_config["database_url"],
|
|
||||||
connect_args={"check_same_thread": False},
|
|
||||||
poolclass=StaticPool,
|
|
||||||
)
|
|
||||||
Base.metadata.create_all(bind=engine)
|
|
||||||
yield engine
|
|
||||||
Base.metadata.drop_all(bind=engine)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def db_session(test_engine) -> Generator[Session, None, None]:
|
|
||||||
"""Create a database session for testing."""
|
|
||||||
connection = test_engine.connect()
|
|
||||||
transaction = connection.begin()
|
|
||||||
session = sessionmaker(autocommit=False, autoflush=False, bind=connection)()
|
|
||||||
|
|
||||||
# Begin a nested transaction
|
|
||||||
nested = connection.begin_nested()
|
|
||||||
|
|
||||||
@event.listens_for(session, "after_transaction_end")
|
|
||||||
def end_savepoint(session, transaction):
|
|
||||||
"""Rollback to the savepoint after each test."""
|
|
||||||
nonlocal nested
|
|
||||||
if not nested.is_active:
|
|
||||||
nested = connection.begin_nested()
|
|
||||||
|
|
||||||
yield session
|
|
||||||
|
|
||||||
# Rollback all changes
|
|
||||||
session.close()
|
|
||||||
transaction.rollback()
|
|
||||||
connection.close()
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def test_redis():
|
|
||||||
"""Create a test Redis client."""
|
|
||||||
client = redis.Redis.from_url("redis://localhost:6379/1", decode_responses=True)
|
|
||||||
# Clear test database
|
|
||||||
client.flushdb()
|
|
||||||
yield client
|
|
||||||
client.flushdb()
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def coordinator_client(db_session):
|
|
||||||
"""Create a test client for the coordinator API."""
|
|
||||||
def override_get_db():
|
|
||||||
yield db_session
|
|
||||||
|
|
||||||
coordinator_app.dependency_overrides[get_db] = override_get_db
|
|
||||||
with TestClient(coordinator_app) as client:
|
|
||||||
yield client
|
|
||||||
coordinator_app.dependency_overrides.clear()
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def wallet_client():
|
|
||||||
"""Create a test client for the wallet daemon."""
|
|
||||||
with TestClient(wallet_app) as client:
|
|
||||||
yield client
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def sample_tenant(db_session):
|
|
||||||
"""Create a sample tenant for testing."""
|
|
||||||
tenant = Tenant(
|
|
||||||
id="test-tenant-123",
|
|
||||||
name="Test Tenant",
|
|
||||||
status="active",
|
|
||||||
created_at=datetime.utcnow(),
|
|
||||||
updated_at=datetime.utcnow(),
|
|
||||||
)
|
|
||||||
db_session.add(tenant)
|
|
||||||
db_session.commit()
|
|
||||||
return tenant
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def sample_tenant_user(db_session, sample_tenant):
|
|
||||||
"""Create a sample tenant user for testing."""
|
|
||||||
user = TenantUser(
|
|
||||||
tenant_id=sample_tenant.id,
|
|
||||||
user_id="test-user-456",
|
|
||||||
role="admin",
|
|
||||||
created_at=datetime.utcnow(),
|
|
||||||
)
|
|
||||||
db_session.add(user)
|
|
||||||
db_session.commit()
|
|
||||||
return user
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def sample_tenant_quota(db_session, sample_tenant):
|
|
||||||
"""Create sample tenant quota for testing."""
|
|
||||||
quota = TenantQuota(
|
|
||||||
tenant_id=sample_tenant.id,
|
|
||||||
resource_type="api_calls",
|
|
||||||
limit=10000,
|
|
||||||
used=0,
|
|
||||||
period="monthly",
|
|
||||||
created_at=datetime.utcnow(),
|
|
||||||
updated_at=datetime.utcnow(),
|
|
||||||
)
|
|
||||||
db_session.add(quota)
|
|
||||||
db_session.commit()
|
|
||||||
return quota
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def sample_job_data():
|
|
||||||
"""Sample job data for testing."""
|
|
||||||
return {
|
|
||||||
"job_type": "ai_inference",
|
|
||||||
"parameters": {
|
|
||||||
"model": "gpt-3.5-turbo",
|
|
||||||
"prompt": "Test prompt",
|
|
||||||
"max_tokens": 100,
|
|
||||||
},
|
|
||||||
"requirements": {
|
|
||||||
"gpu_memory": "8GB",
|
|
||||||
"compute_time": 30,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def sample_receipt_data():
|
|
||||||
"""Sample receipt data for testing."""
|
|
||||||
return {
|
|
||||||
"job_id": "test-job-123",
|
|
||||||
"miner_id": "test-miner-456",
|
|
||||||
"coordinator_id": "test-coordinator-789",
|
|
||||||
"timestamp": datetime.utcnow().isoformat(),
|
|
||||||
"result": {
|
|
||||||
"output": "Test output",
|
|
||||||
"confidence": 0.95,
|
|
||||||
"tokens_used": 50,
|
|
||||||
},
|
|
||||||
"signature": "test-signature",
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def test_keypair():
|
|
||||||
"""Generate a test Ed25519 keypair for signing."""
|
|
||||||
private_key = ed25519.Ed25519PrivateKey.generate()
|
|
||||||
public_key = private_key.public_key()
|
|
||||||
return private_key, public_key
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def signed_receipt(sample_receipt_data, test_keypair):
|
|
||||||
"""Create a signed receipt for testing."""
|
|
||||||
private_key, public_key = test_keypair
|
|
||||||
|
|
||||||
# Serialize receipt without signature
|
|
||||||
receipt_copy = sample_receipt_data.copy()
|
|
||||||
receipt_copy.pop("signature", None)
|
|
||||||
receipt_json = json.dumps(receipt_copy, sort_keys=True, separators=(',', ':'))
|
|
||||||
|
|
||||||
# Sign the receipt
|
|
||||||
signature = private_key.sign(receipt_json.encode())
|
|
||||||
|
|
||||||
# Add signature to receipt
|
|
||||||
receipt_copy["signature"] = signature.hex()
|
|
||||||
receipt_copy["public_key"] = public_key.public_bytes(
|
|
||||||
encoding=serialization.Encoding.Raw,
|
|
||||||
format=serialization.PublicFormat.Raw
|
|
||||||
).hex()
|
|
||||||
|
|
||||||
return receipt_copy
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def aitbc_client(test_config):
|
|
||||||
"""Create an AITBC client for testing."""
|
|
||||||
return AITBCClient(
|
|
||||||
base_url=test_config["coordinator_url"],
|
|
||||||
api_key=test_config["test_api_key"],
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def mock_miner_service():
|
|
||||||
"""Mock miner service for testing."""
|
|
||||||
service = AsyncMock()
|
|
||||||
service.register_miner = AsyncMock(return_value={"miner_id": "test-miner-456"})
|
|
||||||
service.heartbeat = AsyncMock(return_value={"status": "active"})
|
|
||||||
service.fetch_jobs = AsyncMock(return_value=[])
|
|
||||||
service.submit_result = AsyncMock(return_value={"job_id": "test-job-123"})
|
|
||||||
return service
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def mock_blockchain_node():
|
|
||||||
"""Mock blockchain node for testing."""
|
|
||||||
node = AsyncMock()
|
|
||||||
node.get_block = AsyncMock(return_value={"number": 100, "hash": "0x123"})
|
|
||||||
node.get_transaction = AsyncMock(return_value={"hash": "0x456", "status": "confirmed"})
|
|
||||||
node.submit_transaction = AsyncMock(return_value={"hash": "0x789", "status": "pending"})
|
|
||||||
node.subscribe_blocks = AsyncMock()
|
|
||||||
node.subscribe_transactions = AsyncMock()
|
|
||||||
return node
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def sample_gpu_service():
|
|
||||||
"""Sample GPU service definition."""
|
|
||||||
return {
|
|
||||||
"id": "llm-inference",
|
|
||||||
"name": "LLM Inference Service",
|
|
||||||
"category": "ai_ml",
|
|
||||||
"description": "Large language model inference",
|
|
||||||
"requirements": {
|
|
||||||
"gpu_memory": "16GB",
|
|
||||||
"cuda_version": "11.8",
|
|
||||||
"driver_version": "520.61.05",
|
|
||||||
},
|
|
||||||
"pricing": {
|
|
||||||
"per_hour": 0.50,
|
|
||||||
"per_token": 0.0001,
|
|
||||||
},
|
|
||||||
"capabilities": [
|
|
||||||
"text-generation",
|
|
||||||
"chat-completion",
|
|
||||||
"embedding",
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def sample_cross_chain_data():
|
|
||||||
"""Sample cross-chain settlement data."""
|
|
||||||
return {
|
|
||||||
"source_chain": "ethereum",
|
|
||||||
"target_chain": "polygon",
|
|
||||||
"source_tx_hash": "0xabcdef123456",
|
|
||||||
"target_address": "0x1234567890ab",
|
|
||||||
"amount": "1000",
|
|
||||||
"token": "USDC",
|
|
||||||
"bridge_id": "layerzero",
|
|
||||||
"nonce": 12345,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def confidential_transaction_data():
|
|
||||||
"""Sample confidential transaction data."""
|
|
||||||
return {
|
|
||||||
"sender": "0x1234567890abcdef",
|
|
||||||
"receiver": "0xfedcba0987654321",
|
|
||||||
"amount": 1000,
|
|
||||||
"asset": "AITBC",
|
|
||||||
"confidential": True,
|
|
||||||
"ciphertext": "encrypted_data_here",
|
|
||||||
"viewing_key": "viewing_key_here",
|
|
||||||
"proof": "zk_proof_here",
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def mock_hsm_client():
|
|
||||||
"""Mock HSM client for testing."""
|
|
||||||
client = AsyncMock()
|
|
||||||
client.generate_key = AsyncMock(return_value={"key_id": "test-key-123"})
|
|
||||||
client.sign_data = AsyncMock(return_value={"signature": "test-signature"})
|
|
||||||
client.verify_signature = AsyncMock(return_value={"valid": True})
|
|
||||||
client.encrypt_data = AsyncMock(return_value={"ciphertext": "encrypted_data"})
|
|
||||||
client.decrypt_data = AsyncMock(return_value={"plaintext": "decrypted_data"})
|
|
||||||
return client
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def temp_directory():
|
|
||||||
"""Create a temporary directory for testing."""
|
|
||||||
with tempfile.TemporaryDirectory() as temp_dir:
|
|
||||||
yield temp_dir
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def sample_config_file(temp_directory):
|
|
||||||
"""Create a sample configuration file."""
|
|
||||||
config = {
|
|
||||||
"coordinator": {
|
|
||||||
"host": "localhost",
|
|
||||||
"port": 8001,
|
|
||||||
"database_url": "sqlite:///test.db",
|
|
||||||
},
|
|
||||||
"blockchain": {
|
|
||||||
"host": "localhost",
|
|
||||||
"port": 8545,
|
|
||||||
"chain_id": 1337,
|
|
||||||
},
|
|
||||||
"wallet": {
|
|
||||||
"host": "localhost",
|
|
||||||
"port": 8002,
|
|
||||||
"keystore_path": temp_directory,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
config_path = temp_directory / "config.json"
|
|
||||||
with open(config_path, "w") as f:
|
|
||||||
json.dump(config, f)
|
|
||||||
|
|
||||||
return config_path
|
|
||||||
|
|
||||||
|
|
||||||
# Async fixtures
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
async def async_aitbc_client(test_config):
|
|
||||||
"""Create an async AITBC client for testing."""
|
|
||||||
client = AITBCClient(
|
|
||||||
base_url=test_config["coordinator_url"],
|
|
||||||
api_key=test_config["test_api_key"],
|
|
||||||
)
|
|
||||||
yield client
|
|
||||||
await client.close()
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
async def websocket_client():
|
|
||||||
"""Create a WebSocket client for testing."""
|
|
||||||
import websockets
|
|
||||||
|
|
||||||
uri = "ws://localhost:8546"
|
|
||||||
async with websockets.connect(uri) as websocket:
|
|
||||||
yield websocket
|
|
||||||
|
|
||||||
|
|
||||||
# Performance testing fixtures
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def performance_config():
|
|
||||||
"""Configuration for performance tests."""
|
|
||||||
return {
|
|
||||||
"concurrent_users": 100,
|
|
||||||
"ramp_up_time": 30, # seconds
|
|
||||||
"test_duration": 300, # seconds
|
|
||||||
"think_time": 1, # seconds
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# Security testing fixtures
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def malicious_payloads():
|
|
||||||
"""Collection of malicious payloads for security testing."""
|
|
||||||
return {
|
|
||||||
"sql_injection": "'; DROP TABLE jobs; --",
|
|
||||||
"xss": "<script>alert('xss')</script>",
|
|
||||||
"path_traversal": "../../../etc/passwd",
|
|
||||||
"overflow": "A" * 10000,
|
|
||||||
"unicode": "\ufeff\u200b\u200c\u200d",
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def rate_limit_config():
|
|
||||||
"""Rate limiting configuration for testing."""
|
|
||||||
return {
|
|
||||||
"requests_per_minute": 60,
|
|
||||||
"burst_size": 10,
|
|
||||||
"window_size": 60,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# Helper functions
|
|
||||||
|
|
||||||
def create_test_job(job_id: str = None, **kwargs) -> Dict[str, Any]:
|
|
||||||
"""Create a test job with default values."""
|
|
||||||
return {
|
|
||||||
"id": job_id or f"test-job-{datetime.utcnow().timestamp()}",
|
|
||||||
"status": "pending",
|
|
||||||
"created_at": datetime.utcnow().isoformat(),
|
|
||||||
"updated_at": datetime.utcnow().isoformat(),
|
|
||||||
"job_type": kwargs.get("job_type", "ai_inference"),
|
|
||||||
"parameters": kwargs.get("parameters", {}),
|
|
||||||
"requirements": kwargs.get("requirements", {}),
|
|
||||||
"tenant_id": kwargs.get("tenant_id", "test-tenant-123"),
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def create_test_receipt(job_id: str = None, **kwargs) -> Dict[str, Any]:
|
|
||||||
"""Create a test receipt with default values."""
|
|
||||||
return {
|
|
||||||
"id": f"receipt-{job_id or 'test'}",
|
|
||||||
"job_id": job_id or "test-job-123",
|
|
||||||
"miner_id": kwargs.get("miner_id", "test-miner-456"),
|
|
||||||
"coordinator_id": kwargs.get("coordinator_id", "test-coordinator-789"),
|
|
||||||
"timestamp": kwargs.get("timestamp", datetime.utcnow().isoformat()),
|
|
||||||
"result": kwargs.get("result", {"output": "test"}),
|
|
||||||
"signature": kwargs.get("signature", "test-signature"),
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def assert_valid_receipt(receipt: Dict[str, Any]):
|
|
||||||
"""Assert that a receipt has valid structure."""
|
|
||||||
required_fields = ["id", "job_id", "miner_id", "coordinator_id", "timestamp", "result", "signature"]
|
|
||||||
for field in required_fields:
|
|
||||||
assert field in receipt, f"Receipt missing required field: {field}"
|
|
||||||
|
|
||||||
# Validate timestamp format
|
|
||||||
assert isinstance(receipt["timestamp"], str), "Timestamp should be a string"
|
|
||||||
|
|
||||||
# Validate result structure
|
|
||||||
assert isinstance(receipt["result"], dict), "Result should be a dictionary"
|
|
||||||
|
|
||||||
|
|
||||||
# Marks for different test types
|
|
||||||
pytest.mark.unit = pytest.mark.unit
|
|
||||||
pytest.mark.integration = pytest.mark.integration
|
|
||||||
pytest.mark.e2e = pytest.mark.e2e
|
|
||||||
pytest.mark.performance = pytest.mark.performance
|
|
||||||
pytest.mark.security = pytest.mark.security
|
|
||||||
pytest.mark.slow = pytest.mark.slow
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
"""Configure Python path for pytest discovery"""
|
|
||||||
|
|
||||||
import sys
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
# Add project root to sys.path
|
|
||||||
project_root = Path(__file__).parent.parent
|
|
||||||
sys.path.insert(0, str(project_root))
|
|
||||||
|
|
||||||
# Add package source directories
|
|
||||||
sys.path.insert(0, str(project_root / "packages" / "py" / "aitbc-core" / "src"))
|
|
||||||
sys.path.insert(0, str(project_root / "packages" / "py" / "aitbc-crypto" / "src"))
|
|
||||||
sys.path.insert(0, str(project_root / "packages" / "py" / "aitbc-p2p" / "src"))
|
|
||||||
sys.path.insert(0, str(project_root / "packages" / "py" / "aitbc-sdk" / "src"))
|
|
||||||
|
|
||||||
# Add app source directories
|
|
||||||
sys.path.insert(0, str(project_root / "apps" / "coordinator-api" / "src"))
|
|
||||||
sys.path.insert(0, str(project_root / "apps" / "wallet-daemon" / "src"))
|
|
||||||
sys.path.insert(0, str(project_root / "apps" / "blockchain-node" / "src"))
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
[tool:pytest]
|
|
||||||
# Simple pytest configuration for test discovery
|
|
||||||
|
|
||||||
# Test discovery patterns
|
|
||||||
python_files = test_*.py *_test.py
|
|
||||||
python_classes = Test*
|
|
||||||
python_functions = test_*
|
|
||||||
|
|
||||||
# Minimal options for discovery
|
|
||||||
addopts = --collect-only
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
"""Test file to verify pytest discovery is working"""
|
|
||||||
|
|
||||||
def test_pytest_discovery():
|
|
||||||
"""Simple test to verify pytest can discover test files"""
|
|
||||||
assert True
|
|
||||||
|
|
||||||
def test_another_discovery_test():
|
|
||||||
"""Another test to verify multiple tests are discovered"""
|
|
||||||
assert 1 + 1 == 2
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
"""
|
|
||||||
Test file to verify Windsorf test integration is working
|
|
||||||
"""
|
|
||||||
|
|
||||||
import pytest
|
|
||||||
|
|
||||||
|
|
||||||
def test_pytest_discovery():
|
|
||||||
"""Simple test to verify pytest can discover this file"""
|
|
||||||
assert True
|
|
||||||
|
|
||||||
|
|
||||||
def test_windsurf_integration():
|
|
||||||
"""Test that Windsurf test runner is working"""
|
|
||||||
assert "windsurf" in "windsurf test integration"
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("input,expected", [
|
|
||||||
(1, 2),
|
|
||||||
(2, 4),
|
|
||||||
(3, 6),
|
|
||||||
])
|
|
||||||
def test_multiplication(input, expected):
|
|
||||||
"""Parameterized test example"""
|
|
||||||
result = input * 2
|
|
||||||
assert result == expected
|
|
||||||
Reference in New Issue
Block a user