use super::*;
use crate::cluster::ClusterRegistry;
use crate::unified_trace::SyscallSpan;
use std::borrow::Cow;
use std::time::Duration;
fn make_span(
name: &'static str,
duration_nanos: u64,
args: Vec<(Cow<'static, str>, String)>,
) -> SyscallSpan {
SyscallSpan {
span_id: 1,
parent_span_id: 0,
name: Cow::Borrowed(name),
args,
return_value: 0,
timestamp_nanos: 0,
duration_nanos,
errno: None,
}
}
#[test]
fn test_transpiler_file_io_dominant() {
let registry = ClusterRegistry::default_transpiler_clusters().expect("test");
let spans = vec![
make_span("open", 1_000_000, vec![]), make_span("read", 50_000_000, vec![]), make_span("write", 18_000_000, vec![]), make_span("close", 1_000_000, vec![]), make_span("mmap", 10_000_000, vec![]), make_span("munmap", 5_000_000, vec![]), make_span("brk", 5_000_000, vec![]), make_span("openat", 5_000_000, vec![]), make_span("mmap", 5_000_000, vec![]), ];
let attributions = calculate_time_attribution(&spans, ®istry);
assert_eq!(attributions[0].cluster, "FileIO");
assert!(
attributions[0].percentage > 60.0,
"FileIO should dominate with >60%, got {}",
attributions[0].percentage
);
let hotspots = identify_hotspots(&attributions);
assert!(hotspots.iter().any(|h| h.cluster == "FileIO"));
assert!(hotspots.iter().any(|h| h.cluster == "MemoryAllocation"));
let file_io_hotspot = hotspots.iter().find(|h| h.cluster == "FileIO").expect("test");
assert!(file_io_hotspot.is_expected);
}
#[test]
fn test_unexpected_networking_hotspot() {
let registry = ClusterRegistry::default_transpiler_clusters().expect("test");
let spans = vec![
make_span("read", 40_000_000, vec![]),
make_span("socket", 10_000_000, vec![]),
make_span("connect", 20_000_000, vec![]),
make_span("send", 30_000_000, vec![]),
];
let attributions = calculate_time_attribution(&spans, ®istry);
let hotspots = identify_hotspots(&attributions);
let networking = hotspots.iter().find(|h| h.cluster == "Networking");
assert!(networking.is_some());
let networking = networking.expect("test");
assert!(!networking.is_expected); assert!(networking.explanation.contains("UNEXPECTED"));
}
#[test]
fn test_unexpected_gpu_hotspot() {
let registry = ClusterRegistry::default_transpiler_clusters().expect("test");
let spans = vec![
make_span("read", 30_000_000, vec![]),
make_span(
"ioctl",
70_000_000,
vec![(Cow::Borrowed("fd_path"), "/dev/nvidia0".to_string())],
),
];
let attributions = calculate_time_attribution(&spans, ®istry);
let hotspots = identify_hotspots(&attributions);
let gpu = hotspots.iter().find(|h| h.cluster == "GPU");
assert!(gpu.is_some());
let gpu = gpu.expect("test");
assert!(!gpu.is_expected);
assert!(gpu.explanation.contains("UNEXPECTED"));
}
#[test]
fn test_blocking_io_dominates_fast_calls() {
let registry = ClusterRegistry::default_transpiler_clusters().expect("test");
let spans = vec![
make_span("mmap", 1, vec![]),
make_span("mmap", 1, vec![]),
make_span("mmap", 1, vec![]),
make_span("read", 99_000_000, vec![]),
];
let attributions = calculate_time_attribution(&spans, ®istry);
let file_io = attributions.iter().find(|a| a.cluster == "FileIO").expect("test");
assert!(file_io.percentage > 99.0);
assert_eq!(file_io.call_count, 1);
}
#[test]
fn test_hotspot_threshold_filtering() {
let registry = ClusterRegistry::default_transpiler_clusters().expect("test");
let spans = vec![
make_span("read", 60_000_000, vec![]), make_span("mmap", 30_000_000, vec![]), make_span("brk", 6_000_000, vec![]), make_span("close", 4_000_000, vec![]), ];
let attributions = calculate_time_attribution(&spans, ®istry);
let hotspots = identify_hotspots(&attributions);
assert_eq!(hotspots.len(), 2);
assert!(hotspots.iter().all(|h| h.percentage > 5.0));
}
#[test]
fn test_empty_trace() {
let registry = ClusterRegistry::default_transpiler_clusters().expect("test");
let spans: Vec<SyscallSpan> = vec![];
let attributions = calculate_time_attribution(&spans, ®istry);
assert!(attributions.is_empty());
let hotspots = identify_hotspots(&attributions);
assert!(hotspots.is_empty());
}
#[test]
fn test_zero_duration_trace() {
let registry = ClusterRegistry::default_transpiler_clusters().expect("test");
let spans = vec![make_span("read", 0, vec![]), make_span("write", 0, vec![])];
let attributions = calculate_time_attribution(&spans, ®istry);
assert!(attributions.is_empty());
let hotspots = identify_hotspots(&attributions);
assert!(hotspots.is_empty());
}
#[test]
fn test_hotspot_report_formatting() {
let hotspot = Hotspot {
cluster: "FileIO".to_string(),
time: Duration::from_secs(1),
percentage: 65.4,
explanation: "File I/O dominates execution".to_string(),
is_expected: true,
};
let report = hotspot.to_report_string();
assert!(report.contains("FileIO"));
assert!(report.contains("65.4%"));
assert!(report.contains("File I/O dominates"));
assert!(report.contains("✓")); }
#[test]
fn test_avg_per_call_accuracy() {
let registry = ClusterRegistry::default_transpiler_clusters().expect("test");
let spans = vec![
make_span("read", 10_000_000, vec![]), make_span("read", 20_000_000, vec![]), make_span("read", 30_000_000, vec![]), ];
let attributions = calculate_time_attribution(&spans, ®istry);
let file_io = attributions.iter().find(|a| a.cluster == "FileIO").expect("test");
assert_eq!(file_io.avg_per_call, Duration::from_millis(20));
}
#[test]
fn test_percentage_accuracy() {
let registry = ClusterRegistry::default_transpiler_clusters().expect("test");
let spans = vec![
make_span("read", 25_000_000, vec![]), make_span("mmap", 75_000_000, vec![]), ];
let attributions = calculate_time_attribution(&spans, ®istry);
let file_io = attributions.iter().find(|a| a.cluster == "FileIO").expect("test");
assert!((file_io.percentage - 25.0).abs() < 0.01);
let mem = attributions.iter().find(|a| a.cluster == "MemoryAllocation").expect("test");
assert!((mem.percentage - 75.0).abs() < 0.01);
}