use do_memory_storage_redb::{AdaptiveCache, AdaptiveCacheConfig};
use std::time::Duration;
use uuid::Uuid;
#[tokio::test]
async fn test_adaptive_cache_ttl_increase_for_hot_items() {
let config = AdaptiveCacheConfig {
max_size: 100,
default_ttl: Duration::from_secs(60),
min_ttl: Duration::from_secs(10),
max_ttl: Duration::from_secs(300),
hot_threshold: 3,
cold_threshold: 1,
adaptation_rate: 0.5, window_size: 10,
cleanup_interval_secs: 0,
enable_background_cleanup: false,
};
let cache = AdaptiveCache::<String>::new(config);
let id = Uuid::new_v4();
cache
.record_access(id, false, Some("value".to_string()))
.await;
let initial_ttl = cache.ttl(id).await.expect("Should have TTL");
assert_eq!(initial_ttl, Duration::from_secs(60));
for _ in 0..5 {
cache.record_access(id, true, None).await;
}
let hot_ttl = cache.ttl(id).await.expect("Should have TTL");
assert!(
hot_ttl > initial_ttl,
"Hot item TTL ({:?}) should be greater than initial ({:?})",
hot_ttl,
initial_ttl
);
}
#[tokio::test]
async fn test_adaptive_cache_ttl_decrease_for_cold_items() {
let config = AdaptiveCacheConfig {
max_size: 100,
default_ttl: Duration::from_secs(60),
min_ttl: Duration::from_secs(10),
max_ttl: Duration::from_secs(300),
hot_threshold: 10,
cold_threshold: 1, adaptation_rate: 0.3,
window_size: 10,
cleanup_interval_secs: 0,
enable_background_cleanup: false,
};
let cache = AdaptiveCache::<String>::new(config);
let id = Uuid::new_v4();
cache
.record_access(id, false, Some("value".to_string()))
.await;
cache.record_access(id, true, None).await;
let cold_ttl = cache.ttl(id).await.expect("Should have TTL");
assert!(
cold_ttl < Duration::from_secs(60),
"Cold item TTL ({:?}) should be less than default (60s)",
cold_ttl
);
}
#[tokio::test]
async fn test_adaptive_cache_ttl_max_bound() {
let config = AdaptiveCacheConfig {
max_size: 100,
default_ttl: Duration::from_secs(60),
min_ttl: Duration::from_secs(10),
max_ttl: Duration::from_secs(100), hot_threshold: 2,
cold_threshold: 0,
adaptation_rate: 0.5,
window_size: 10,
cleanup_interval_secs: 0,
enable_background_cleanup: false,
};
let cache = AdaptiveCache::<String>::new(config);
let id = Uuid::new_v4();
cache
.record_access(id, false, Some("value".to_string()))
.await;
for _ in 0..20 {
cache.record_access(id, true, None).await;
}
let ttl = cache.ttl(id).await.expect("Should have TTL");
assert!(
ttl <= Duration::from_secs(100),
"TTL ({:?}) should not exceed max_ttl (100s)",
ttl
);
}
#[tokio::test]
async fn test_adaptive_cache_ttl_min_bound() {
let config = AdaptiveCacheConfig {
max_size: 100,
default_ttl: Duration::from_secs(60),
min_ttl: Duration::from_secs(30), max_ttl: Duration::from_secs(300),
hot_threshold: 100, cold_threshold: 10, adaptation_rate: 0.5,
window_size: 10,
cleanup_interval_secs: 0,
enable_background_cleanup: false,
};
let cache = AdaptiveCache::<String>::new(config);
let id = Uuid::new_v4();
cache
.record_access(id, false, Some("value".to_string()))
.await;
for _ in 0..5 {
cache.record_access(id, true, None).await;
}
let ttl = cache.ttl(id).await.expect("Should have TTL");
assert!(
ttl >= Duration::from_secs(30),
"TTL ({:?}) should not go below min_ttl (30s)",
ttl
);
}
#[tokio::test]
async fn test_adaptive_cache_window_overflow() {
let config = AdaptiveCacheConfig {
max_size: 100,
default_ttl: Duration::from_secs(60),
min_ttl: Duration::from_secs(10),
max_ttl: Duration::from_secs(300),
hot_threshold: 3,
cold_threshold: 1,
adaptation_rate: 0.25,
window_size: 5, cleanup_interval_secs: 0,
enable_background_cleanup: false,
};
let cache = AdaptiveCache::<String>::new(config);
let id = Uuid::new_v4();
cache
.record_access(id, false, Some("value".to_string()))
.await;
for _ in 0..10 {
cache.record_access(id, true, None).await;
}
let access_count = cache.access_count(id).await;
assert_eq!(access_count, Some(10));
let hot_count = cache.hot_count().await;
assert!(hot_count > 0, "Should have hot items");
}
#[tokio::test]
async fn test_adaptive_cache_multiple_hot_cold_items() {
let config = AdaptiveCacheConfig {
max_size: 100,
default_ttl: Duration::from_secs(60),
min_ttl: Duration::from_secs(10),
max_ttl: Duration::from_secs(300),
hot_threshold: 5,
cold_threshold: 1,
adaptation_rate: 0.25,
window_size: 10,
cleanup_interval_secs: 0,
enable_background_cleanup: false,
};
let cache = AdaptiveCache::<String>::new(config);
let hot_id = Uuid::new_v4();
cache
.record_access(hot_id, false, Some("hot".to_string()))
.await;
for _ in 0..10 {
cache.record_access(hot_id, true, None).await;
}
let cold_id = Uuid::new_v4();
cache
.record_access(cold_id, false, Some("cold".to_string()))
.await;
let neutral_id = Uuid::new_v4();
cache
.record_access(neutral_id, false, Some("neutral".to_string()))
.await;
for _ in 0..3 {
cache.record_access(neutral_id, true, None).await;
}
let metrics = cache.get_metrics().await;
assert!(metrics.hot_item_count >= 1, "Should have hot items");
assert!(metrics.cold_item_count >= 1, "Should have cold items");
assert_eq!(metrics.base.item_count, 3);
}