use std::collections::{BTreeMap, HashMap};
use std::time::{Duration, SystemTime};
use super::config::TestStorageConfig;
#[derive(Debug, Clone)]
pub struct IntegrationTestResult {
pub test_case_id: String,
pub timestamp: SystemTime,
pub outcome: TestOutcome,
pub performance_metrics: PerformanceMetrics,
pub validation_results: ValidationResults,
pub error_info: Option<ErrorInfo>,
pub artifacts: Vec<TestArtifact>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum TestOutcome {
Passed,
Failed,
Skipped,
Timeout,
Error,
}
#[derive(Debug, Clone)]
pub struct PerformanceMetrics {
pub execution_duration: Duration,
pub setup_duration: Duration,
pub cleanup_duration: Duration,
pub peak_memory_usage: usize,
pub avg_cpu_usage: f64,
pub custom_metrics: HashMap<String, f64>,
}
#[derive(Debug, Clone)]
pub struct ValidationResults {
pub status: ValidationStatus,
pub validations: Vec<IndividualValidation>,
pub summary: ValidationSummary,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ValidationStatus {
Passed,
Failed,
Partial,
NotExecuted,
}
#[derive(Debug, Clone)]
pub struct IndividualValidation {
pub name: String,
pub status: ValidationStatus,
pub expected: String,
pub actual: String,
pub error_message: Option<String>,
}
#[derive(Debug, Clone)]
pub struct ValidationSummary {
pub total: usize,
pub passed: usize,
pub failed: usize,
pub skipped: usize,
}
#[derive(Debug, Clone)]
pub struct ErrorInfo {
pub error_code: String,
pub message: String,
pub category: ErrorCategory,
pub stack_trace: Option<String>,
pub context: HashMap<String, String>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ErrorCategory {
Setup,
Execution,
Validation,
Cleanup,
Infrastructure,
Timeout,
Resource,
Configuration,
Custom(String),
}
#[derive(Debug, Clone)]
pub struct TestArtifact {
pub name: String,
pub artifact_type: ArtifactType,
pub path: String,
pub size: usize,
pub metadata: HashMap<String, String>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ArtifactType {
Log,
Screenshot,
Report,
Data,
Configuration,
Custom(String),
}
#[derive(Debug, Clone)]
pub struct IntegrationValidationResult {
pub component_results: ComponentIntegrationResults,
pub system_results: SystemIntegrationResults,
pub performance_results: PerformanceIntegrationResults,
pub overall_status: ValidationStatus,
}
#[derive(Debug, Clone)]
pub struct ComponentIntegrationResults {
pub components: HashMap<String, ComponentResult>,
pub integration_matrix: Vec<Vec<IntegrationStatus>>,
}
#[derive(Debug, Clone)]
pub struct SystemIntegrationResults {
pub end_to_end_results: Vec<EndToEndResult>,
pub system_health: SystemHealthMetrics,
}
#[derive(Debug, Clone)]
pub struct PerformanceIntegrationResults {
pub benchmarks: HashMap<String, BenchmarkResult>,
pub trends: PerformanceTrends,
pub regressions: Vec<PerformanceRegression>,
}
#[derive(Debug, Clone)]
pub struct ComponentResult {
pub name: String,
pub status: ValidationStatus,
pub metrics: PerformanceMetrics,
pub error_details: Option<ErrorInfo>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum IntegrationStatus {
Compatible,
Incompatible,
Warning,
NotTested,
}
#[derive(Debug, Clone)]
pub struct EndToEndResult {
pub scenario: String,
pub status: ValidationStatus,
pub execution_time: Duration,
pub steps: Vec<StepResult>,
}
#[derive(Debug, Clone)]
pub struct StepResult {
pub name: String,
pub status: ValidationStatus,
pub duration: Duration,
pub output: Option<String>,
}
#[derive(Debug, Clone)]
pub struct SystemHealthMetrics {
pub health_score: f64,
pub component_health: HashMap<String, f64>,
pub resource_utilization: ResourceUtilization,
}
#[derive(Debug, Clone)]
pub struct ResourceUtilization {
pub cpu: f64,
pub memory: f64,
pub disk: f64,
pub network: f64,
}
#[derive(Debug, Clone)]
pub struct BenchmarkResult {
pub name: String,
pub score: f64,
pub baseline_comparison: Option<f64>,
pub metrics: PerformanceMetrics,
}
#[derive(Debug, Clone)]
pub struct PerformanceTrends {
pub execution_time_trend: Vec<(SystemTime, Duration)>,
pub memory_trend: Vec<(SystemTime, usize)>,
pub success_rate_trend: Vec<(SystemTime, f64)>,
}
#[derive(Debug, Clone)]
pub struct PerformanceRegression {
pub metric: String,
pub previous_value: f64,
pub current_value: f64,
pub regression_percentage: f64,
pub severity: RegressionSeverity,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum RegressionSeverity {
Low,
Medium,
High,
Critical,
}
pub struct TestResultStorage {
pub storage_config: TestStorageConfig,
pub result_cache: HashMap<String, super::execution::TestExecutionResult>,
pub result_index: BTreeMap<SystemTime, String>,
pub storage_stats: StorageStatistics,
}
impl TestResultStorage {
#[must_use]
pub fn new(config: TestStorageConfig) -> Self {
Self {
storage_config: config,
result_cache: HashMap::new(),
result_index: BTreeMap::new(),
storage_stats: StorageStatistics::default(),
}
}
pub fn store_result(
&mut self,
result: super::execution::TestExecutionResult,
) -> Result<(), String> {
let id = result.execution_id.clone();
let timestamp = result.start_time;
self.storage_stats.total_results += 1;
self.storage_stats.storage_size += std::mem::size_of_val(&result);
self.result_cache.insert(id.clone(), result);
self.result_index.insert(timestamp, id);
if self.should_cleanup() {
self.cleanup_old_results();
}
Ok(())
}
#[must_use]
pub fn get_result(&self, execution_id: &str) -> Option<&super::execution::TestExecutionResult> {
self.result_cache.get(execution_id)
}
#[must_use]
pub fn get_results_by_time_range(
&self,
start: SystemTime,
end: SystemTime,
) -> Vec<&super::execution::TestExecutionResult> {
self.result_index
.range(start..=end)
.filter_map(|(_, id)| self.result_cache.get(id))
.collect()
}
#[must_use]
pub fn get_recent_results(&self, count: usize) -> Vec<&super::execution::TestExecutionResult> {
self.result_index
.iter()
.rev()
.take(count)
.filter_map(|(_, id)| self.result_cache.get(id))
.collect()
}
#[must_use]
pub fn get_results_for_test_case(
&self,
test_case_id: &str,
) -> Vec<&super::execution::TestExecutionResult> {
self.result_cache
.values()
.filter(|r| r.test_case_id == test_case_id)
.collect()
}
pub fn clear_all(&mut self) {
self.result_cache.clear();
self.result_index.clear();
self.storage_stats = StorageStatistics::default();
}
#[must_use]
pub const fn get_statistics(&self) -> &StorageStatistics {
&self.storage_stats
}
const fn should_cleanup(&self) -> bool {
match &self.storage_config.retention_policy {
super::config::RetentionPolicy::KeepLast(max_results) => {
self.storage_stats.total_results > *max_results
}
super::config::RetentionPolicy::KeepForDuration(_) => {
true
}
super::config::RetentionPolicy::KeepAll => false,
super::config::RetentionPolicy::Custom(_) => false,
}
}
fn cleanup_old_results(&mut self) {
match &self.storage_config.retention_policy {
super::config::RetentionPolicy::KeepLast(max_results) => {
while self.storage_stats.total_results > *max_results {
if let Some((time, id)) = self
.result_index
.iter()
.next()
.map(|(t, i)| (*t, i.clone()))
{
self.result_index.remove(&time);
if let Some(result) = self.result_cache.remove(&id) {
self.storage_stats.total_results =
self.storage_stats.total_results.saturating_sub(1);
self.storage_stats.storage_size = self
.storage_stats
.storage_size
.saturating_sub(std::mem::size_of_val(&result));
}
} else {
break;
}
}
}
super::config::RetentionPolicy::KeepForDuration(duration) => {
let cutoff_time = SystemTime::now()
.checked_sub(*duration)
.unwrap_or(SystemTime::UNIX_EPOCH);
let old_ids: Vec<String> = self
.result_index
.range(..cutoff_time)
.map(|(_, id)| id.clone())
.collect();
for id in old_ids {
if let Some(result) = self.result_cache.remove(&id) {
self.result_index.remove(&result.start_time);
self.storage_stats.total_results =
self.storage_stats.total_results.saturating_sub(1);
self.storage_stats.storage_size = self
.storage_stats
.storage_size
.saturating_sub(std::mem::size_of_val(&result));
}
}
}
_ => {}
}
self.storage_stats.last_cleanup = SystemTime::now();
}
pub const fn export_results(&self, _file_path: &str) -> Result<(), String> {
Ok(())
}
pub const fn import_results(&mut self, _file_path: &str) -> Result<usize, String> {
Ok(0)
}
}
#[derive(Debug, Clone)]
pub struct StorageStatistics {
pub total_results: usize,
pub storage_size: usize,
pub last_cleanup: SystemTime,
pub compression_ratio: f64,
}
impl Default for StorageStatistics {
fn default() -> Self {
Self {
total_results: 0,
storage_size: 0,
last_cleanup: SystemTime::now(),
compression_ratio: 1.0,
}
}
}