use rkvs::{
ManagerAutosaveConfig, NamespaceAutosaveConfig, NamespaceConfig, Result, StorageConfig,
StorageManager,
};
use std::time::Duration;
use tempfile::tempdir;
#[tokio::test]
async fn test_save_and_load_manager_snapshot() -> Result<()> {
let temp_dir = tempdir()?;
let persistence_path = temp_dir.path().to_path_buf();
let snapshot_filename = "test_full_snapshot.bin";
let ns1_name = "users";
let ns1_key = "user:1";
let ns1_value = b"Alice";
let ns2_name = "products";
let ns2_key = "product:xyz";
let ns2_value = b"Widget";
{
let original_storage_config = StorageConfig {
max_namespaces: Some(10),
manager_autosave: Some(ManagerAutosaveConfig {
interval: Duration::from_secs(300),
filename: "autosave_manager.bin".to_string(),
}),
namespace_autosave: vec![NamespaceAutosaveConfig {
namespace_name: ns1_name.to_string(), interval: Duration::from_secs(60),
filename_pattern: "autosave_ns1.bin".to_string(),
}],
};
let storage1 = StorageManager::builder()
.with_config(original_storage_config.clone()) .with_persistence(persistence_path.clone())
.build()
.await?;
storage1.initialize(None).await?;
let ns1_config = NamespaceConfig::default();
ns1_config.set_shard_count(2);
storage1
.create_namespace(ns1_name, Some(ns1_config))
.await?;
let ns2_config = NamespaceConfig::default();
ns2_config.set_shard_count(4);
storage1
.create_namespace(ns2_name, Some(ns2_config))
.await?;
let namespace1 = storage1.namespace(ns1_name).await?;
namespace1.set(ns1_key, ns1_value.to_vec()).await?;
let namespace2 = storage1.namespace(ns2_name).await?;
namespace2.set(ns2_key, ns2_value.to_vec()).await?;
assert_eq!(
namespace1.get(ns1_key).await.map(|v| (*v).clone()),
Some(ns1_value.to_vec())
);
assert_eq!(
namespace2.get(ns2_key).await.map(|v| (*v).clone()),
Some(ns2_value.to_vec())
);
storage1.save_all(snapshot_filename).await?;
let storage2 = StorageManager::builder()
.with_persistence(persistence_path.clone())
.build()
.await?;
storage2.initialize(Some(snapshot_filename)).await?;
let loaded_storage_config = storage2.get_config().await;
assert_eq!(loaded_storage_config, original_storage_config);
let loaded_ns1 = storage2.namespace(ns1_name).await?;
assert_eq!(
loaded_ns1.get(ns1_key).await.map(|v| (*v).clone()),
Some(ns1_value.to_vec())
);
let loaded_ns2 = storage2.namespace(ns2_name).await?;
assert_eq!(
loaded_ns2.get(ns2_key).await.map(|v| (*v).clone()),
Some(ns2_value.to_vec())
);
let loaded_ns1_config = loaded_ns1.get_config().await;
assert_eq!(loaded_ns1_config.shard_count(), 2);
let loaded_ns2_config = loaded_ns2.get_config().await;
assert_eq!(loaded_ns2_config.shard_count(), 4);
}
Ok(())
}
#[tokio::test]
async fn test_save_and_load_single_namespace_snapshot() -> Result<()> {
let temp_dir = tempdir()?;
let persistence_path = temp_dir.path().to_path_buf();
let ns_snapshot_filename = "test_single_ns_snapshot.bin";
let ns1_name = "namespace_to_save";
let ns1_key = "data_key_1";
let ns1_value = b"Value for NS1";
let ns2_name = "other_namespace";
let ns2_key = "data_key_2";
let ns2_value = b"Value for NS2 (should not be loaded)";
{
let storage1 = StorageManager::builder()
.with_persistence(persistence_path.clone())
.build()
.await?;
storage1.initialize(None).await?;
let ns1_config = NamespaceConfig::default();
ns1_config.set_shard_count(3);
storage1
.create_namespace(ns1_name, Some(ns1_config))
.await?;
let namespace1 = storage1.namespace(ns1_name).await?;
namespace1.set(ns1_key, ns1_value.to_vec()).await?;
let ns2_config = NamespaceConfig::default();
ns2_config.set_shard_count(5);
storage1
.create_namespace(ns2_name, Some(ns2_config))
.await?;
let namespace2 = storage1.namespace(ns2_name).await?;
namespace2.set(ns2_key, ns2_value.to_vec()).await?;
assert_eq!(
namespace1.get(ns1_key).await.map(|v| (*v).clone()),
Some(ns1_value.to_vec())
);
assert_eq!(
namespace2.get(ns2_key).await.map(|v| (*v).clone()),
Some(ns2_value.to_vec())
);
storage1
.save_namespace(ns1_name, ns_snapshot_filename)
.await?;
}
{
let storage2 = StorageManager::builder()
.with_persistence(persistence_path.clone())
.build()
.await?;
storage2.initialize(None).await?;
assert!(storage2.namespace(ns1_name).await.is_err());
assert!(storage2.namespace(ns2_name).await.is_err());
let loaded_name = storage2.load_namespace(ns_snapshot_filename).await?;
assert_eq!(loaded_name, ns1_name);
let loaded_ns1 = storage2.namespace(ns1_name).await?;
assert_eq!(
loaded_ns1.get(ns1_key).await.map(|v| (*v).clone()),
Some(ns1_value.to_vec())
);
assert_eq!(loaded_ns1.get_config().await.shard_count(), 3);
assert!(storage2.namespace(ns2_name).await.is_err());
}
Ok(())
}
#[tokio::test]
async fn test_load_namespace_with_new_name() -> Result<()> {
let temp_dir = tempdir()?;
let persistence_path = temp_dir.path().to_path_buf();
let snapshot_filename = "base_snapshot.bin";
let original_ns_name = "original_namespace";
let key = "test_key";
let value = b"test_value";
let new_name_1 = "clone_1";
let new_name_2 = "clone_2";
{
let storage1 = StorageManager::builder()
.with_persistence(persistence_path.clone())
.build()
.await?;
storage1.initialize(None).await?;
let ns_config = NamespaceConfig::default();
ns_config.set_shard_count(2);
storage1
.create_namespace(original_ns_name, Some(ns_config))
.await?;
let namespace = storage1.namespace(original_ns_name).await?;
namespace.set(key, value.to_vec()).await?;
storage1
.save_namespace(original_ns_name, snapshot_filename)
.await?;
}
{
let storage2 = StorageManager::builder()
.with_persistence(persistence_path.clone())
.build()
.await?;
storage2.initialize(None).await?;
let loaded_name_1 = storage2
.load_namespace_with_name(snapshot_filename, new_name_1)
.await?;
assert_eq!(loaded_name_1, new_name_1);
let loaded_name_2 = storage2
.load_namespace_with_name(snapshot_filename, new_name_2)
.await?;
assert_eq!(loaded_name_2, new_name_2);
assert!(storage2.namespace(original_ns_name).await.is_err());
let ns1 = storage2.namespace(new_name_1).await?;
assert_eq!(
ns1.get(key).await.map(|v| (*v).clone()),
Some(value.to_vec())
);
assert_eq!(ns1.get_config().await.shard_count(), 2);
let ns2 = storage2.namespace(new_name_2).await?;
assert_eq!(
ns2.get(key).await.map(|v| (*v).clone()),
Some(value.to_vec())
);
assert_eq!(ns2.get_config().await.shard_count(), 2);
}
Ok(())
}