use oxcache::backend::interface::{CacheConnector, CacheReader, CacheWriter};
use oxcache::backend::memory::dashmap::{
dashmap_memory, dashmap_memory_with_capacity, dashmap_memory_with_capacity_and_ttl, DashMapBackendBuilder,
DashMapMemoryBackend,
};
use oxcache::backend::score::BackendScore;
use std::time::Duration;
async fn poll_until<F, Fut>(timeout: Duration, interval: Duration, f: F) -> bool
where
F: Fn() -> Fut,
Fut: std::future::Future<Output = bool>,
{
let start = std::time::Instant::now();
while start.elapsed() < timeout {
if f().await {
return true;
}
tokio::time::sleep(interval).await;
}
false
}
#[tokio::test]
async fn test_dashmap_new_default_state() {
let backend = DashMapMemoryBackend::new();
assert!(backend.capacity() > 0);
assert!(backend.is_empty().await.unwrap());
}
#[tokio::test]
async fn test_dashmap_builder_default() {
let backend = DashMapBackendBuilder::default().build();
assert!(backend.capacity() > 0);
}
#[tokio::test]
async fn test_dashmap_builder_with_capacity_custom() {
let backend = DashMapBackendBuilder::default().capacity(5000).build();
assert_eq!(backend.capacity(), 5000);
}
#[tokio::test]
async fn test_dashmap_builder_with_ttl_default_ttl() {
let backend = DashMapBackendBuilder::default()
.capacity(1000)
.default_ttl(Duration::from_secs(60))
.build();
assert_eq!(backend.capacity(), 1000);
}
#[tokio::test]
async fn test_dashmap_set_and_get_basic_roundtrip() {
let backend = DashMapMemoryBackend::new();
backend.set("key1", b"value1".to_vec(), None).await.unwrap();
let value = backend.get("key1").await.unwrap();
assert_eq!(value, Some(b"value1".to_vec()));
}
#[tokio::test]
async fn test_dashmap_get_nonexistent_returns_none() {
let backend = DashMapMemoryBackend::new();
let value = backend.get("nonexistent").await.unwrap();
assert!(value.is_none());
}
#[tokio::test]
async fn test_dashmap_delete_removes_key() {
let backend = DashMapMemoryBackend::new();
backend.set("key1", b"value1".to_vec(), None).await.unwrap();
assert!(backend.exists("key1").await.unwrap());
backend.delete("key1").await.unwrap();
assert!(!backend.exists("key1").await.unwrap());
}
#[tokio::test]
async fn test_dashmap_exists_checks_key_presence() {
let backend = DashMapMemoryBackend::new();
assert!(!backend.exists("key1").await.unwrap());
backend.set("key1", b"value1".to_vec(), None).await.unwrap();
assert!(backend.exists("key1").await.unwrap());
}
#[tokio::test]
async fn test_dashmap_clear_empties_all() {
let backend = DashMapMemoryBackend::new();
backend.set("key1", b"value1".to_vec(), None).await.unwrap();
backend.set("key2", b"value2".to_vec(), None).await.unwrap();
backend.clear().await.unwrap();
assert!(backend.is_empty().await.unwrap());
assert!(!backend.exists("key1").await.unwrap());
assert!(!backend.exists("key2").await.unwrap());
}
#[tokio::test]
async fn test_dashmap_close_shutdown_empties() {
let backend = DashMapMemoryBackend::new();
backend.set("key1", b"value1".to_vec(), None).await.unwrap();
backend.shutdown().await;
assert!(backend.is_empty().await.unwrap());
}
#[tokio::test]
async fn test_dashmap_ttl_returns_remaining() {
let backend = DashMapMemoryBackend::new();
backend
.set("key1", b"value1".to_vec(), Some(Duration::from_secs(60)))
.await
.unwrap();
let ttl = backend.ttl("key1").await.unwrap();
assert!(ttl.is_some());
assert!(ttl.unwrap() <= Duration::from_secs(60));
}
#[tokio::test]
async fn test_dashmap_ttl_nonexistent_returns_none() {
let backend = DashMapMemoryBackend::new();
let ttl = backend.ttl("nonexistent").await.unwrap();
assert!(ttl.is_none());
}
#[tokio::test]
async fn test_dashmap_expire_sets_ttl() {
let backend = DashMapMemoryBackend::new();
backend.set("key1", b"value1".to_vec(), None).await.unwrap();
let ttl_before = backend.ttl("key1").await.unwrap();
assert!(ttl_before.is_none());
let result = backend.expire("key1", Duration::from_secs(30)).await.unwrap();
assert!(result);
let ttl_after = backend.ttl("key1").await.unwrap();
assert!(ttl_after.is_some());
}
#[tokio::test]
async fn test_dashmap_expire_nonexistent_returns_false() {
let backend = DashMapMemoryBackend::new();
let result = backend.expire("nonexistent", Duration::from_secs(30)).await.unwrap();
assert!(!result);
}
#[tokio::test]
async fn test_dashmap_health_check_returns_ok() {
let backend = DashMapMemoryBackend::new();
backend.health_check().await.unwrap();
}
#[tokio::test]
async fn test_dashmap_stats_returns_metrics() {
let backend = DashMapMemoryBackend::new();
backend.set("key1", b"value1".to_vec(), None).await.unwrap();
backend.get("key1").await.unwrap();
backend.get("nonexistent").await.unwrap();
let stats = backend.stats().await.unwrap();
assert_eq!(stats.get("type"), Some(&"dashmap".to_string()));
assert!(stats.contains_key("capacity"));
assert!(stats.contains_key("entry_count"));
assert!(stats.contains_key("hits"));
assert!(stats.contains_key("misses"));
assert!(stats.contains_key("hit_rate"));
}
#[tokio::test]
async fn test_dashmap_len_tracks_count() {
let backend = DashMapMemoryBackend::new();
assert_eq!(backend.len().await.unwrap(), 0);
backend.set("key1", b"value1".to_vec(), None).await.unwrap();
assert_eq!(backend.len().await.unwrap(), 1);
backend.set("key2", b"value2".to_vec(), None).await.unwrap();
assert_eq!(backend.len().await.unwrap(), 2);
backend.delete("key1").await.unwrap();
assert_eq!(backend.len().await.unwrap(), 1);
}
#[tokio::test]
async fn test_dashmap_capacity_method_returns_positive() {
let backend = DashMapMemoryBackend::new();
let capacity = backend.capacity();
assert!(capacity > 0);
}
#[test]
fn test_dashmap_hit_rate_empty() {
let backend = DashMapMemoryBackend::new();
assert_eq!(backend.hit_rate(), 0.0);
}
#[tokio::test]
async fn test_dashmap_hit_rate_with_hits() {
let backend = DashMapMemoryBackend::new();
backend.set("key1", b"value1".to_vec(), None).await.unwrap();
backend.get("key1").await.unwrap();
backend.get("key1").await.unwrap();
backend.get("nonexistent").await.unwrap();
let hit_rate = backend.hit_rate();
assert!(hit_rate > 0.0 && hit_rate <= 1.0);
}
#[test]
fn test_dashmap_entry_count_initial_zero() {
let backend = DashMapMemoryBackend::new();
assert_eq!(backend.entry_count(), 0);
}
#[test]
fn test_dashmap_backend_score_returns_positive() {
let backend = DashMapMemoryBackend::new();
assert!(backend.score() > 0);
assert!(!backend.is_persistent());
assert_eq!(backend.backend_name(), "dashmap");
}
#[test]
fn test_dashmap_clone_copies_capacity() {
let backend1 = DashMapMemoryBackend::new();
let backend2 = backend1.clone();
assert_eq!(backend1.capacity(), backend2.capacity());
}
#[test]
fn test_dashmap_debug_includes_name() {
let backend = DashMapMemoryBackend::new();
let debug_str = format!("{:?}", backend);
assert!(debug_str.contains("DashMapMemoryBackend"));
}
#[test]
fn test_convenience_dashmap_memory_default_has_capacity() {
let backend = dashmap_memory();
assert!(backend.capacity() > 0);
}
#[test]
fn test_convenience_dashmap_memory_with_capacity_custom() {
let backend = dashmap_memory_with_capacity(2000);
assert_eq!(backend.capacity(), 2000);
}
#[test]
fn test_convenience_dashmap_memory_with_capacity_and_ttl_custom() {
let backend = dashmap_memory_with_capacity_and_ttl(3000, Duration::from_secs(120));
assert_eq!(backend.capacity(), 3000);
}
#[tokio::test]
async fn test_dashmap_overwrite_replaces_value() {
let backend = DashMapMemoryBackend::new();
backend.set("key1", b"value1".to_vec(), None).await.unwrap();
backend.set("key1", b"value2".to_vec(), None).await.unwrap();
let value = backend.get("key1").await.unwrap();
assert_eq!(value, Some(b"value2".to_vec()));
}
#[tokio::test]
async fn test_dashmap_large_value_handles_1mb() {
let backend = DashMapMemoryBackend::new();
let large_value = vec![0u8; 1024 * 1024];
backend.set("large_key", large_value.clone(), None).await.unwrap();
let value = backend.get("large_key").await.unwrap();
assert_eq!(value, Some(large_value));
}
#[tokio::test]
async fn test_dashmap_many_keys_handles_100() {
let backend = DashMapMemoryBackend::builder().capacity(1000).build();
for i in 0..100 {
let key = format!("key_{}", i);
let value = format!("value_{}", i);
backend.set(&key, value.as_bytes().to_vec(), None).await.unwrap();
}
assert_eq!(backend.len().await.unwrap(), 100);
for i in 0..100 {
let key = format!("key_{}", i);
let expected = format!("value_{}", i);
let value = backend.get(&key).await.unwrap();
assert_eq!(value, Some(expected.as_bytes().to_vec()));
}
}
#[tokio::test]
async fn test_dashmap_ttl_expiration_evicts_after_ttl() {
let backend = DashMapMemoryBackend::new();
backend
.set("key1", b"value1".to_vec(), Some(Duration::from_millis(50)))
.await
.unwrap();
assert!(backend.get("key1").await.unwrap().is_some());
assert!(
poll_until(Duration::from_millis(500), Duration::from_millis(10), || async {
backend.get("key1").await.unwrap().is_none()
})
.await
);
}
#[tokio::test]
async fn test_dashmap_default_ttl_evicts_after_default() {
let backend = DashMapMemoryBackend::builder()
.default_ttl(Duration::from_millis(100))
.build();
backend.set("key1", b"value1".to_vec(), None).await.unwrap();
assert!(backend.get("key1").await.unwrap().is_some());
assert!(
poll_until(Duration::from_millis(500), Duration::from_millis(10), || async {
backend.get("key1").await.unwrap().is_none()
})
.await
);
}