#![cfg(test)]
use crate::advanced_diagnostics_types::{AdvancedDiagnosticEngine, HealthTrend};
use crate::storage::BufferPoolStats;
use std::time::Duration;
#[test]
fn test_advanced_diagnostic_engine_creation() {
let engine = AdvancedDiagnosticEngine::new();
assert_eq!(engine.historical_buffer.len(), 0);
assert_eq!(engine.query_tracker.recent_queries.len(), 0);
assert_eq!(engine.transaction_tracker.commits, 0);
}
#[test]
fn test_record_snapshot() {
let mut engine = AdvancedDiagnosticEngine::new();
let stats = BufferPoolStats::default();
engine.record_snapshot(0.1, 100.0, 1_000_000, 0, &stats);
assert_eq!(engine.historical_buffer.len(), 1);
for _ in 0..30 {
engine.record_snapshot(0.1, 100.0, 1_000_000, 0, &stats);
}
assert!(engine.historical_buffer.len() <= engine.max_history_size);
}
#[test]
fn test_record_query() {
let mut engine = AdvancedDiagnosticEngine::new();
engine.record_query(
Duration::from_millis(100),
"SELECT_PATTERN".to_string(),
vec!["SPO".to_string()],
);
assert_eq!(engine.query_tracker.recent_queries.len(), 1);
assert_eq!(engine.query_tracker.patterns.len(), 1);
assert_eq!(
engine
.query_tracker
.patterns
.get("SELECT_PATTERN")
.unwrap()
.frequency,
1
);
}
#[test]
fn test_record_cache_hit_miss() {
let mut engine = AdvancedDiagnosticEngine::new();
engine.record_cache_hit(true);
engine.record_cache_hit(true);
engine.record_cache_hit(false);
assert_eq!(engine.query_tracker.cache_hits, 2);
assert_eq!(engine.query_tracker.cache_misses, 1);
}
#[test]
fn test_record_transaction() {
let mut engine = AdvancedDiagnosticEngine::new();
engine.record_transaction(Duration::from_millis(50), true);
engine.record_transaction(Duration::from_millis(75), false);
assert_eq!(engine.transaction_tracker.commits, 1);
assert_eq!(engine.transaction_tracker.aborts, 1);
assert_eq!(engine.transaction_tracker.recent_durations.len(), 2);
}
#[test]
fn test_record_conflict_and_deadlock() {
let mut engine = AdvancedDiagnosticEngine::new();
engine.record_conflict();
engine.record_conflict();
engine.record_deadlock();
assert_eq!(engine.transaction_tracker.conflicts, 2);
assert_eq!(engine.transaction_tracker.deadlocks, 1);
}
#[test]
fn test_record_contention() {
let mut engine = AdvancedDiagnosticEngine::new();
engine.record_contention("SPO_INDEX".to_string(), Duration::from_millis(10));
engine.record_contention("SPO_INDEX".to_string(), Duration::from_millis(20));
let stats = engine
.transaction_tracker
.contention_map
.get("SPO_INDEX")
.unwrap();
assert_eq!(stats.count, 2);
assert_eq!(stats.total_wait_time, Duration::from_millis(30));
}
#[test]
fn test_analyze_query_performance_empty() {
let engine = AdvancedDiagnosticEngine::new();
let analysis = engine.analyze_query_performance().unwrap();
assert_eq!(analysis.total_queries, 0);
assert_eq!(analysis.avg_execution_time, Duration::ZERO);
assert_eq!(analysis.cache_hit_rate, 0.0);
}
#[test]
fn test_analyze_query_performance_with_data() {
let mut engine = AdvancedDiagnosticEngine::new();
for i in 0..10 {
engine.record_query(
Duration::from_millis(100 + i * 10),
"PATTERN_A".to_string(),
vec!["SPO".to_string()],
);
}
engine.record_cache_hit(true);
engine.record_cache_hit(true);
engine.record_cache_hit(false);
let analysis = engine.analyze_query_performance().unwrap();
assert_eq!(analysis.total_queries, 10);
assert!(analysis.avg_execution_time.as_millis() > 0);
assert!((analysis.cache_hit_rate - 0.666).abs() < 0.01);
assert_eq!(analysis.query_patterns.len(), 1);
}
#[test]
fn test_analyze_transaction_patterns_empty() {
let engine = AdvancedDiagnosticEngine::new();
let analysis = engine.analyze_transaction_patterns().unwrap();
assert_eq!(analysis.total_transactions, 0);
assert_eq!(analysis.commit_rate, 0.0);
assert_eq!(analysis.abort_rate, 0.0);
}
#[test]
fn test_analyze_transaction_patterns_with_data() {
let mut engine = AdvancedDiagnosticEngine::new();
engine.record_transaction(Duration::from_millis(50), true);
engine.record_transaction(Duration::from_millis(75), true);
engine.record_transaction(Duration::from_millis(100), false);
engine.record_conflict();
engine.record_contention("SPO_INDEX".to_string(), Duration::from_millis(25));
let analysis = engine.analyze_transaction_patterns().unwrap();
assert_eq!(analysis.total_transactions, 3);
assert!((analysis.commit_rate - 0.666).abs() < 0.01);
assert!((analysis.abort_rate - 0.333).abs() < 0.01);
assert!((analysis.conflict_rate - 0.333).abs() < 0.01);
assert_eq!(analysis.contention_points.len(), 1);
}
#[test]
fn test_health_trend_determination() {
let engine = AdvancedDiagnosticEngine::new();
let latency = vec![0.1, 0.11, 0.1, 0.12, 0.1];
let errors = vec![1.0, 1.0, 1.0, 1.0, 1.0];
assert_eq!(
engine.determine_health_trend(&latency, &errors),
HealthTrend::Stable
);
let latency = vec![0.5, 0.4, 0.3, 0.2, 0.1];
let errors = vec![5.0, 4.0, 3.0, 2.0, 1.0];
assert_eq!(
engine.determine_health_trend(&latency, &errors),
HealthTrend::Improving
);
let latency = vec![0.1, 0.2, 0.3, 0.4, 0.5];
let errors = vec![1.0, 2.0, 4.0, 8.0, 10.0];
assert_eq!(
engine.determine_health_trend(&latency, &errors),
HealthTrend::DegradingRapidly
);
}
#[test]
fn test_generate_report_empty() {
let engine = AdvancedDiagnosticEngine::new();
let report = engine.generate_report(1_000_000, 10_000_000).unwrap();
assert_eq!(report.query_analysis.total_queries, 0);
assert_eq!(report.transaction_analysis.total_transactions, 0);
assert_eq!(report.predictive_health.historical_metrics.data_points, 0);
}
#[test]
fn test_generate_report_with_data() {
let mut engine = AdvancedDiagnosticEngine::new();
let stats = BufferPoolStats::default();
engine.record_snapshot(0.1, 100.0, 1_000_000, 0, &stats);
engine.record_query(
Duration::from_millis(100),
"PATTERN_A".to_string(),
vec!["SPO".to_string()],
);
engine.record_transaction(Duration::from_millis(50), true);
let report = engine.generate_report(1_000_000, 10_000_000).unwrap();
assert_eq!(report.query_analysis.total_queries, 1);
assert_eq!(report.transaction_analysis.total_transactions, 1);
assert_eq!(report.predictive_health.historical_metrics.data_points, 1);
}
#[test]
fn test_tuning_recommendations() {
let mut engine = AdvancedDiagnosticEngine::new();
engine.record_cache_hit(false);
engine.record_cache_hit(false);
engine.record_cache_hit(false);
engine.record_cache_hit(true);
let recommendations = engine
.generate_tuning_recommendations(1_000_000, 10_000_000)
.unwrap();
assert!(!recommendations.is_empty());
assert!(recommendations
.iter()
.any(|r| r.parameter == "query_cache_size"));
}
#[test]
fn test_anomaly_detection() {
let mut engine = AdvancedDiagnosticEngine::new();
let stats = BufferPoolStats::default();
for _ in 0..10 {
engine.record_snapshot(0.1, 100.0, 1_000_000, 0, &stats);
}
engine.record_snapshot(50.0, 100.0, 1_000_000, 0, &stats);
let anomalies = engine.detect_anomalies().unwrap();
assert!(!anomalies.is_empty());
assert!(anomalies.iter().any(|a| a.metric == "query_latency"));
}
#[test]
fn test_capacity_forecast() {
let mut engine = AdvancedDiagnosticEngine::new();
let stats = BufferPoolStats::default();
engine.record_snapshot(0.1, 100.0, 1_000_000, 0, &stats);
std::thread::sleep(std::time::Duration::from_millis(10));
engine.record_snapshot(0.1, 100.0, 1_500_000, 0, &stats);
let forecast = engine.forecast_capacity(1_500_000, 10_000_000).unwrap();
assert_eq!(forecast.current_storage_bytes, 1_500_000);
assert!(forecast.growth_rate_per_day > 0.0);
}
#[test]
fn test_fragmentation_analysis() {
let engine = AdvancedDiagnosticEngine::new();
let analysis = engine.analyze_fragmentation(10_000_000).unwrap();
assert!(analysis.overall_fragmentation_pct >= 0.0);
assert!(analysis.compaction_priority >= 0.0 && analysis.compaction_priority <= 1.0);
assert!(!analysis.index_fragmentation.is_empty());
}
#[test]
fn test_index_usage_analysis() {
let engine = AdvancedDiagnosticEngine::new();
let stats = engine.analyze_index_usage().unwrap();
assert!(stats.total_scans > 0);
assert!(!stats.usage_by_index.is_empty());
assert!(stats.usage_by_index.contains_key("SPO"));
assert!(stats.usage_by_index.contains_key("POS"));
assert!(stats.usage_by_index.contains_key("OSP"));
}
#[test]
fn test_predictive_health_empty() {
let engine = AdvancedDiagnosticEngine::new();
let health = engine.predict_health_issues().unwrap();
assert_eq!(health.historical_metrics.data_points, 0);
assert_eq!(health.predicted_issues_24h.len(), 0);
assert_eq!(health.health_trend, HealthTrend::Stable);
}
#[test]
fn test_predictive_health_with_trends() {
let mut engine = AdvancedDiagnosticEngine::new();
let stats = BufferPoolStats::default();
for i in 0..10 {
engine.record_snapshot(
0.1 * (i as f64 + 1.0),
100.0,
1_000_000 + i * 100_000,
i,
&stats,
);
}
let health = engine.predict_health_issues().unwrap();
assert_eq!(health.historical_metrics.data_points, 10);
assert!(!health.predicted_issues_24h.is_empty() || health.health_trend != HealthTrend::Stable);
}