use crate::backend::native::v3::{KvValue, V3Backend};
use crate::backend::{EdgeSpec, GraphBackend, NodeSpec, SubscriptionFilter};
use crate::snapshot::SnapshotId;
use tempfile::TempDir;
#[test]
fn test_graph_ops_without_kv_or_pubsub() {
let temp_dir = TempDir::new().unwrap();
let db_path = temp_dir.path().join("test.graph");
let backend = V3Backend::create(&db_path).unwrap();
let node1 = backend
.insert_node(NodeSpec {
kind: "File".to_string(),
name: "main.rs".to_string(),
file_path: Some("src/main.rs".to_string()),
data: serde_json::json!({"lines": 100}),
})
.unwrap();
let node2 = backend
.insert_node(NodeSpec {
kind: "Function".to_string(),
name: "main".to_string(),
file_path: None,
data: serde_json::json!({"public": true}),
})
.unwrap();
backend
.insert_edge(EdgeSpec {
from: node1,
to: node2,
edge_type: "contains".to_string(),
data: serde_json::json!({}),
})
.unwrap();
let ids = backend.entity_ids().unwrap();
assert_eq!(ids.len(), 2);
let outgoing = backend.fetch_outgoing(node1).unwrap();
assert_eq!(outgoing.len(), 1);
assert_eq!(outgoing[0], node2);
let incoming = backend.fetch_incoming(node2).unwrap();
assert_eq!(incoming.len(), 1);
assert_eq!(incoming[0], node1);
}
#[test]
fn test_kv_not_initialized_on_get() {
let temp_dir = TempDir::new().unwrap();
let db_path = temp_dir.path().join("test.graph");
let backend = V3Backend::create(&db_path).unwrap();
assert!(
!backend.is_kv_initialized(),
"KV store should not be initialized on creation"
);
let snapshot_id = SnapshotId::current();
let result = backend.kv_get_v3(snapshot_id, b"test_key");
assert!(result.is_none(), "Should return None for non-existent key");
assert!(
!backend.is_kv_initialized(),
"KV store should NOT be initialized after read-only get"
);
}
#[test]
fn test_kv_lazy_init_on_set() {
let temp_dir = TempDir::new().unwrap();
let db_path = temp_dir.path().join("test.graph");
let backend = V3Backend::create(&db_path).unwrap();
assert!(
!backend.is_kv_initialized(),
"KV store should not be initialized on creation"
);
backend.kv_set_v3(
b"my_key".to_vec(),
KvValue::String("value".to_string()),
None,
);
assert!(
backend.is_kv_initialized(),
"KV store should be initialized after first set"
);
}
#[test]
fn test_pubsub_lazy_init_on_subscribe() {
let temp_dir = TempDir::new().unwrap();
let db_path = temp_dir.path().join("test.graph");
let backend = V3Backend::create(&db_path).unwrap();
assert!(
!backend.is_pubsub_initialized(),
"Publisher should not be initialized on creation"
);
let filter = SubscriptionFilter::all();
let (sub_id, _receiver) = backend.subscribe(filter).unwrap();
assert!(
backend.is_pubsub_initialized(),
"Publisher should be initialized after first subscribe"
);
backend.unsubscribe(sub_id).unwrap();
}
#[test]
fn test_kv_operations_after_lazy_init() {
let temp_dir = TempDir::new().unwrap();
let db_path = temp_dir.path().join("test.graph");
let backend = V3Backend::create(&db_path).unwrap();
let snapshot_id = SnapshotId::current();
let value = backend.kv_get_v3(snapshot_id, b"counter");
assert!(value.is_none());
backend.kv_set_v3(b"counter".to_vec(), KvValue::Integer(42), None);
let value = backend.kv_get_v3(snapshot_id, b"counter");
assert!(value.is_some());
match value.unwrap() {
KvValue::Integer(v) => assert_eq!(v, 42),
_ => panic!("Expected integer value"),
}
backend.kv_delete_v3(b"counter");
let value = backend.kv_get_v3(snapshot_id, b"counter");
assert!(value.is_none());
}
#[test]
fn test_pubsub_operations_after_lazy_init() {
let temp_dir = TempDir::new().unwrap();
let db_path = temp_dir.path().join("test.graph");
let backend = V3Backend::create(&db_path).unwrap();
let filter = SubscriptionFilter::all();
let (sub_id, _receiver) = backend.subscribe(filter).unwrap();
let removed = backend.unsubscribe(sub_id).unwrap();
assert!(removed);
let removed = backend.unsubscribe(sub_id).unwrap();
assert!(!removed);
}
#[test]
fn test_multiple_graph_ops_no_kv_pubsub_init() {
let temp_dir = TempDir::new().unwrap();
let db_path = temp_dir.path().join("test.graph");
let backend = V3Backend::create(&db_path).unwrap();
for i in 0..10 {
let node = backend
.insert_node(NodeSpec {
kind: "Node".to_string(),
name: format!("node_{}", i),
file_path: None,
data: serde_json::json!({}),
})
.unwrap();
if i > 0 {
backend
.insert_edge(EdgeSpec {
from: (i as i64),
to: node,
edge_type: "links".to_string(),
data: serde_json::json!({}),
})
.unwrap();
}
}
assert!(
!backend.is_kv_initialized(),
"KV should not be initialized after graph ops"
);
assert!(
!backend.is_pubsub_initialized(),
"PubSub should not be initialized after graph ops"
);
}
#[test]
fn test_interleaved_graph_and_kv_ops() {
let temp_dir = TempDir::new().unwrap();
let db_path = temp_dir.path().join("test.graph");
let backend = V3Backend::create(&db_path).unwrap();
let snapshot_id = SnapshotId::current();
let node1 = backend
.insert_node(NodeSpec {
kind: "File".to_string(),
name: "a.rs".to_string(),
file_path: None,
data: serde_json::json!({}),
})
.unwrap();
backend.kv_set_v3(
b"metadata".to_vec(),
KvValue::Json(serde_json::json!({"author": "test"})),
None,
);
let node2 = backend
.insert_node(NodeSpec {
kind: "File".to_string(),
name: "b.rs".to_string(),
file_path: None,
data: serde_json::json!({}),
})
.unwrap();
backend
.insert_edge(EdgeSpec {
from: node1,
to: node2,
edge_type: "depends_on".to_string(),
data: serde_json::json!({}),
})
.unwrap();
let value = backend.kv_get_v3(snapshot_id, b"metadata");
assert!(value.is_some());
let outgoing = backend.fetch_outgoing(node1).unwrap();
assert_eq!(outgoing.len(), 1);
}