use rand::{Rng, SeedableRng};
use sqlitegraph::{EdgeSpec, GraphConfig, NeighborQuery, NodeSpec, SnapshotId, open_graph};
#[test]
fn test_reopen_maintains_graph_integrity() {
let temp_dir = tempfile::tempdir().unwrap();
let db_path = temp_dir.path().join("reopen_test.db");
let seed = 42u64;
println!("=== PHASE 1: Initial graph creation ===");
let graph =
open_graph(&db_path, &GraphConfig::native()).expect("Failed to create V2 native graph");
let mut node_ids = Vec::new();
for i in 1..=300 {
let node_id = graph
.insert_node(NodeSpec {
kind: "TestNode".to_string(),
name: format!("node_{}", i),
file_path: None,
data: serde_json::json!({"id": i, "phase": 1}),
})
.expect(&format!("Failed to insert node {}", i));
node_ids.push(node_id);
}
assert_eq!(node_ids.len(), 300, "Should have created 300 nodes");
println!(
"✅ Created 300 nodes (IDs: {} to {})",
node_ids.first().unwrap(),
node_ids.last().unwrap()
);
let mut rng = rand::rngs::StdRng::seed_from_u64(seed);
let mut edge_count = 0;
while edge_count < 500 {
let from_idx = rng.gen_range(0..node_ids.len());
let to_idx = rng.gen_range(0..node_ids.len());
if from_idx != to_idx {
let from_id = node_ids[from_idx];
let to_id = node_ids[to_idx];
let neighbors = graph
.neighbors(SnapshotId::current(), from_id, NeighborQuery::default())
.unwrap_or_default();
if !neighbors.contains(&to_id) {
graph
.insert_edge(EdgeSpec {
from: from_id,
to: to_id,
edge_type: "test_edge".to_string(),
data: serde_json::json!({"edge_id": edge_count, "seed": seed}),
})
.expect(&format!(
"Failed to insert edge {} from {} to {}",
edge_count, from_id, to_id
));
edge_count += 1;
}
}
}
println!(
"✅ Inserted 500 edges using deterministic RNG seed {}",
seed
);
let sample_nodes: Vec<i64> = (0..10).map(|i| node_ids[i * 30]).collect();
let mut original_neighbor_counts = Vec::new();
for &node_id in &sample_nodes {
let neighbors = graph
.neighbors(SnapshotId::current(), node_id, NeighborQuery::default())
.expect("Failed to get neighbors");
original_neighbor_counts.push(neighbors.len());
println!("Node {} has {} neighbors", node_id, neighbors.len());
}
drop(graph);
println!("✅ Graph closed - database file flushed");
println!("=== PHASE 2: Reopen and verify integrity ===");
let graph =
open_graph(&db_path, &GraphConfig::native()).expect("Failed to reopen V2 native graph");
println!("✅ Graph reopened successfully");
for &node_id in &node_ids {
let node = graph
.get_node(SnapshotId::current(), node_id)
.expect(&format!("Failed to get node {}", node_id));
assert_eq!(
node.id, node_id,
"Node {} should still exist after reopen",
node_id
);
}
println!("✅ All 300 nodes verified to exist after reopen");
for (i, &node_id) in sample_nodes.iter().enumerate() {
let neighbors = graph
.neighbors(SnapshotId::current(), node_id, NeighborQuery::default())
.expect(&format!("Failed to get neighbors for node {}", node_id));
let original_count = original_neighbor_counts[i];
assert_eq!(
neighbors.len(),
original_count,
"Node {} neighbor count changed: was {}, now {}",
node_id,
original_count,
neighbors.len()
);
println!(
"Node {} has {} neighbors (stable: {})",
node_id,
neighbors.len(),
original_count
);
}
println!("✅ All sampled node neighbor counts are stable after reopen");
let new_from_id = node_ids[0];
let new_to_id = node_ids[1];
let neighbors = graph
.neighbors(SnapshotId::current(), new_from_id, NeighborQuery::default())
.unwrap_or_default();
if !neighbors.contains(&new_to_id) {
graph
.insert_edge(EdgeSpec {
from: new_from_id,
to: new_to_id,
edge_type: "after_reopen".to_string(),
data: serde_json::json!({"test": "edge_insertion_after_reopen"}),
})
.expect("Failed to insert edge after reopen");
println!("✅ Successfully inserted new edge after reopen");
} else {
println!(
"ℹ️ Edge between {} and {} already exists, skipping new edge test",
new_from_id, new_to_id
);
}
let final_neighbors = graph
.neighbors(SnapshotId::current(), new_from_id, NeighborQuery::default())
.expect("Failed to get final neighbors");
assert!(
final_neighbors.len() >= original_neighbor_counts[0],
"Final neighbor count should be >= original count"
);
println!(
"✅ Final neighbor count: {} (>= {})",
final_neighbors.len(),
original_neighbor_counts[0]
);
println!(
"🎉 REOPEN INTEGRATION TEST PASSED - Database behavior is stable across close/reopen cycles"
);
}