use super::*;
use crate::memory_types::{BatchIngestItemResult, IngestPolicy};
use super::crud::test_fake_embedder;
#[test]
fn test_batch_ingest_empty_batch() {
let mut store = MemoryStore::test_store();
let result = store
.batch_ingest("test-project", vec![], IngestPolicy::ConflictAware)
.unwrap();
assert_eq!(result.results.len(), 0);
}
#[test]
fn test_batch_ingest_mixed_outcomes() {
let path = MemoryStore::test_db_path();
let db = crate::sqlite::Database::open(&path).unwrap();
let embedding = test_fake_embedder("Alice works at Microsoft").unwrap();
db.insert(
"test-project",
"Alice works at Microsoft",
&embedding,
None,
"fact",
"active",
)
.unwrap();
let mut store = MemoryStore::from_db_with_test_embedder(db);
let items = vec![
("", None), ("Bob works at Google", None), ("Alice works at Microsoft", None), ("Charlie works at Amazon", None), ];
let result = store
.batch_ingest("test-project", items.clone(), IngestPolicy::ConflictAware)
.unwrap();
assert_eq!(result.results.len(), 4);
match &result.results[0] {
BatchIngestItemResult::Error { message } => {
assert!(message.contains("empty") || message.contains("EmptyInput"));
}
_ => panic!("Expected Error for item 0, got {:?}", result.results[0]),
}
match &result.results[1] {
BatchIngestItemResult::Added { id } => {
assert!(!id.is_empty());
let memory = store.get(id, "test-project").unwrap().unwrap();
assert_eq!(memory.content, "Bob works at Google");
}
_ => panic!("Expected Added for item 1, got {:?}", result.results[1]),
}
match &result.results[2] {
BatchIngestItemResult::Conflicts {
proposed,
conflicts,
} => {
assert_eq!(proposed, "Alice works at Microsoft");
assert!(!conflicts.is_empty());
assert!(conflicts.iter().any(|c| c.content.contains("Alice")));
}
_ => panic!("Expected Conflicts for item 2, got {:?}", result.results[2]),
}
match &result.results[3] {
BatchIngestItemResult::Added { id } => {
assert!(!id.is_empty());
let memory = store.get(id, "test-project").unwrap().unwrap();
assert_eq!(memory.content, "Charlie works at Amazon");
}
_ => panic!("Expected Added for item 3, got {:?}", result.results[3]),
}
}
#[test]
fn test_batch_ingest_deterministic_index_mapping() {
let path = MemoryStore::test_db_path();
let db = crate::sqlite::Database::open(&path).unwrap();
let embedding = test_fake_embedder("conflict with item 1").unwrap();
db.insert(
"test-project",
"conflict with item 1",
&embedding,
None,
"fact",
"active",
)
.unwrap();
let mut store = MemoryStore::from_db_with_test_embedder(db);
let items = vec![
("unique item 0", None),
("conflict with item 1", None), ("", None), ("unique item 3", Some("metadata")),
];
let result = store
.batch_ingest("test-project", items.clone(), IngestPolicy::ConflictAware)
.unwrap();
assert_eq!(result.results.len(), 4);
assert!(matches!(
&result.results[0],
BatchIngestItemResult::Added { .. }
));
assert!(matches!(
&result.results[1],
BatchIngestItemResult::Conflicts { .. }
));
assert!(matches!(
&result.results[2],
BatchIngestItemResult::Error { .. }
));
if let BatchIngestItemResult::Added { id } = &result.results[3] {
let memory = store.get(id, "test-project").unwrap().unwrap();
assert_eq!(memory.content, "unique item 3");
assert_eq!(memory.metadata, Some("metadata".to_string()));
} else {
panic!("Expected Added for index 3");
}
}
#[test]
fn test_batch_ingest_policy_force() {
let path = MemoryStore::test_db_path();
let db = crate::sqlite::Database::open(&path).unwrap();
let embedding = test_fake_embedder("Alice works at Microsoft").unwrap();
db.insert(
"test-project",
"Alice works at Microsoft",
&embedding,
None,
"fact",
"active",
)
.unwrap();
let mut store = MemoryStore::from_db_with_test_embedder(db);
let items = vec![
("Alice works at Microsoft", None), ("Bob works at Google", None), ];
let result = store
.batch_ingest("test-project", items.clone(), IngestPolicy::Force)
.unwrap();
assert_eq!(result.results.len(), 2);
match &result.results[0] {
BatchIngestItemResult::Added { id } => {
assert!(!id.is_empty());
let memory = store.get(id, "test-project").unwrap().unwrap();
assert_eq!(memory.content, "Alice works at Microsoft");
}
_ => panic!("Expected Added for item 0 with Force policy"),
}
match &result.results[1] {
BatchIngestItemResult::Added { id } => {
assert!(!id.is_empty());
let memory = store.get(id, "test-project").unwrap().unwrap();
assert_eq!(memory.content, "Bob works at Google");
}
_ => panic!("Expected Added for item 1 with Force policy"),
}
}
#[test]
fn test_batch_ingest_invalid_inputs() {
let mut store = MemoryStore::test_store();
let too_long = "a".repeat(100_001);
let whitespace = " \t\n ";
let items = vec![
("", None), (" ", None), (&too_long, None), ("valid input", None), (whitespace, None), ];
let result = store
.batch_ingest("test-project", items.clone(), IngestPolicy::ConflictAware)
.unwrap();
assert_eq!(result.results.len(), 5);
for &idx in &[0_usize, 1, 2, 4] {
match &result.results[idx] {
BatchIngestItemResult::Error { .. } => {
}
other => panic!(
"Expected Error for invalid input at index {}, got {:?}",
idx, other
),
}
}
match &result.results[3] {
BatchIngestItemResult::Added { id } => {
assert!(!id.is_empty());
let memory = store.get(id, "test-project").unwrap().unwrap();
assert_eq!(memory.content, "valid input");
}
_ => panic!("Expected Added for valid input at index 3"),
}
}
#[test]
fn test_batch_ingest_all_errors() {
let mut store = MemoryStore::test_store();
let items = vec![
("", None), (" ", None), ];
let result = store
.batch_ingest("test-project", items.clone(), IngestPolicy::ConflictAware)
.unwrap();
assert_eq!(result.results.len(), 2);
for (idx, item_result) in result.results.iter().enumerate() {
match item_result {
BatchIngestItemResult::Error { .. } => {
}
_ => panic!("Expected Error for all items at index {}", idx),
}
}
}
#[test]
fn test_batch_ingest_metadata_preservation() {
let mut store = MemoryStore::test_store();
let items = vec![
("content with metadata", Some(r#"{"tag": "important"}"#)),
("content without metadata", None),
(
"json metadata",
Some(r#"{"source": "user", "priority": 1}"#),
),
];
let result = store
.batch_ingest("test-project", items.clone(), IngestPolicy::ConflictAware)
.unwrap();
assert_eq!(result.results.len(), 3);
if let BatchIngestItemResult::Added { id } = &result.results[0] {
let memory = store.get(id, "test-project").unwrap().unwrap();
assert_eq!(memory.metadata, Some(r#"{"tag": "important"}"#.to_string()));
} else {
panic!("Expected Added for item 0");
}
if let BatchIngestItemResult::Added { id } = &result.results[1] {
let memory = store.get(id, "test-project").unwrap().unwrap();
assert_eq!(memory.metadata, None);
} else {
panic!("Expected Added for item 1");
}
if let BatchIngestItemResult::Added { id } = &result.results[2] {
let memory = store.get(id, "test-project").unwrap().unwrap();
assert_eq!(
memory.metadata,
Some(r#"{"source": "user", "priority": 1}"#.to_string())
);
} else {
panic!("Expected Added for item 2");
}
}