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;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TestPayload {
pub operation: String,
pub input_a: f64,
pub input_b: f64,
pub expected: f64,
}
#[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>,
}
#[async_trait::async_trait]
pub trait RuntimeTest: Send + Sync {
fn name(&self) -> &str;
async fn execute_compute(&self, payload: TestPayload) -> Result<TestResult>;
async fn test_file_io(&self, content: Vec<u8>) -> Result<Vec<u8>>;
async fn test_network(&self, url: &str) -> Result<String>;
async fn test_crypto(&self, data: Vec<u8>) -> Result<Vec<u8>>;
async fn benchmark(&self) -> Result<BenchmarkResults>;
}
#[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,
}
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);
}
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()),
});
}
}
}
match runtime.benchmark().await {
Ok(bench) => report.add_benchmark(bench),
Err(e) => warn!("Benchmark failed for {}: {}", runtime.name(), e),
}
}
Ok(report)
}
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)
}
}
#[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,
}
#[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());
}
self.generate_recommendations();
}
fn generate_recommendations(&mut self) {
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);
}
}