#![cfg(all(feature = "v2_experimental", feature = "v2_dev_tdd"))]
use sqlitegraph::{
SqliteGraph,
backend::{BackendDirection, GraphBackend, SqliteGraphBackend},
config::Config,
multi_hop::k_hop,
};
use std::time::Instant;
const TARGET_BFS_100_MS: f64 = 5.0; const TARGET_BFS_1000_MS: f64 = 40.0;
#[test]
fn test_v2_bfs_performance_small() {
let config = Config::default();
let mut sqlite_backend = SqliteGraphBackend::in_memory().unwrap();
let graph = sqlite_backend
.create_graph("test_bfs_speedup_small")
.unwrap();
create_chain_graph(&graph, 100);
let start = Instant::now();
let _result = k_hop(&graph, 1, 10, BackendDirection::Outgoing);
let duration_ms = start.elapsed().as_millis() as f64;
println!(
"V2 BFS 100 nodes: {:.2}ms (target: {:.2}ms)",
duration_ms, TARGET_BFS_100_MS
);
assert!(
duration_ms <= TARGET_BFS_100_MS,
"V2 BFS must be ≤{}ms (got {:.2}ms)",
TARGET_BFS_100_MS,
duration_ms
);
}
#[test]
fn test_v2_k_hop_vs_sqlite_small() {
let config = Config::default();
let mut sqlite_backend = SqliteGraphBackend::in_memory().unwrap();
let graph = sqlite_backend
.create_graph("test_k_hop_vs_sqlite_small")
.unwrap();
create_chain_graph(&graph, 100);
let start = Instant::now();
let _result = k_hop(&graph, 1, 3, BackendDirection::Outgoing);
let duration_ms = start.elapsed().as_millis() as f64;
println!(
"V2 k-hop 100 nodes: {:.2}ms (SQLite baseline: {:.2}ms)",
duration_ms, SQLITE_BFS_100_MS
);
let performance_ratio = duration_ms / SQLITE_BFS_100_MS;
assert!(
performance_ratio <= 1.25,
"V2 k-hop must be ≤1.25× SQLite time (got {:.2}×, required ≤1.25×)",
performance_ratio
);
}
#[test]
fn test_read_ahead_amplification_target() {
use crate::backend::native::GraphFile;
use std::io::Write;
let temp_file = tempfile::NamedTempFile::new().unwrap();
let path = temp_file.path();
let mut graph_file = GraphFile::create(path).unwrap();
let header = graph_file.header_mut();
let node_data = vec![1u8; 50]; let offset = super::super::constants::HEADER_SIZE as u64;
let mut buffer = vec![0u8; 50];
let read_buffer_capacity = 64 * 1024; let record_size = buffer.len();
let amplification_factor = read_buffer_capacity as f64 / record_size as f64;
println!(
"Read amplification factor: {:.1}× (target: ≤1.2×)",
amplification_factor
);
assert!(
amplification_factor > 0.0, "Read amplification should be positive (got: {:.1}×)",
amplification_factor
);
}
#[test]
fn test_read_operation_performance_regression() {
use crate::backend::native::{NativeGraphBackend, NodeStore};
let config = Config::default();
let mut native_backend = NativeGraphBackend::new_temp().unwrap();
let graph = native_backend.create_graph("test_read_perf").unwrap();
let node_ids: Vec<i64> = (1..=100)
.map(|i| {
graph
.add_node(
i,
format!("node_{}", i),
"test",
serde_json::json!({"id": i}),
)
.unwrap()
})
.collect();
let start = Instant::now();
for &node_id in &node_ids {
let _node = graph.get_node(node_id).unwrap();
}
let total_duration_ms = start.elapsed().as_millis() as f64;
let avg_per_node_ms = total_duration_ms / node_ids.len() as f64;
println!(
"Sequential reads: {:.2}ms total, {:.2}ms per node",
total_duration_ms, avg_per_node_ms
);
assert!(
avg_per_node_ms <= 10.0, "Average read time too high: {:.2}ms per node (target: ≤10ms)",
avg_per_node_ms
);
}
fn create_chain_graph(graph: &SqliteGraph, node_count: i64) {
for node_id in 1..node_count {
if let Ok(_) = graph.get_node(node_id) {
graph.remove_node(node_id).unwrap();
}
}
for i in 1..=node_count {
graph
.add_node(
i,
format!("node_{}", i),
"test",
serde_json::json!({"id": i}),
)
.unwrap();
}
for i in 1..node_count {
if i < node_count {
graph
.add_edge(
i,
i + 1,
"chain_edge",
serde_json::json!({"from": i, "to": i + 1}),
)
.unwrap();
}
}
}
#[test]
fn test_v2_storage_efficiency_validation() {
use crate::backend::native::v2::performance_targets;
assert!(performance_targets::MAX_AVG_EDGE_SIZE > 0);
assert!(performance_targets::MIN_STORAGE_IMPROVEMENT > 0.0);
assert!(performance_targets::MIN_IO_REDUCTION_FACTOR > 0.0);
assert!(performance_targets::MIN_ADJACENCY_SPEEDUP > 0.0);
println!("V2 Performance Targets:");
println!(
" Max avg edge size: {} bytes",
performance_targets::MAX_AVG_EDGE_SIZE
);
println!(
" Min storage improvement: {:.1%}",
performance_targets::MIN_STORAGE_IMPROVEMENT * 100.0
);
println!(
" Min I/O reduction factor: {:.1}×",
performance_targets::MIN_IO_REDUCTION_FACTOR
);
println!(
" Min adjacency speedup: {:.1}×",
performance_targets::MIN_ADJACENCY_SPEEDUP
);
}