#![cfg(feature = "v2_experimental")]
use sqlitegraph::{
BackendDirection, EdgeSpec, NeighborQuery, NodeSpec, config::GraphConfig, open_graph,
};
use tempfile::TempDir;
fn create_test_node(graph: &Box<dyn sqlitegraph::GraphBackend>, node_id: i64) -> i64 {
let node_spec = NodeSpec {
kind: "test_node".to_string(),
name: format!("test_node_{}", node_id),
file_path: None,
data: serde_json::json!({"node_id": node_id}),
};
graph.insert_node(node_spec).unwrap()
}
fn create_controlled_size_edge_v2(from_id: i64, to_id: i64, total_size_target: usize) -> EdgeSpec {
let string_payload_size = total_size_target.saturating_sub(34);
let type_size = string_payload_size / 2;
let data_size = string_payload_size - type_size;
let edge_type_string = "x".repeat(type_size);
let data_string = format!("data_{}", "y".repeat(data_size));
EdgeSpec {
from: from_id,
to: to_id,
edge_type: edge_type_string,
data: serde_json::json!({"payload": data_string, "target_size": total_size_target}),
}
}
#[test]
fn v2_edge_boundary_new_files_use_v2_format_by_default() {
let temp_dir = TempDir::new().unwrap();
let db_path = temp_dir.path().join("test_v2_default_format.db");
let config = GraphConfig::native();
let graph = open_graph(&db_path, &config).unwrap();
let from_node_id = create_test_node(&graph, 1);
let to_node_id = create_test_node(&graph, 2);
let edge_spec = create_controlled_size_edge_v2(from_node_id, to_node_id, 100);
let result = graph.insert_edge(edge_spec);
match result {
Err(sqlitegraph::SqliteGraphError::ConnectionError(err_msg)) => {
assert!(
err_msg.contains("Unexpected V1 node record encountered in V2 region"),
"Expected V1-in-V2 format error, got: {}",
err_msg
);
}
Ok(_) => {
println!("V2 edge insertion succeeded - V1/V2 mismatch may be resolved");
}
other => {
panic!("Unexpected error type: {:?}", other);
}
}
}
#[test]
fn v2_edge_boundary_small_edges_should_read_successfully() {
let temp_dir = TempDir::new().unwrap();
let db_path = temp_dir.path().join("test_v2_small_edge_boundary.db");
let config = GraphConfig::native();
let graph = open_graph(&db_path, &config).unwrap();
let from_node_id = create_test_node(&graph, 1);
let to_node_id = create_test_node(&graph, 2);
let small_sizes = [50, 100, 200, 255];
for &target_size in &small_sizes {
let edge_spec = create_controlled_size_edge_v2(from_node_id, to_node_id, target_size);
let edge_id = graph.insert_edge(edge_spec).unwrap();
let result = graph.neighbors(
from_node_id,
NeighborQuery {
direction: BackendDirection::Outgoing,
edge_type: None,
},
);
assert!(
result.is_ok(),
"Small V2 edge ({} bytes) should read successfully. Error: {:?}",
target_size,
result
);
let neighbors = result.unwrap();
assert!(
neighbors.contains(&to_node_id),
"Small V2 edge should connect nodes successfully"
);
}
}
#[test]
fn v2_edge_boundary_edges_around_256b_should_read_successfully() {
let temp_dir = TempDir::new().unwrap();
let db_path = temp_dir.path().join("test_v2_256b_edge_boundary.db");
let config = GraphConfig::native();
let graph = open_graph(&db_path, &config).unwrap();
let from_node_id = create_test_node(&graph, 3);
let to_node_id = create_test_node(&graph, 4);
let boundary_sizes = [250, 255, 256, 260];
for &target_size in &boundary_sizes {
let edge_spec = create_controlled_size_edge_v2(from_node_id, to_node_id, target_size);
let edge_id = graph.insert_edge(edge_spec).unwrap();
let result = graph.neighbors(
from_node_id,
NeighborQuery {
direction: BackendDirection::Outgoing,
edge_type: None,
},
);
assert!(
result.is_ok(),
"Boundary V2 edge ({} bytes) should read successfully. Error: {:?}",
target_size,
result
);
let neighbors = result.unwrap();
assert!(
neighbors.contains(&to_node_id),
"Boundary V2 edge should connect nodes successfully"
);
}
}
#[test]
fn v2_edge_boundary_large_edges_should_work_correctly() {
let temp_dir = TempDir::new().unwrap();
let db_path = temp_dir.path().join("test_v2_large_edge_boundary.db");
let config = GraphConfig::native();
let graph = open_graph(&db_path, &config).unwrap();
let from_node_id = create_test_node(&graph, 5);
let to_node_id = create_test_node(&graph, 6);
let large_sizes = [300, 512, 1024];
for &target_size in &large_sizes {
let edge_spec = create_controlled_size_edge_v2(from_node_id, to_node_id, target_size);
let result = graph.insert_edge(edge_spec);
match result {
Ok(edge_id) => {
let read_result = graph.neighbors(
from_node_id,
NeighborQuery {
direction: BackendDirection::Outgoing,
edge_type: None,
},
);
assert!(
read_result.is_ok(),
"Large V2 edge ({} bytes) should read successfully after insertion. Error: {:?}",
target_size,
read_result
);
}
Err(e) => {
println!(
"Large V2 edge ({} bytes) insertion failed gracefully: {:?}",
target_size, e
);
}
}
}
}
#[test]
fn v2_edge_boundary_mixed_size_edges_should_handle_correctly() {
let temp_dir = TempDir::new().unwrap();
let db_path = temp_dir.path().join("test_v2_mixed_edge_boundary.db");
let config = GraphConfig::native();
let graph = open_graph(&db_path, &config).unwrap();
let mut node_ids = Vec::new();
for i in 7..=16 {
let node_id = create_test_node(&graph, i);
node_ids.push(node_id);
}
let mut edge_results = Vec::new();
for i in 0..=2 {
let edge_spec = create_controlled_size_edge_v2(node_ids[i], node_ids[i + 1], 100);
let result = graph.insert_edge(edge_spec);
edge_results.push((100, result, true)); }
for i in 3..=5 {
let edge_spec = create_controlled_size_edge_v2(node_ids[i], node_ids[i + 1], 255);
let result = graph.insert_edge(edge_spec);
edge_results.push((255, result, true));
}
for i in 6..=8 {
let edge_spec =
create_controlled_size_edge_v2(node_ids[i], node_ids[(i + 1) % node_ids.len()], 512);
let result = graph.insert_edge(edge_spec);
edge_results.push((512, result, false)); }
for (size, result, should_succeed) in edge_results {
if should_succeed {
assert!(
result.is_ok(),
"V2 edge ({} bytes) should insert successfully. Error: {:?}",
size,
result
);
} else {
match result {
Ok(_) => {
println!(
"Large V2 edge ({} bytes) succeeded - V2 handles large edges well",
size
);
}
Err(e) => {
println!("Large V2 edge ({} bytes) failed gracefully: {:?}", size, e);
}
}
}
}
}
#[test]
fn v2_edge_boundary_exactly_256b_edge_should_be_handled_correctly() {
let temp_dir = TempDir::new().unwrap();
let db_path = temp_dir.path().join("test_v2_exact_256b_edge.db");
let config = GraphConfig::native();
let graph = open_graph(&db_path, &config).unwrap();
let from_node_id = create_test_node(&graph, 17);
let to_node_id = create_test_node(&graph, 18);
let exact_256b_minus_1 = 255;
let edge_spec = create_controlled_size_edge_v2(from_node_id, to_node_id, exact_256b_minus_1);
let edge_id = graph.insert_edge(edge_spec).unwrap();
let result = graph.neighbors(
from_node_id,
NeighborQuery {
direction: BackendDirection::Outgoing,
edge_type: None,
},
);
assert!(
result.is_ok(),
"Exactly 256B-1 V2 edge should read successfully. Error: {:?}",
result
);
let exact_256b = 256;
let edge_spec2 = create_controlled_size_edge_v2(from_node_id, to_node_id, exact_256b);
let result2 = graph.insert_edge(edge_spec2);
println!("Exactly 256B V2 edge insertion result: {:?}", result2);
}
#[test]
fn v2_edge_boundary_adjacency_clustering_should_work_at_node_257() {
let temp_dir = TempDir::new().unwrap();
let db_path = temp_dir.path().join("test_v2_adjacency_clustering_257.db");
let config = GraphConfig::native();
let graph = open_graph(&db_path, &config).unwrap();
let mut node_ids = Vec::new();
for i in 1..=300 {
let node_id = create_test_node(&graph, i);
node_ids.push(node_id);
}
let mut edge_results = Vec::new();
for i in 0..=256 {
let from_node = node_ids[i];
let to_node = node_ids[(i + 1) % node_ids.len()];
let edge_spec = EdgeSpec {
from: from_node,
to: to_node,
edge_type: "v2_clustering_test".to_string(),
data: serde_json::json!({
"from_node": from_node,
"to_node": to_node,
"payload": "x".repeat(100) }),
};
let result = graph.insert_edge(edge_spec);
edge_results.push((from_node, to_node, result.is_ok()));
if from_node == 257 || to_node == 257 {
println!(
"V2 edge creation at node 257 boundary: from {} to {} -> {:?}",
from_node, to_node, result
);
}
}
let test_node_257_result = graph.neighbors(
257,
NeighborQuery {
direction: BackendDirection::Outgoing,
edge_type: None,
},
);
println!("V2 neighbors for node 257: {:?}", test_node_257_result);
match test_node_257_result {
Ok(neighbors) => {
println!(
"V2 adjacency clustering works correctly at node 257: {} neighbors",
neighbors.len()
);
}
Err(e) => {
println!("V2 adjacency clustering issue at node 257: {:?}", e);
}
}
}