hanzo-runtime-tests 0.1.2

Hanzo AI - Runtime Tests Library
//! Unified runtime testing framework for Hanzo Node
//!
//! Tests all execution environments:
//! - Native Rust
//! - WASM
//! - JavaScript/TypeScript (Deno)
//! - Python
//! - Docker containers
//! - Go plugins
//! - MCP servers

use anyhow::Result;
use serde::{Deserialize, Serialize};
use std::time::{Duration, Instant};
use tokio::sync::mpsc;
use tracing::{info, warn, error};

pub mod native_tests;
pub mod wasm_tests;
pub mod deno_tests;
pub mod python_tests;
pub mod docker_tests;
pub mod unified_tests;

/// Standard test payload for all runtimes
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TestPayload {
    pub operation: String,
    pub input_a: f64,
    pub input_b: f64,
    pub expected: f64,
}

/// Test result with performance metrics
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TestResult {
    pub runtime: String,
    pub success: bool,
    pub result: Option<f64>,
    pub execution_time: Duration,
    pub memory_usage: Option<u64>,
    pub gas_consumed: Option<u64>,
    pub error: Option<String>,
}

/// Runtime test trait - all runtimes must implement this
#[async_trait::async_trait]
pub trait RuntimeTest: Send + Sync {
    /// Get the runtime name
    fn name(&self) -> &str;

    /// Execute a simple computation
    async fn execute_compute(&self, payload: TestPayload) -> Result<TestResult>;

    /// Test file I/O capabilities
    async fn test_file_io(&self, content: Vec<u8>) -> Result<Vec<u8>>;

    /// Test network capabilities
    async fn test_network(&self, url: &str) -> Result<String>;

    /// Test crypto operations
    async fn test_crypto(&self, data: Vec<u8>) -> Result<Vec<u8>>;

    /// Benchmark performance
    async fn benchmark(&self) -> Result<BenchmarkResults>;
}

/// Benchmark results for runtime comparison
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BenchmarkResults {
    pub runtime: String,
    pub ops_per_second: f64,
    pub avg_latency_ms: f64,
    pub p99_latency_ms: f64,
    pub memory_efficiency: f64,
    pub startup_time_ms: f64,
}

/// Unified test orchestrator
pub struct RuntimeOrchestrator {
    runtimes: Vec<Box<dyn RuntimeTest>>,
    results: Vec<TestResult>,
}

impl RuntimeOrchestrator {
    pub fn new() -> Self {
        Self {
            runtimes: vec![],
            results: vec![],
        }
    }

    pub fn add_runtime(&mut self, runtime: Box<dyn RuntimeTest>) {
        self.runtimes.push(runtime);
    }

    /// Run all tests across all runtimes
    pub async fn run_all_tests(&mut self) -> Result<TestReport> {
        info!("Starting unified runtime tests");

        let test_cases = vec![
            TestPayload {
                operation: "add".to_string(),
                input_a: 10.0,
                input_b: 20.0,
                expected: 30.0,
            },
            TestPayload {
                operation: "multiply".to_string(),
                input_a: 5.0,
                input_b: 7.0,
                expected: 35.0,
            },
            TestPayload {
                operation: "fibonacci".to_string(),
                input_a: 10.0,
                input_b: 0.0,
                expected: 55.0,
            },
        ];

        let mut report = TestReport::new();

        for runtime in &self.runtimes {
            info!("Testing runtime: {}", runtime.name());

            for test_case in &test_cases {
                let start = Instant::now();
                match runtime.execute_compute(test_case.clone()).await {
                    Ok(result) => {
                        report.add_result(result);
                    }
                    Err(e) => {
                        error!("Test failed for {}: {}", runtime.name(), e);
                        report.add_result(TestResult {
                            runtime: runtime.name().to_string(),
                            success: false,
                            result: None,
                            execution_time: start.elapsed(),
                            memory_usage: None,
                            gas_consumed: None,
                            error: Some(e.to_string()),
                        });
                    }
                }
            }

            // Run benchmarks
            match runtime.benchmark().await {
                Ok(bench) => report.add_benchmark(bench),
                Err(e) => warn!("Benchmark failed for {}: {}", runtime.name(), e),
            }
        }

        Ok(report)
    }

