#![cfg(feature = "encryption")]
#[cfg(feature = "var-collections")]
use armdb::VarTree;
use armdb::{Config, ConstTree, DbError};
use tempfile::tempdir;
fn encrypted_config(key: [u8; 32]) -> Config {
let mut config = Config::test();
config.encryption_key = Some(key);
config
}
#[test]
fn test_encrypted_const_tree_basic() {
let dir = tempdir().unwrap();
let key = [0x42u8; 32];
let tree = ConstTree::<[u8; 8], 8>::open(dir.path(), encrypted_config(key)).unwrap();
for i in 0..100u64 {
let k = i.to_be_bytes();
let v = (i * 10).to_be_bytes();
tree.put(&k, &v).unwrap();
}
for i in 0..100u64 {
let k = i.to_be_bytes();
let expected = (i * 10).to_be_bytes();
assert_eq!(tree.get(&k).unwrap(), expected);
}
let k = 50u64.to_be_bytes();
tree.delete(&k).unwrap();
assert!(tree.get(&k).is_none());
assert_eq!(tree.len(), 99);
}
#[test]
fn test_encrypted_recovery() {
let dir = tempdir().unwrap();
let key = [0x42u8; 32];
{
let tree = ConstTree::<[u8; 8], 8>::open(dir.path(), encrypted_config(key)).unwrap();
for i in 0..100u64 {
let k = i.to_be_bytes();
let v = (i * 10).to_be_bytes();
tree.put(&k, &v).unwrap();
}
tree.close().unwrap();
}
{
let tree = ConstTree::<[u8; 8], 8>::open(dir.path(), encrypted_config(key)).unwrap();
assert_eq!(tree.len(), 100);
for i in 0..100u64 {
let k = i.to_be_bytes();
let expected = (i * 10).to_be_bytes();
assert_eq!(
tree.get(&k).unwrap(),
expected,
"encrypted recovery mismatch at key {}",
i
);
}
}
}
#[test]
fn test_encrypted_wrong_key_fails() {
let dir = tempdir().unwrap();
let key_a = [0x42u8; 32];
let key_b = [0x99u8; 32];
{
let tree = ConstTree::<[u8; 8], 8>::open(dir.path(), encrypted_config(key_a)).unwrap();
for i in 0..50u64 {
let k = i.to_be_bytes();
let v = i.to_be_bytes();
tree.put(&k, &v).unwrap();
}
tree.close().unwrap();
}
let result = ConstTree::<[u8; 8], 8>::open(dir.path(), encrypted_config(key_b));
assert!(result.is_err(), "opening with wrong key should fail");
}
#[test]
fn test_encrypted_no_key_fails() {
let dir = tempdir().unwrap();
let key = [0x42u8; 32];
{
let tree = ConstTree::<[u8; 8], 8>::open(dir.path(), encrypted_config(key)).unwrap();
tree.put(&1u64.to_be_bytes(), &1u64.to_be_bytes()).unwrap();
tree.close().unwrap();
}
let result = ConstTree::<[u8; 8], 8>::open(dir.path(), Config::test());
assert!(
matches!(&result, Err(DbError::Config(_))),
"opening encrypted db without key should return Config error, got {:?}",
result.as_ref().err()
);
}
#[test]
fn test_unencrypted_with_key_fails() {
let dir = tempdir().unwrap();
{
let tree = ConstTree::<[u8; 8], 8>::open(dir.path(), Config::test()).unwrap();
tree.put(&1u64.to_be_bytes(), &1u64.to_be_bytes()).unwrap();
tree.close().unwrap();
}
let key = [0x42u8; 32];
let result = ConstTree::<[u8; 8], 8>::open(dir.path(), encrypted_config(key));
assert!(
matches!(&result, Err(DbError::Config(_))),
"opening unencrypted db with key should return Config error, got {:?}",
result.as_ref().err()
);
}
#[test]
fn test_encrypted_compaction() {
let dir = tempdir().unwrap();
let key = [0x42u8; 32];
let mut config = encrypted_config(key);
config.max_file_size = 4096;
config.compaction_threshold = 0.1;
let tree = ConstTree::<[u8; 8], 8>::open(dir.path(), config).unwrap();
for i in 0..500u64 {
let k = i.to_be_bytes();
let v = i.to_be_bytes();
tree.put(&k, &v).unwrap();
}
for i in 0..250u64 {
let k = i.to_be_bytes();
let v = (i + 1000).to_be_bytes();
tree.put(&k, &v).unwrap();
}
tree.compact().unwrap();
for i in 0..500u64 {
let k = i.to_be_bytes();
let expected = if i < 250 {
(i + 1000).to_be_bytes()
} else {
i.to_be_bytes()
};
assert_eq!(
tree.get(&k).unwrap(),
expected,
"encrypted compaction mismatch at key {}",
i
);
}
}
#[cfg(feature = "var-collections")]
#[test]
fn test_encrypted_var_tree() {
let dir = tempdir().unwrap();
let key = [0x42u8; 32];
let tree = VarTree::<[u8; 8]>::open(dir.path(), encrypted_config(key)).unwrap();
for i in 0..100u64 {
let k = i.to_be_bytes();
let v = format!("encrypted_val_{i}");
tree.put(&k, v.as_bytes()).unwrap();
}
for i in 0..100u64 {
let k = i.to_be_bytes();
let expected = format!("encrypted_val_{i}");
assert_eq!(tree.get(&k).unwrap().as_ref(), expected.as_bytes());
}
tree.delete(&50u64.to_be_bytes()).unwrap();
assert!(tree.get(&50u64.to_be_bytes()).is_none());
assert_eq!(tree.len(), 99);
}