use serde::{Deserialize, Serialize};
use std::path::Path;
use crate::error::Result;
use envsubst::substitute;
use serde_json::Value;
use serde::de::DeserializeOwned;
use async_trait::async_trait;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TestConfig {
pub name: String,
pub description: String,
#[serde(default = "default_timeout")]
pub timeout: u64,
#[serde(default = "default_retries")]
pub retries: u32,
pub environment: String,
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct TestResult {
pub name: String,
pub status: String,
pub duration: f64,
pub details: Option<serde_json::Value>,
pub timestamp: String,
}
fn default_timeout() -> u64 {
30
}
fn default_retries() -> u32 {
3
}
#[async_trait]
pub trait TestRunner {
async fn run(&self, config: &(impl serde::Serialize + Send + Sync)) -> Result<TestResult>;
}
pub fn load_config<T: DeserializeOwned>(path: &Path) -> Result<T> {
let content = std::fs::read_to_string(path)?;
let env_vars = std::env::vars().collect::<std::collections::HashMap<_, _>>();
let substituted = substitute(&content, &env_vars)
.map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))?;
let test_type = determine_test_type(path);
let json_value: Value = serde_json::from_str(&substituted)?;
if let Some(test_type) = test_type {
crate::schema::validate_config(&json_value, test_type)?;
}
Ok(serde_json::from_value(json_value)?)
}
fn determine_test_type(path: &Path) -> Option<&'static str> {
let file_name = path.file_name()?.to_str()?;
if file_name.contains("api_collection") {
return Some("api_collection");
} else if file_name.contains("api") {
return Some("api");
} else if file_name.contains("performance_enhanced") {
return Some("performance_enhanced");
} else if file_name.contains("performance") {
return Some("performance");
} else if file_name.contains("security") {
return Some("security");
} else if file_name.contains("web") {
return Some("web");
} else if file_name.contains("data_driven") {
return Some("data_driven");
}
None
}
pub fn save_result(result: &TestResult, output_path: &Path) -> Result<()> {
let content = serde_json::to_string_pretty(result)?;
std::fs::write(output_path, content)?;
Ok(())
}