use std::collections::{HashMap, VecDeque};
use std::thread;
use std::time::SystemTime;
use super::results::IntegrationTestResult;
use super::scenarios::IntegrationTestCase;
pub struct TestExecutionEngine {
pub execution_queue: VecDeque<TestExecutionRequest>,
pub active_executions: HashMap<String, ActiveTestExecution>,
pub execution_history: VecDeque<TestExecutionResult>,
pub resource_monitor: ResourceMonitor,
}
impl TestExecutionEngine {
#[must_use]
pub fn new() -> Self {
Self {
execution_queue: VecDeque::new(),
active_executions: HashMap::new(),
execution_history: VecDeque::new(),
resource_monitor: ResourceMonitor::new(),
}
}
pub fn queue_test(&mut self, request: TestExecutionRequest) -> Result<String, String> {
let id = request.id.clone();
self.execution_queue.push_back(request);
Ok(id)
}
pub fn execute_test(
&mut self,
request: TestExecutionRequest,
) -> Result<TestExecutionResult, String> {
let execution_id = request.id.clone();
let test_case_id = request.test_case.id;
let start_time = SystemTime::now();
let test_result = IntegrationTestResult {
test_case_id: test_case_id.clone(),
timestamp: start_time,
outcome: super::results::TestOutcome::Passed,
performance_metrics: super::results::PerformanceMetrics {
execution_duration: std::time::Duration::from_secs(0),
setup_duration: std::time::Duration::from_secs(0),
cleanup_duration: std::time::Duration::from_secs(0),
peak_memory_usage: 0,
avg_cpu_usage: 0.0,
custom_metrics: HashMap::new(),
},
validation_results: super::results::ValidationResults {
status: super::results::ValidationStatus::Passed,
validations: Vec::new(),
summary: super::results::ValidationSummary {
total: 0,
passed: 0,
failed: 0,
skipped: 0,
},
},
error_info: None,
artifacts: Vec::new(),
};
let end_time = SystemTime::now();
let result = TestExecutionResult {
execution_id,
test_case_id,
status: ExecutionStatus::Success,
start_time,
end_time,
result: test_result,
metadata: HashMap::new(),
};
self.execution_history.push_back(result.clone());
Ok(result)
}
#[must_use]
pub fn get_execution_status(&self, execution_id: &str) -> Option<&ActiveTestExecution> {
self.active_executions.get(execution_id)
}
pub fn cancel_execution(&mut self, execution_id: &str) -> Result<(), String> {
if self.active_executions.remove(execution_id).is_some() {
Ok(())
} else {
Err(format!("Execution {execution_id} not found"))
}
}
#[must_use]
pub const fn get_execution_history(&self) -> &VecDeque<TestExecutionResult> {
&self.execution_history
}
#[must_use]
pub fn queue_size(&self) -> usize {
self.execution_queue.len()
}
#[must_use]
pub fn active_execution_count(&self) -> usize {
self.active_executions.len()
}
pub fn process_next(&mut self) -> Result<Option<TestExecutionResult>, String> {
if let Some(request) = self.execution_queue.pop_front() {
Ok(Some(self.execute_test(request)?))
} else {
Ok(None)
}
}
pub fn clear_history(&mut self) {
self.execution_history.clear();
}
pub fn update_resource_usage(&mut self, usage: ResourceUsage) {
self.resource_monitor.current_usage = usage.clone();
self.resource_monitor
.usage_history
.push_back(ResourceUsageSnapshot {
timestamp: SystemTime::now(),
usage,
active_tests: self.active_executions.len(),
});
while self.resource_monitor.usage_history.len() > 1000 {
self.resource_monitor.usage_history.pop_front();
}
}
#[must_use]
pub const fn has_available_resources(&self, allocation: &ResourceAllocation) -> bool {
let limits = &self.resource_monitor.limits;
let current = &self.resource_monitor.current_usage;
current.memory_usage + allocation.memory_bytes <= limits.max_memory_usage
&& current.disk_usage + allocation.disk_bytes <= limits.max_disk_usage
&& current.thread_count + 1 <= limits.max_threads
}
}
#[derive(Debug, Clone)]
pub struct TestExecutionRequest {
pub id: String,
pub test_case: IntegrationTestCase,
pub priority: super::scenarios::TestPriority,
pub requested_time: SystemTime,
pub context: ExecutionContext,
}
#[derive(Debug, Clone)]
pub struct ExecutionContext {
pub parameters: HashMap<String, String>,
pub environment: HashMap<String, String>,
pub resources: ResourceAllocation,
pub metadata: HashMap<String, String>,
}
#[derive(Debug)]
pub struct ActiveTestExecution {
pub request: TestExecutionRequest,
pub start_time: SystemTime,
pub current_step: usize,
pub thread_handle: Option<thread::JoinHandle<TestExecutionResult>>,
pub progress: ExecutionProgress,
}
#[derive(Debug, Clone)]
pub struct ExecutionProgress {
pub completed_steps: usize,
pub total_steps: usize,
pub percentage: f64,
pub status: TestStatus,
pub estimated_completion: Option<SystemTime>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum TestStatus {
Queued,
Running,
Completed,
Failed,
Cancelled,
Timeout,
}
#[derive(Debug, Clone)]
pub struct TestExecutionResult {
pub execution_id: String,
pub test_case_id: String,
pub status: ExecutionStatus,
pub start_time: SystemTime,
pub end_time: SystemTime,
pub result: IntegrationTestResult,
pub metadata: HashMap<String, String>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ExecutionStatus {
Success,
Failure(String),
Timeout,
Cancelled,
Error(String),
}
#[derive(Debug, Clone)]
pub struct ResourceAllocation {
pub cpu_cores: usize,
pub memory_bytes: usize,
pub disk_bytes: usize,
pub network_bandwidth: Option<usize>,
}
#[derive(Debug)]
pub struct ResourceMonitor {
pub current_usage: ResourceUsage,
pub usage_history: VecDeque<ResourceUsageSnapshot>,
pub limits: ResourceLimits,
pub alert_thresholds: HashMap<String, f64>,
}
impl ResourceMonitor {
#[must_use]
pub fn new() -> Self {
Self {
current_usage: ResourceUsage::default(),
usage_history: VecDeque::new(),
limits: ResourceLimits::default(),
alert_thresholds: HashMap::new(),
}
}
}
#[derive(Debug, Clone)]
pub struct ResourceUsage {
pub cpu_usage: f64,
pub memory_usage: usize,
pub network_usage: f64,
pub disk_usage: usize,
pub thread_count: usize,
}
impl Default for ResourceUsage {
fn default() -> Self {
Self {
cpu_usage: 0.0,
memory_usage: 0,
network_usage: 0.0,
disk_usage: 0,
thread_count: 0,
}
}
}
#[derive(Debug, Clone)]
pub struct ResourceUsageSnapshot {
pub timestamp: SystemTime,
pub usage: ResourceUsage,
pub active_tests: usize,
}
#[derive(Debug, Clone)]
pub struct ResourceLimits {
pub max_cpu_usage: f64,
pub max_memory_usage: usize,
pub max_network_usage: f64,
pub max_disk_usage: usize,
pub max_threads: usize,
}
impl Default for ResourceLimits {
fn default() -> Self {
Self {
max_cpu_usage: 95.0,
max_memory_usage: 8 * 1024 * 1024 * 1024, max_network_usage: 1000.0, max_disk_usage: 100 * 1024 * 1024 * 1024, max_threads: 1000,
}
}
}