use proptest::prelude::*;
use std::fs;
use tempfile::TempDir;
use vantadb::node::{NodeFlags, NodeTier, UnifiedNode, VectorRepresentations};
use vantadb::storage::StorageEngine;
fn node_strategy() -> impl Strategy<Value = UnifiedNode> {
(0u64..10000u64, 0u32..100u32).prop_map(|(id, cluster)| UnifiedNode {
id,
bitset: 0,
semantic_cluster: cluster,
tier: NodeTier::Cold,
flags: NodeFlags::new(),
vector: VectorRepresentations::None,
relational: std::collections::BTreeMap::new(),
edges: Vec::new(),
epoch: 0,
ext_metadata: std::collections::HashMap::new(),
importance: 0.0,
last_accessed: 0,
hits: 0,
confidence_score: 0.0,
})
}
proptest! {
#![proptest_config(ProptestConfig::with_cases(32))]
#[test]
fn prop_insert_persist_after_flush(nodes in proptest::collection::vec(node_strategy(), 0..10)) {
prop_assume!(!nodes.is_empty());
let unique_ids: std::collections::HashSet<u64> = nodes.iter().map(|n| n.id).collect();
let expected_count = unique_ids.len();
let temp_dir = TempDir::new().unwrap();
let db_path = temp_dir.path().to_str().unwrap();
{
let engine = StorageEngine::open(db_path).unwrap();
for node in &nodes {
engine.insert(node).unwrap();
}
engine.flush().unwrap();
}
{
let engine = StorageEngine::open(db_path).unwrap();
let all_nodes = engine.scan_nodes().unwrap();
assert_eq!(all_nodes.len(), expected_count);
}
}
}
proptest! {
#![proptest_config(ProptestConfig::with_cases(32))]
#[test]
fn prop_vector_store_monotonic_growth(nodes in proptest::collection::vec(node_strategy(), 0..10)) {
prop_assume!(!nodes.is_empty());
let temp_dir = TempDir::new().unwrap();
let db_path = temp_dir.path().to_str().unwrap();
let vector_store_path = temp_dir.path().join("data").join("vector_store.vanta");
let mut last_size = 0;
{
let engine = StorageEngine::open(db_path).unwrap();
for node in &nodes {
engine.insert(node).unwrap();
engine.flush().unwrap();
if vector_store_path.exists() {
let current_size = fs::metadata(&vector_store_path).unwrap().len();
assert!(current_size >= last_size, "Vector store should not shrink without compaction");
last_size = current_size;
}
}
}
}
}
proptest! {
#![proptest_config(ProptestConfig::with_cases(32))]
#[test]
fn prop_index_storage_consistency(nodes in proptest::collection::vec(node_strategy(), 0..10)) {
prop_assume!(!nodes.is_empty());
let unique_ids: std::collections::HashSet<u64> = nodes.iter().map(|n| n.id).collect();
let expected_count = unique_ids.len() as u64;
let temp_dir = TempDir::new().unwrap();
let db_path = temp_dir.path().to_str().unwrap();
{
let engine = StorageEngine::open(db_path).unwrap();
for node in &nodes {
engine.insert(node).unwrap();
}
engine.flush().unwrap();
}
{
let engine = StorageEngine::open(db_path).unwrap();
let stats = engine.get_memory_stats();
let index_count = stats.node_count;
let storage_nodes = engine.scan_nodes().unwrap();
let storage_count = storage_nodes.len() as u64;
assert_eq!(index_count, expected_count, "Index count must match unique nodes inserted");
assert_eq!(storage_count, expected_count, "Storage count must match unique nodes inserted");
assert_eq!(index_count, storage_count, "Index and storage counts must match each other");
}
}
}