Files
aitbc/tests/e2e/test_client_miner_workflow.py
oib 15427c96c0 chore: update file permissions to executable across repository
- Change file mode from 644 to 755 for all project files
- Add chain_id parameter to get_balance RPC endpoint with default "ait-devnet"
- Rename Miner.extra_meta_data to extra_metadata for consistency
2026-03-06 22:17:54 +01:00

633 lines
27 KiB
Python
Executable File

"""
Client-to-Miner End-to-End Workflow Test
Tests complete pipeline from client request to miner processing with enhanced services
"""
import asyncio
import httpx
import pytest
import json
import time
from datetime import datetime, timedelta
from typing import Dict, Any, List, Optional
from unittest.mock import AsyncMock, patch
# Service endpoints
COORDINATOR_API = "http://localhost:8000"
ENHANCED_SERVICES = {
"multimodal": "http://localhost:8002",
"gpu_multimodal": "http://localhost:8003",
"modality_optimization": "http://localhost:8004",
"adaptive_learning": "http://localhost:8005",
"marketplace_enhanced": "http://localhost:8006",
"openclaw_enhanced": "http://localhost:8007"
}
class ClientToMinerWorkflowTester:
"""Test framework for client-to-miner workflows"""
def __init__(self):
self.client = httpx.AsyncClient(timeout=30.0)
self.workflow_data = self._generate_workflow_data()
self.job_id = None
self.execution_id = None
def _generate_workflow_data(self) -> Dict[str, Any]:
"""Generate realistic workflow test data"""
return {
"client_request": {
"job_type": "multimodal_analysis",
"input_data": {
"text": "Analyze this product review for sentiment and extract key features.",
"image_url": "https://example.com/product-image.jpg",
"metadata": {
"priority": "high",
"deadline": "2026-02-25T12:00:00Z",
"quality_threshold": 0.9
}
},
"processing_requirements": {
"sentiment_analysis": True,
"feature_extraction": True,
"gpu_acceleration": True,
"optimization_level": "balanced"
}
},
"agent_workflow": {
"workflow_id": "advanced-multimodal-agent",
"steps": [
{
"step_id": "text_processing",
"service": "multimodal",
"operation": "process_text",
"inputs": {"text": "{{input_data.text}}"},
"expected_duration": 0.02
},
{
"step_id": "image_processing",
"service": "gpu_multimodal",
"operation": "process_image",
"inputs": {"image_url": "{{input_data.image_url}}"},
"expected_duration": 0.15
},
{
"step_id": "data_optimization",
"service": "modality_optimization",
"operation": "optimize_multimodal",
"inputs": {"multimodal_data": "{{previous_results}}"},
"expected_duration": 0.05
},
{
"step_id": "adaptive_analysis",
"service": "adaptive_learning",
"operation": "analyze_with_learning",
"inputs": {"optimized_data": "{{previous_results}}"},
"expected_duration": 0.12
}
],
"verification_level": "full",
"max_execution_time": 60,
"max_cost_budget": 1.0
}
}
async def setup_test_environment(self) -> bool:
"""Setup test environment and verify all services"""
print("🔧 Setting up client-to-miner test environment...")
# Check coordinator API
try:
response = await self.client.get(f"{COORDINATOR_API}/v1/health")
if response.status_code != 200:
print("❌ Coordinator API not healthy")
return False
print("✅ Coordinator API is healthy")
except Exception as e:
print(f"❌ Coordinator API unavailable: {e}")
return False
# Check enhanced services
healthy_services = []
for service_name, service_url in ENHANCED_SERVICES.items():
try:
response = await self.client.get(f"{service_url}/health")
if response.status_code == 200:
healthy_services.append(service_name)
print(f"{service_name} is healthy")
else:
print(f"{service_name} is unhealthy: {response.status_code}")
except Exception as e:
print(f"{service_name} is unavailable: {e}")
if len(healthy_services) < 4: # At least 4 services needed for workflow
print(f"⚠️ Only {len(healthy_services)}/{len(ENHANCED_SERVICES)} services healthy")
return False
print("✅ Test environment ready")
return True
async def cleanup_test_environment(self):
"""Cleanup test environment"""
print("🧹 Cleaning up test environment...")
await self.client.aclose()
async def submit_client_request(self) -> Dict[str, Any]:
"""Step 1: Submit client request to coordinator"""
print("\n📤 Step 1: Submitting client request...")
try:
# Submit job to coordinator
response = await self.client.post(
f"{COORDINATOR_API}/v1/jobs",
json=self.workflow_data["client_request"]
)
if response.status_code == 200:
job_result = response.json()
self.job_id = job_result.get("job_id")
print(f"✅ Job submitted: {self.job_id}")
return {
"status": "success",
"job_id": self.job_id,
"estimated_cost": job_result.get("estimated_cost", "unknown"),
"estimated_duration": job_result.get("estimated_duration", "unknown")
}
else:
print(f"❌ Job submission failed: {response.status_code}")
return {"status": "failed", "error": str(response.status_code)}
except Exception as e:
print(f"❌ Job submission error: {e}")
return {"status": "failed", "error": str(e)}
async def create_agent_workflow(self) -> Dict[str, Any]:
"""Step 2: Create agent workflow for processing"""
print("\n🤖 Step 2: Creating agent workflow...")
try:
# Create workflow via agent service
response = await self.client.post(
f"{ENHANCED_SERVICES['multimodal']}/workflows/create",
json=self.workflow_data["agent_workflow"]
)
if response.status_code == 200:
workflow_result = response.json()
workflow_id = workflow_result.get("workflow_id")
print(f"✅ Agent workflow created: {workflow_id}")
return {
"status": "success",
"workflow_id": workflow_id,
"total_steps": len(self.workflow_data["agent_workflow"]["steps"])
}
else:
print(f"❌ Workflow creation failed: {response.status_code}")
return {"status": "failed", "error": str(response.status_code)}
except Exception as e:
print(f"❌ Workflow creation error: {e}")
return {"status": "failed", "error": str(e)}
async def execute_agent_workflow(self, workflow_id: str) -> Dict[str, Any]:
"""Step 3: Execute agent workflow"""
print("\n⚡ Step 3: Executing agent workflow...")
try:
# Execute workflow
response = await self.client.post(
f"{ENHANCED_SERVICES['multimodal']}/workflows/{workflow_id}/execute",
json={
"inputs": self.workflow_data["client_request"]["input_data"],
"verification_level": "full"
}
)
if response.status_code == 200:
execution_result = response.json()
self.execution_id = execution_result.get("execution_id")
print(f"✅ Workflow execution started: {self.execution_id}")
return {
"status": "success",
"execution_id": self.execution_id,
"estimated_completion": execution_result.get("estimated_completion", "unknown")
}
else:
print(f"❌ Workflow execution failed: {response.status_code}")
return {"status": "failed", "error": str(response.status_code)}
except Exception as e:
print(f"❌ Workflow execution error: {e}")
return {"status": "failed", "error": str(e)}
async def monitor_workflow_execution(self) -> Dict[str, Any]:
"""Step 4: Monitor workflow execution progress"""
print("\n📊 Step 4: Monitoring workflow execution...")
if not self.execution_id:
return {"status": "failed", "error": "No execution ID"}
try:
# Monitor execution with timeout
max_wait_time = 30.0
start_time = time.time()
while time.time() - start_time < max_wait_time:
response = await self.client.get(
f"{ENHANCED_SERVICES['multimodal']}/executions/{self.execution_id}/status"
)
if response.status_code == 200:
status_result = response.json()
current_status = status_result.get("status", "unknown")
current_step = status_result.get("current_step", 0)
total_steps = status_result.get("total_steps", 4)
print(f" 📈 Progress: {current_step}/{total_steps} steps, Status: {current_status}")
if current_status in ["completed", "failed"]:
break
await asyncio.sleep(1.0)
# Get final status
final_response = await self.client.get(
f"{ENHANCED_SERVICES['multimodal']}/executions/{self.execution_id}/status"
)
if final_response.status_code == 200:
final_result = final_response.json()
final_status = final_result.get("status", "unknown")
if final_status == "completed":
print(f"✅ Workflow completed successfully")
return {
"status": "success",
"final_status": final_status,
"total_steps": final_result.get("total_steps", 4),
"execution_time": final_result.get("execution_time", "unknown"),
"final_result": final_result.get("final_result", {})
}
else:
print(f"❌ Workflow failed: {final_status}")
return {
"status": "failed",
"final_status": final_status,
"error": final_result.get("error", "Unknown error")
}
else:
print(f"❌ Failed to get final status: {final_response.status_code}")
return {"status": "failed", "error": "Status check failed"}
except Exception as e:
print(f"❌ Monitoring error: {e}")
return {"status": "failed", "error": str(e)}
async def verify_execution_receipt(self) -> Dict[str, Any]:
"""Step 5: Verify execution receipt"""
print("\n🔍 Step 5: Verifying execution receipt...")
if not self.execution_id:
return {"status": "failed", "error": "No execution ID"}
try:
# Get execution receipt
response = await self.client.get(
f"{ENHANCED_SERVICES['multimodal']}/executions/{self.execution_id}/receipt"
)
if response.status_code == 200:
receipt_result = response.json()
# Verify receipt components
receipt_components = {
"execution_id": receipt_result.get("execution_id"),
"workflow_id": receipt_result.get("workflow_id"),
"timestamp": receipt_result.get("timestamp"),
"results_hash": receipt_result.get("results_hash"),
"verification_proof": receipt_result.get("verification_proof"),
"cost_breakdown": receipt_result.get("cost_breakdown")
}
# Check if all components are present
missing_components = [k for k, v in receipt_components.items() if not v]
if not missing_components:
print(f"✅ Execution receipt verified")
return {
"status": "success",
"receipt_components": receipt_components,
"total_cost": receipt_result.get("total_cost", "unknown"),
"verification_level": receipt_result.get("verification_level", "unknown")
}
else:
print(f"⚠️ Receipt missing components: {missing_components}")
return {
"status": "partial",
"missing_components": missing_components,
"receipt_components": receipt_components
}
else:
print(f"❌ Receipt retrieval failed: {response.status_code}")
return {"status": "failed", "error": str(response.status_code)}
except Exception as e:
print(f"❌ Receipt verification error: {e}")
return {"status": "failed", "error": str(e)}
async def submit_to_marketplace(self) -> Dict[str, Any]:
"""Step 6: Submit successful workflow to marketplace"""
print("\n🏪 Step 6: Submitting to marketplace...")
if not self.execution_id:
return {"status": "failed", "error": "No execution ID"}
try:
# Create marketplace listing for the successful workflow
response = await self.client.post(
f"{ENHANCED_SERVICES['marketplace_enhanced']}/v1/models/mint",
json={
"title": "Multi-Modal Analysis Agent",
"description": "Advanced multi-modal agent with sentiment analysis and feature extraction",
"model_type": "agent_workflow",
"workflow_id": self.execution_id,
"capabilities": [
"sentiment_analysis",
"feature_extraction",
"gpu_acceleration",
"adaptive_optimization"
],
"performance_metrics": {
"accuracy": 0.94,
"processing_time": 0.08,
"cost_efficiency": 0.85
},
"pricing": {
"execution_price": 0.15,
"subscription_price": 25.0
},
"royalties": {
"creator_percentage": 12.0,
"platform_percentage": 5.0
}
}
)
if response.status_code == 200:
marketplace_result = response.json()
print(f"✅ Submitted to marketplace: {marketplace_result.get('model_id')}")
return {
"status": "success",
"model_id": marketplace_result.get("model_id"),
"token_id": marketplace_result.get("token_id"),
"listing_price": marketplace_result.get("pricing", {}).get("execution_price", "unknown")
}
else:
print(f"❌ Marketplace submission failed: {response.status_code}")
return {"status": "failed", "error": str(response.status_code)}
except Exception as e:
print(f"❌ Marketplace submission error: {e}")
return {"status": "failed", "error": str(e)}
async def run_complete_workflow(self) -> Dict[str, Any]:
"""Run complete client-to-miner workflow"""
print("🚀 Starting Complete Client-to-Miner Workflow")
print("="*60)
workflow_start = time.time()
results = {}
# Step 1: Submit client request
results["client_request"] = await self.submit_client_request()
if results["client_request"]["status"] != "success":
return {"overall_status": "failed", "failed_at": "client_request", "results": results}
# Step 2: Create agent workflow
results["workflow_creation"] = await self.create_agent_workflow()
if results["workflow_creation"]["status"] != "success":
return {"overall_status": "failed", "failed_at": "workflow_creation", "results": results}
# Step 3: Execute workflow
results["workflow_execution"] = await self.execute_agent_workflow(
results["workflow_creation"]["workflow_id"]
)
if results["workflow_execution"]["status"] != "success":
return {"overall_status": "failed", "failed_at": "workflow_execution", "results": results}
# Step 4: Monitor execution
results["execution_monitoring"] = await self.monitor_workflow_execution()
if results["execution_monitoring"]["status"] != "success":
return {"overall_status": "failed", "failed_at": "execution_monitoring", "results": results}
# Step 5: Verify receipt
results["receipt_verification"] = await self.verify_execution_receipt()
# Step 6: Submit to marketplace (optional)
if results["execution_monitoring"]["status"] == "success":
results["marketplace_submission"] = await self.submit_to_marketplace()
workflow_duration = time.time() - workflow_start
# Calculate overall success
successful_steps = len([r for r in results.values() if r.get("status") == "success"])
total_steps = len(results)
success_rate = successful_steps / total_steps
print("\n" + "="*60)
print(" WORKFLOW COMPLETION SUMMARY")
print("="*60)
print(f"Total Duration: {workflow_duration:.2f}s")
print(f"Successful Steps: {successful_steps}/{total_steps}")
print(f"Success Rate: {success_rate:.1%}")
print(f"Overall Status: {'✅ SUCCESS' if success_rate >= 0.8 else '⚠️ PARTIAL'}")
return {
"overall_status": "success" if success_rate >= 0.8 else "partial_failure",
"workflow_duration": workflow_duration,
"success_rate": success_rate,
"successful_steps": successful_steps,
"total_steps": total_steps,
"results": results
}
# Pytest test functions
@pytest.mark.asyncio
@pytest.mark.e2e
async def test_client_to_miner_complete_workflow():
"""Test complete client-to-miner workflow"""
tester = ClientToMinerWorkflowTester()
try:
# Setup test environment
if not await tester.setup_test_environment():
pytest.skip("Services not available for testing")
# Run complete workflow
result = await tester.run_complete_workflow()
# Assertions
assert result["overall_status"] in ["success", "partial_failure"], f"Workflow failed: {result}"
assert result["workflow_duration"] < 60.0, "Workflow took too long"
assert result["success_rate"] >= 0.6, "Success rate too low"
# Verify critical steps
results = result["results"]
assert results.get("client_request", {}).get("status") == "success", "Client request failed"
assert results.get("workflow_creation", {}).get("status") == "success", "Workflow creation failed"
assert results.get("workflow_execution", {}).get("status") == "success", "Workflow execution failed"
print(f"✅ Client-to-miner workflow: {result['success_rate']:.1%} success rate")
finally:
await tester.cleanup_test_environment()
@pytest.mark.asyncio
@pytest.mark.e2e
async def test_enhanced_services_integration():
"""Test integration of all enhanced services in workflow"""
tester = ClientToMinerWorkflowTester()
try:
# Setup test environment
if not await tester.setup_test_environment():
pytest.skip("Services not available for testing")
print("\n🔗 Testing Enhanced Services Integration...")
# Test service-to-service communication
integration_tests = []
# Test 1: Multi-modal to GPU Multi-modal
print(" 🤖➡️🚀 Testing Multi-modal to GPU Multi-modal...")
try:
response = await tester.client.post(
f"{ENHANCED_SERVICES['multimodal']}/process",
json={
"agent_id": "integration-test",
"inputs": {"text": "Test integration workflow"},
"processing_mode": "gpu_offload"
}
)
if response.status_code == 200:
integration_tests.append({"test": "multimodal_to_gpu", "status": "success"})
print(" ✅ Integration successful")
else:
integration_tests.append({"test": "multimodal_to_gpu", "status": "failed", "error": response.status_code})
print(f" ❌ Integration failed: {response.status_code}")
except Exception as e:
integration_tests.append({"test": "multimodal_to_gpu", "status": "error", "error": str(e)})
print(f" ❌ Integration error: {e}")
# Test 2: Optimization to Marketplace
print(" ⚡➡️🏪 Testing Optimization to Marketplace...")
try:
response = await tester.client.post(
f"{ENHANCED_SERVICES['modality_optimization']}/optimize",
json={
"modality": "text",
"data": {"content": "Test marketplace integration"},
"strategy": "marketplace_ready"
}
)
if response.status_code == 200:
optimized_data = response.json()
# Try to submit optimized data to marketplace
marketplace_response = await tester.client.post(
f"{ENHANCED_SERVICES['marketplace_enhanced']}/v1/offers/create",
json={
"model_id": "integration-test-model",
"offer_type": "sale",
"price": 0.1,
"optimized_data": optimized_data.get("result", {})
}
)
if marketplace_response.status_code == 200:
integration_tests.append({"test": "optimization_to_marketplace", "status": "success"})
print(" ✅ Integration successful")
else:
integration_tests.append({"test": "optimization_to_marketplace", "status": "failed", "error": marketplace_response.status_code})
print(f" ❌ Marketplace integration failed: {marketplace_response.status_code}")
else:
integration_tests.append({"test": "optimization_to_marketplace", "status": "failed", "error": response.status_code})
print(f" ❌ Optimization failed: {response.status_code}")
except Exception as e:
integration_tests.append({"test": "optimization_to_marketplace", "status": "error", "error": str(e)})
print(f" ❌ Integration error: {e}")
# Test 3: Adaptive Learning to OpenClaw
print(" 🧠➡️🌐 Testing Adaptive Learning to OpenClaw...")
try:
# Create learning agent
agent_response = await tester.client.post(
f"{ENHANCED_SERVICES['adaptive_learning']}/create-agent",
json={
"agent_id": "integration-test-agent",
"algorithm": "q_learning",
"config": {"learning_rate": 0.01}
}
)
if agent_response.status_code == 200:
# Deploy to OpenClaw
openclaw_response = await tester.client.post(
f"{ENHANCED_SERVICES['openclaw_enhanced']}/deploy-agent",
json={
"agent_id": "integration-test-agent",
"deployment_config": {"execution_mode": "hybrid"}
}
)
if openclaw_response.status_code == 200:
integration_tests.append({"test": "learning_to_openclaw", "status": "success"})
print(" ✅ Integration successful")
else:
integration_tests.append({"test": "learning_to_openclaw", "status": "failed", "error": openclaw_response.status_code})
print(f" ❌ OpenClaw deployment failed: {openclaw_response.status_code}")
else:
integration_tests.append({"test": "learning_to_openclaw", "status": "failed", "error": agent_response.status_code})
print(f" ❌ Agent creation failed: {agent_response.status_code}")
except Exception as e:
integration_tests.append({"test": "learning_to_openclaw", "status": "error", "error": str(e)})
print(f" ❌ Integration error: {e}")
# Evaluate integration results
successful_integrations = len([t for t in integration_tests if t["status"] == "success"])
total_integrations = len(integration_tests)
integration_rate = successful_integrations / total_integrations
print(f"\n📊 Integration Test Results:")
print(f"Successful: {successful_integrations}/{total_integrations}")
print(f"Integration Rate: {integration_rate:.1%}")
# Assertions
assert integration_rate >= 0.6, "Integration rate too low"
print(f"✅ Enhanced services integration: {integration_rate:.1%} success rate")
finally:
await tester.cleanup_test_environment()
if __name__ == "__main__":
# Run tests manually
async def main():
tester = ClientToMinerWorkflowTester()
try:
if await tester.setup_test_environment():
result = await tester.run_complete_workflow()
print(f"\n🎯 Final Result: {result['overall_status']}")
print(f"📊 Success Rate: {result['success_rate']:.1%}")
print(f"⏱️ Duration: {result['workflow_duration']:.2f}s")
finally:
await tester.cleanup_test_environment()
asyncio.run(main())