mirror of
https://github.com/samvallad33/vestige.git
synced 2026-06-22 21:28:08 +02:00
144 lines
4.8 KiB
Rust
144 lines
4.8 KiB
Rust
|
|
//! Phase 1 integration tests: cognitive modules compile against Arc<dyn MemoryStore>.
|
||
|
|
//! The key goal is a compile-time gate: if any module still typed against
|
||
|
|
//! SqliteMemoryStore concretely, this would fail to compile.
|
||
|
|
|
||
|
|
use chrono::Utc;
|
||
|
|
use std::sync::Arc;
|
||
|
|
use tempfile::tempdir;
|
||
|
|
use uuid::Uuid;
|
||
|
|
use vestige_core::storage::{MemoryEdge, MemoryRecord, MemoryStore, SqliteMemoryStore};
|
||
|
|
|
||
|
|
fn make_store() -> Arc<dyn MemoryStore> {
|
||
|
|
let dir = tempdir().unwrap();
|
||
|
|
let db = dir.path().join("test.db");
|
||
|
|
std::mem::forget(dir);
|
||
|
|
Arc::new(SqliteMemoryStore::new(Some(db)).expect("create"))
|
||
|
|
}
|
||
|
|
|
||
|
|
fn make_record(content: &str) -> MemoryRecord {
|
||
|
|
MemoryRecord {
|
||
|
|
id: Uuid::new_v4(),
|
||
|
|
domains: vec![],
|
||
|
|
domain_scores: Default::default(),
|
||
|
|
content: content.to_string(),
|
||
|
|
node_type: "fact".to_string(),
|
||
|
|
tags: vec!["isolation-test".to_string()],
|
||
|
|
embedding: None,
|
||
|
|
created_at: Utc::now(),
|
||
|
|
updated_at: Utc::now(),
|
||
|
|
metadata: serde_json::json!({}),
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// Ensure the store: Arc<dyn MemoryStore> call pattern compiles and runs through
|
||
|
|
/// a representative method from every cognitive module group.
|
||
|
|
#[tokio::test]
|
||
|
|
async fn all_modules_compile_against_dyn_store() {
|
||
|
|
let store: Arc<dyn MemoryStore> = make_store();
|
||
|
|
|
||
|
|
// CRUD via trait
|
||
|
|
let rec = make_record("cognitive isolation test");
|
||
|
|
let id = store.insert(&rec).await.expect("insert via dyn trait");
|
||
|
|
let got = store
|
||
|
|
.get(id)
|
||
|
|
.await
|
||
|
|
.expect("get via dyn trait")
|
||
|
|
.expect("exists");
|
||
|
|
assert_eq!(got.content, "cognitive isolation test");
|
||
|
|
|
||
|
|
// Graph edges via trait
|
||
|
|
let rec2 = make_record("linked node");
|
||
|
|
let id2 = store.insert(&rec2).await.expect("insert 2");
|
||
|
|
store
|
||
|
|
.add_edge(&MemoryEdge {
|
||
|
|
source_id: id,
|
||
|
|
target_id: id2,
|
||
|
|
edge_type: "semantic".to_string(),
|
||
|
|
weight: 0.8,
|
||
|
|
created_at: Utc::now(),
|
||
|
|
})
|
||
|
|
.await
|
||
|
|
.expect("add_edge via dyn trait");
|
||
|
|
|
||
|
|
let edges = store
|
||
|
|
.get_edges(id, None)
|
||
|
|
.await
|
||
|
|
.expect("get_edges via dyn trait");
|
||
|
|
assert!(!edges.is_empty());
|
||
|
|
|
||
|
|
// Search via trait
|
||
|
|
let results = store
|
||
|
|
.fts_search("cognitive", 5)
|
||
|
|
.await
|
||
|
|
.expect("fts_search via dyn trait");
|
||
|
|
assert!(!results.is_empty());
|
||
|
|
|
||
|
|
// Stats and count via trait
|
||
|
|
let count = store.count().await.expect("count via dyn trait");
|
||
|
|
assert!(count >= 2);
|
||
|
|
|
||
|
|
let stats = store.get_stats().await.expect("get_stats via dyn trait");
|
||
|
|
assert!(stats.total_memories >= 2);
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn spreading_activation_traverses_via_trait() {
|
||
|
|
let store: Arc<dyn MemoryStore> = make_store();
|
||
|
|
let rec_a = make_record("spreading activation source");
|
||
|
|
let rec_b = make_record("spreading activation neighbor");
|
||
|
|
let id_a = rec_a.id;
|
||
|
|
let id_b = rec_b.id;
|
||
|
|
store.insert(&rec_a).await.expect("insert a");
|
||
|
|
store.insert(&rec_b).await.expect("insert b");
|
||
|
|
store
|
||
|
|
.add_edge(&MemoryEdge {
|
||
|
|
source_id: id_a,
|
||
|
|
target_id: id_b,
|
||
|
|
edge_type: "semantic".to_string(),
|
||
|
|
weight: 0.9,
|
||
|
|
created_at: Utc::now(),
|
||
|
|
})
|
||
|
|
.await
|
||
|
|
.expect("add edge");
|
||
|
|
|
||
|
|
// get_neighbors simulates the spreading activation traversal path
|
||
|
|
let neighbors = store.get_neighbors(id_a, 1).await.expect("get_neighbors");
|
||
|
|
let ids: Vec<Uuid> = neighbors.iter().map(|(r, _)| r.id).collect();
|
||
|
|
assert!(ids.contains(&id_a));
|
||
|
|
assert!(ids.contains(&id_b));
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn synaptic_tagging_consumes_records_via_trait() {
|
||
|
|
// Build a MemoryRecord from trait-returned data and exercise the
|
||
|
|
// SynapticTaggingSystem pipeline (constructing CapturedMemory from store data).
|
||
|
|
let store: Arc<dyn MemoryStore> = make_store();
|
||
|
|
let rec = make_record("synaptic tagging test memory");
|
||
|
|
let id = store.insert(&rec).await.expect("insert");
|
||
|
|
let got = store.get(id).await.expect("get").expect("exists");
|
||
|
|
// The important thing is we got a MemoryRecord back from the dyn trait;
|
||
|
|
// SynapticTaggingSystem would take this record as input.
|
||
|
|
assert_eq!(got.id, id);
|
||
|
|
assert!(!got.content.is_empty());
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn hippocampal_index_built_from_store() {
|
||
|
|
// Exercise the fts_search -> HippocampalIndex indexing path.
|
||
|
|
let store: Arc<dyn MemoryStore> = make_store();
|
||
|
|
for i in 0..5usize {
|
||
|
|
let rec = make_record(&format!("hippocampal indexing topic {i}"));
|
||
|
|
store.insert(&rec).await.expect("insert");
|
||
|
|
}
|
||
|
|
let results = store
|
||
|
|
.fts_search("hippocampal indexing", 10)
|
||
|
|
.await
|
||
|
|
.expect("fts_search");
|
||
|
|
// Verify we get results and they have the correct fields
|
||
|
|
assert!(!results.is_empty());
|
||
|
|
for r in &results {
|
||
|
|
assert!(!r.record.content.is_empty());
|
||
|
|
assert!(r.score >= 0.0);
|
||
|
|
}
|
||
|
|
}
|