    /// Compare runtime performance
    pub async fn compare_performance(&self) -> Result<PerformanceComparison> {
        let mut comparison = PerformanceComparison::new();

        for runtime in &self.runtimes {
            let bench = runtime.benchmark().await?;
            comparison.add_runtime_benchmark(bench);
        }

        comparison.analyze();
        Ok(comparison)
    }
}

/// Test report with all results
#[derive(Debug, Serialize, Deserialize)]
pub struct TestReport {
    pub timestamp: chrono::DateTime<chrono::Utc>,
    pub results: Vec<TestResult>,
    pub benchmarks: Vec<BenchmarkResults>,
    pub summary: TestSummary,
}

impl TestReport {
    fn new() -> Self {
        Self {
            timestamp: chrono::Utc::now(),
            results: vec![],
            benchmarks: vec![],
            summary: TestSummary::default(),
        }
    }

    fn add_result(&mut self, result: TestResult) {
        self.results.push(result);
        self.update_summary();
    }

    fn add_benchmark(&mut self, benchmark: BenchmarkResults) {
        self.benchmarks.push(benchmark);
    }

    fn update_summary(&mut self) {
        self.summary.total_tests = self.results.len();
        self.summary.passed = self.results.iter().filter(|r| r.success).count();
        self.summary.failed = self.results.iter().filter(|r| !r.success).count();

        if !self.results.is_empty() {
            self.summary.avg_execution_time = Duration::from_millis(
                (self.results.iter()
                    .map(|r| r.execution_time.as_millis() as u64)
                    .sum::<u64>() / self.results.len() as u64) as u64
            );
        }
    }
}

#[derive(Debug, Default, Serialize, Deserialize)]
pub struct TestSummary {
    pub total_tests: usize,
    pub passed: usize,
    pub failed: usize,
    pub avg_execution_time: Duration,
}

/// Performance comparison across runtimes
#[derive(Debug, Serialize, Deserialize)]
pub struct PerformanceComparison {
    pub runtimes: Vec<BenchmarkResults>,
    pub fastest_runtime: Option<String>,
    pub most_efficient: Option<String>,
    pub recommendations: Vec<String>,
}

impl PerformanceComparison {
    fn new() -> Self {
        Self {
            runtimes: vec![],
            fastest_runtime: None,
            most_efficient: None,
            recommendations: vec![],
        }
    }

    fn add_runtime_benchmark(&mut self, bench: BenchmarkResults) {
        self.runtimes.push(bench);
    }

    fn analyze(&mut self) {
        if let Some(fastest) = self.runtimes.iter()
            .min_by(|a, b| a.avg_latency_ms.partial_cmp(&b.avg_latency_ms).unwrap()) {
            self.fastest_runtime = Some(fastest.runtime.clone());
        }

        if let Some(efficient) = self.runtimes.iter()
            .max_by(|a, b| a.memory_efficiency.partial_cmp(&b.memory_efficiency).unwrap()) {
            self.most_efficient = Some(efficient.runtime.clone());
        }

        // Generate recommendations based on analysis
        self.generate_recommendations();
    }

    fn generate_recommendations(&mut self) {
        // Analyze and provide recommendations
        for runtime in &self.runtimes {
            if runtime.ops_per_second > 10000.0 {
                self.recommendations.push(
                    format!("{} is suitable for high-throughput workloads", runtime.runtime)
                );
            }
            if runtime.avg_latency_ms < 1.0 {
                self.recommendations.push(
                    format!("{} is ideal for low-latency requirements", runtime.runtime)
                );
            }
            if runtime.memory_efficiency > 0.9 {
                self.recommendations.push(
                    format!("{} has excellent memory efficiency", runtime.runtime)
                );
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[tokio::test]
    async fn test_orchestrator_creation() {
        let orchestrator = RuntimeOrchestrator::new();
        assert_eq!(orchestrator.runtimes.len(), 0);
    }

    #[tokio::test]
    async fn test_payload_serialization() {
        let payload = TestPayload {
            operation: "test".to_string(),
            input_a: 1.0,
            input_b: 2.0,
            expected: 3.0,
        };

        let json = serde_json::to_string(&payload).unwrap();
        let decoded: TestPayload = serde_json::from_str(&json).unwrap();

        assert_eq!(decoded.operation, payload.operation);
    }
}