Files
bichon/crates/blob/tests/integration_test.rs
T

274 lines
7.6 KiB
Rust

use bichon_blob::{Codec, Config, Engine};
use tempfile::TempDir;
#[test]
fn test_create_and_list_accounts() {
let dir = TempDir::new().unwrap();
let engine = Engine::open(dir.path(), Config::default()).unwrap();
engine.create_account("alice").unwrap();
engine.create_account("bob").unwrap();
let accounts = engine.list_accounts();
assert!(accounts.contains(&"alice".to_string()));
assert!(accounts.contains(&"bob".to_string()));
}
#[test]
fn test_write_and_read() {
let dir = TempDir::new().unwrap();
let engine = Engine::open(dir.path(), Config::default()).unwrap();
engine.create_account("alice").unwrap();
let key = [0xAA; 32];
let value = b"Hello, this is a test email!".to_vec();
engine
.write("alice", key, &value, Codec::Zstd)
.unwrap();
let result = engine.read("alice", &key).unwrap();
assert_eq!(result, Some(value));
}
#[test]
fn test_read_missing_key() {
let dir = TempDir::new().unwrap();
let engine = Engine::open(dir.path(), Config::default()).unwrap();
engine.create_account("alice").unwrap();
let key = [0xFF; 32];
let result = engine.read("alice", &key).unwrap();
assert_eq!(result, None);
}
#[test]
fn test_delete() {
let dir = TempDir::new().unwrap();
let engine = Engine::open(dir.path(), Config::default()).unwrap();
engine.create_account("alice").unwrap();
let key = [0xBB; 32];
let value = b"Some email content".to_vec();
engine
.write("alice", key, &value, Codec::Zstd)
.unwrap();
engine.delete("alice", &key).unwrap();
let result = engine.read("alice", &key).unwrap();
assert_eq!(result, None);
}
#[test]
fn test_delete_account() {
let dir = TempDir::new().unwrap();
let engine = Engine::open(dir.path(), Config::default()).unwrap();
engine.create_account("alice").unwrap();
engine.delete_account("alice").unwrap();
let accounts = engine.list_accounts();
assert!(!accounts.contains(&"alice".to_string()));
}
#[test]
fn test_small_value_not_compressed() {
let dir = TempDir::new().unwrap();
let engine = Engine::open(dir.path(), Config::default()).unwrap();
engine.create_account("alice").unwrap();
let key = [0xCC; 32];
let value = b"hi"; // Smaller than 4KB threshold
engine
.write("alice", key, value, Codec::Zstd)
.unwrap();
let result = engine.read("alice", &key).unwrap();
assert_eq!(result, Some(value.to_vec()));
}
#[test]
fn test_large_value() {
let dir = TempDir::new().unwrap();
let engine = Engine::open(dir.path(), Config::default()).unwrap();
engine.create_account("alice").unwrap();
let key = [0xDD; 32];
let value = vec![b'X'; 100_000]; // 100KB
engine
.write("alice", key, &value, Codec::Zstd)
.unwrap();
let result = engine.read("alice", &key).unwrap();
assert_eq!(result, Some(value));
}
#[test]
fn test_multiple_keys() {
let dir = TempDir::new().unwrap();
let engine = Engine::open(dir.path(), Config::default()).unwrap();
engine.create_account("alice").unwrap();
let n = 100;
for i in 0..n {
let mut key = [0u8; 32];
key[0..4].copy_from_slice(&(i as u32).to_le_bytes());
let value = format!("email number {}", i).into_bytes();
engine
.write("alice", key, &value, Codec::Zstd)
.unwrap();
}
for i in 0..n {
let mut key = [0u8; 32];
key[0..4].copy_from_slice(&(i as u32).to_le_bytes());
let result = engine.read("alice", &key).unwrap();
assert_eq!(result, Some(format!("email number {}", i).into_bytes()));
}
}
#[test]
fn test_gc() {
let dir = TempDir::new().unwrap();
let engine = Engine::open(dir.path(), Config::default()).unwrap();
engine.create_account("alice").unwrap();
// Write many entries
let value = vec![b'Y'; 5000];
let n = 100;
for i in 0..n {
let mut key = [0u8; 32];
key[0..4].copy_from_slice(&(i as u32).to_le_bytes());
engine
.write("alice", key, &value, Codec::None)
.unwrap();
}
// Delete even-numbered keys
for i in (0..n).step_by(2) {
let mut key = [0u8; 32];
key[0..4].copy_from_slice(&(i as u32).to_le_bytes());
engine.delete("alice", &key).unwrap();
}
// Run GC
let _result = engine.gc("alice").unwrap();
// Verify remaining keys still readable
for i in (1..n).step_by(2) {
let mut key = [0u8; 32];
key[0..4].copy_from_slice(&(i as u32).to_le_bytes());
let result = engine.read("alice", &key).unwrap();
assert_eq!(result, Some(value.clone()));
}
// Deleted keys should not exist
for i in (0..n).step_by(2) {
let mut key = [0u8; 32];
key[0..4].copy_from_slice(&(i as u32).to_le_bytes());
let result = engine.read("alice", &key).unwrap();
assert_eq!(result, None);
}
}
#[test]
fn test_reopen_persistence() {
let dir = TempDir::new().unwrap();
let key = [0xEE; 32];
let value = b"persistent data".to_vec();
{
let engine = Engine::open(dir.path(), Config::default()).unwrap();
engine.create_account("alice").unwrap();
engine
.write("alice", key, &value, Codec::Zstd)
.unwrap();
}
// Reopen
{
let engine = Engine::open(dir.path(), Config::default()).unwrap();
let result = engine.read("alice", &key).unwrap();
assert_eq!(result, Some(value));
}
}
#[test]
fn test_stats() {
let dir = TempDir::new().unwrap();
let engine = Engine::open(dir.path(), Config::default()).unwrap();
engine.create_account("alice").unwrap();
engine
.write("alice", [1u8; 32], b"hello", Codec::None)
.unwrap();
let stats = engine.stats("alice").unwrap();
assert!(stats.total_bytes > 0);
}
#[test]
fn test_batch_write() {
let dir = TempDir::new().unwrap();
let engine = Engine::open(dir.path(), Config::default()).unwrap();
engine.create_account("alice").unwrap();
let n = 50;
let entries: Vec<_> = (0..n)
.map(|i: u64| {
let mut key = [0u8; 32];
key[0..8].copy_from_slice(&i.to_le_bytes());
let value = format!("batch email {}", i).into_bytes();
(key, value, Codec::Zstd)
})
.collect();
engine.write_batch("alice", &entries).unwrap();
for (key, value, _) in &entries {
let result = engine.read("alice", key).unwrap();
assert_eq!(result.as_ref(), Some(value));
}
}
#[test]
fn test_batch_write_persistence() {
let dir = TempDir::new().unwrap();
let entries: Vec<_> = (0..30u64)
.map(|i| {
let mut key = [0u8; 32];
key[0..8].copy_from_slice(&i.to_le_bytes());
(key, format!("persist {}", i).into_bytes(), Codec::Zstd)
})
.collect();
{
let engine = Engine::open(dir.path(), Config::default()).unwrap();
engine.create_account("alice").unwrap();
engine.write_batch("alice", &entries).unwrap();
}
{
let engine = Engine::open(dir.path(), Config::default()).unwrap();
for (key, value, _) in &entries {
let result = engine.read("alice", key).unwrap();
assert_eq!(result.as_ref(), Some(value));
}
}
}
#[test]
fn test_invalid_config_rejected() {
let dir = TempDir::new().unwrap();
let mut config = Config::default();
config.lru_bucket_count = 0;
assert!(Engine::open(dir.path(), config).is_err());
let mut config = Config::default();
config.gc_deleted_ratio = 1.5;
assert!(Engine::open(dir.path(), config).is_err());
}