use sqlitegraph::backend::native::graph_ops::TraversalContext;
use sqlitegraph::backend::native::types::NativeNodeId;
#[test]
fn test_telemetry_json_format_valid() {
let mut ctx = TraversalContext::new();
ctx.record_node_visit();
ctx.record_node_visit();
ctx.record_buffer_hit();
ctx.record_buffer_miss();
let telemetry_json = ctx.export_telemetry();
let telemetry: serde_json::Value =
serde_json::from_str(&telemetry_json).expect("Telemetry JSON should be valid");
assert!(telemetry.get("time_total_ms").is_some());
assert!(telemetry.get("nodes_visited").is_some());
assert!(telemetry.get("cluster_hits").is_some());
assert!(telemetry.get("cluster_misses").is_some());
assert!(telemetry.get("fragmentation_score").is_some());
assert_eq!(telemetry["nodes_visited"], 2);
assert_eq!(telemetry["cluster_hits"], 1);
assert_eq!(telemetry["cluster_misses"], 1);
}
#[test]
fn test_telemetry_chain_detection() {
let mut ctx = TraversalContext::new();
let cluster_size = 4096u64;
for i in 0..10 {
let offset = i * cluster_size;
ctx.detector.observe_with_cluster(
i as NativeNodeId,
1, offset,
cluster_size as u32,
);
}
ctx.detector.record_chain(10);
let telemetry_json = ctx.export_telemetry();
let telemetry: serde_json::Value =
serde_json::from_str(&telemetry_json).expect("Telemetry JSON should be valid");
assert_eq!(telemetry["chains_detected"], 1);
assert_eq!(telemetry["average_chain_length"], 10.0);
assert_eq!(telemetry["fragmentation_score"], 0.0);
}
#[test]
fn test_telemetry_fragmentation_calculation() {
let mut ctx = TraversalContext::new();
ctx.detector.observe_with_cluster(1, 1, 0, 100);
ctx.detector.observe_with_cluster(2, 1, 200, 100); ctx.detector.observe_with_cluster(3, 1, 300, 100);
let telemetry_json = ctx.export_telemetry();
let telemetry: serde_json::Value =
serde_json::from_str(&telemetry_json).expect("Telemetry JSON should be valid");
let fragmentation = telemetry["fragmentation_score"]
.as_f64()
.expect("fragmentation_score should be a number");
assert!(
fragmentation > 0.0,
"Fragmentation should be > 0 for gapped clusters"
);
assert_eq!(telemetry["gap_bytes"], 100);
}
#[test]
fn test_telemetry_timing_fields_populated() {
let mut ctx = TraversalContext::new();
for i in 0i32..10 {
ctx.detector
.observe_with_cluster(i as NativeNodeId, 1, (i * 100) as u64, 100);
}
let _ = ctx.detector.should_use_sequential_read();
let telemetry_json = ctx.export_telemetry();
let telemetry: serde_json::Value =
serde_json::from_str(&telemetry_json).expect("Telemetry JSON should be valid");
let linear_detection_ms = telemetry["linear_detection_ms"]
.as_f64()
.expect("linear_detection_ms should be a number");
assert!(linear_detection_ms >= 0.0);
let contiguity_validation_ms = telemetry["contiguity_validation_ms"]
.as_f64()
.expect("contiguity_validation_ms should be a number");
assert!(contiguity_validation_ms >= 0.0);
}
#[test]
fn test_telemetry_empty_traversal() {
let ctx = TraversalContext::new();
let telemetry_json = ctx.export_telemetry();
let telemetry: serde_json::Value = serde_json::from_str(&telemetry_json)
.expect("Telemetry JSON should be valid even for empty traversal");
assert_eq!(telemetry["nodes_visited"], 0);
assert_eq!(telemetry["cluster_hits"], 0);
assert_eq!(telemetry["cluster_misses"], 0);
assert_eq!(telemetry["chains_detected"], 0);
assert_eq!(telemetry["average_chain_length"], 0.0);
assert_eq!(telemetry["fragmentation_score"], 0.0);
assert_eq!(telemetry["gap_bytes"], 0);
assert_eq!(telemetry["cluster_offsets_count"], 0);
}
#[test]
fn test_telemetry_combined_hit_rate() {
let mut ctx = TraversalContext::new();
ctx.record_buffer_hit();
ctx.record_buffer_hit();
ctx.record_buffer_hit();
ctx.record_buffer_miss();
ctx.stats.hits = 5;
ctx.stats.misses = 2;
let telemetry_json = ctx.export_telemetry();
let telemetry: serde_json::Value =
serde_json::from_str(&telemetry_json).expect("Telemetry JSON should be valid");
let combined_hit_rate = telemetry["combined_hit_rate"]
.as_f64()
.expect("combined_hit_rate should be a number");
assert!((combined_hit_rate - 8.0 / 11.0).abs() < f64::EPSILON);
}
#[test]
fn test_telemetry_cluster_buffer_stats() {
let mut ctx = TraversalContext::new();
ctx.record_overshoot();
ctx.record_undershoot();
ctx.record_undershoot();
ctx.record_buffer_realloc();
let telemetry_json = ctx.export_telemetry();
let telemetry: serde_json::Value =
serde_json::from_str(&telemetry_json).expect("Telemetry JSON should be valid");
assert_eq!(telemetry["overshoot_count"], 1);
assert_eq!(telemetry["undershoot_count"], 2);
assert_eq!(telemetry["cluster_buffer_reallocs"], 1);
}
#[test]
fn test_telemetry_l2_cache_stats() {
let mut ctx = TraversalContext::new();
ctx.stats.hits = 42;
ctx.stats.misses = 13;
let telemetry_json = ctx.export_telemetry();
let telemetry: serde_json::Value =
serde_json::from_str(&telemetry_json).expect("Telemetry JSON should be valid");
assert_eq!(telemetry["l2_cache_hits"], 42);
assert_eq!(telemetry["l2_cache_misses"], 13);
}