use super::*;
use tempfile::TempDir;
#[tokio::test]
async fn test_reserve_capacity_async() {
let dir = TempDir::new().unwrap();
let storage = Arc::new(RwLock::new(MmapStorage::new(dir.path(), 128).unwrap()));
let result = reserve_capacity_async(storage, 1000).await;
assert!(result.is_ok());
}
#[tokio::test]
async fn test_store_batch_async() {
let dir = TempDir::new().unwrap();
let storage = Arc::new(RwLock::new(MmapStorage::new(dir.path(), 4).unwrap()));
let vectors: Vec<(u64, Vec<f32>)> = (0..100).map(|i| (i, vec![i as f32; 4])).collect();
let result = store_batch_async(storage.clone(), vectors).await;
assert!(result.is_ok());
assert_eq!(result.unwrap(), 100);
}
#[tokio::test]
async fn store_batch_async_stores_every_vector_it_counts() {
let dir = TempDir::new().expect("test: temp dir");
let storage = Arc::new(RwLock::new(
MmapStorage::new(dir.path(), 4).expect("test: open storage"),
));
let vectors: Vec<(u64, Vec<f32>)> = (0..100)
.map(|i| (i, vec![i as f32, 1.0, 2.0, 3.0]))
.collect();
let count = store_batch_async(storage.clone(), vectors)
.await
.expect("test: batch must store");
assert_eq!(count, 100);
let stored: Vec<Option<Vec<f32>>> = {
let guard = storage.read();
(0..100u64)
.map(|i| guard.retrieve(i).expect("test: retrieve must not fail"))
.collect()
};
for (i, entry) in stored.into_iter().enumerate() {
let vector = entry.unwrap_or_else(|| panic!("test: vector {i} is missing"));
assert_eq!(vector, vec![i as f32, 1.0, 2.0, 3.0], "vector {i}");
}
}
#[tokio::test]
async fn store_batch_async_rejects_the_whole_batch_on_a_bad_dimension() {
let dir = TempDir::new().expect("test: temp dir");
let storage = Arc::new(RwLock::new(
MmapStorage::new(dir.path(), 4).expect("test: open storage"),
));
let vectors = vec![
(1u64, vec![1.0, 1.0, 1.0, 1.0]),
(2u64, vec![2.0, 2.0, 2.0, 2.0]),
(3u64, vec![3.0, 3.0]), ];
store_batch_async(storage.clone(), vectors)
.await
.expect_err("test: a wrong dimension must reject the batch");
let committed: Vec<(u64, bool)> = {
let guard = storage.read();
[1u64, 2, 3]
.into_iter()
.map(|id| {
let present = guard
.retrieve(id)
.expect("test: retrieve must not fail")
.is_some();
(id, present)
})
.collect()
};
for (id, present) in committed {
assert!(!present, "vector {id} was committed by a batch that failed");
}
}
#[tokio::test]
async fn store_batch_async_leaves_the_batch_durable_on_disk() {
let dir = TempDir::new().expect("test: temp dir");
let vectors: Vec<(u64, Vec<f32>)> = (0..64)
.map(|i| (i, vec![i as f32, 0.5, 0.25, 0.125]))
.collect();
{
let storage = Arc::new(RwLock::new(
MmapStorage::new(dir.path(), 4).expect("test: open storage"),
));
store_batch_async(storage, vectors)
.await
.expect("test: batch must store");
}
let reopened = MmapStorage::new(dir.path(), 4).expect("test: reopen storage");
for i in 0..64u64 {
let stored = reopened
.retrieve(i)
.expect("test: retrieve must not fail")
.unwrap_or_else(|| panic!("test: vector {i} did not survive the reopen"));
assert_eq!(stored, vec![i as f32, 0.5, 0.25, 0.125], "vector {i}");
}
}
#[tokio::test]
async fn test_flush_async() {
let dir = TempDir::new().unwrap();
let storage = Arc::new(RwLock::new(MmapStorage::new(dir.path(), 128).unwrap()));
let result = flush_async(storage).await;
assert!(result.is_ok());
}