use fibre_cache::{AsyncCache, builder::CacheBuilder, policy::lru::LruPolicy};
use std::{sync::Arc, time::Duration};
fn new_test_cache(capacity: u64) -> AsyncCache<i32, String> {
CacheBuilder::new()
.capacity(capacity)
.shards(4) .cache_policy_factory(|| Box::new(LruPolicy::new()))
.janitor_tick_interval(Duration::from_millis(50))
.build_async()
.unwrap()
}
#[tokio::test]
#[cfg(feature = "bulk")]
async fn test_async_multi_insert_and_multiget() {
let cache = new_test_cache(100);
let items: Vec<_> = (0..20).map(|i| (i, i.to_string(), 1)).collect();
cache.multi_insert(items).await;
let metrics = cache.metrics();
assert_eq!(metrics.current_cost, 20);
let keys_to_get: Vec<_> = (0..20).collect();
let found = cache.multiget(keys_to_get.clone()).await;
assert_eq!(found.len(), 20, "Should find all inserted items");
for i in 0..20 {
assert_eq!(*found.get(&i).unwrap(), Arc::new(i.to_string()));
}
assert_eq!(cache.metrics().hits, 20);
assert_eq!(cache.metrics().misses, 0);
let mixed_keys: Vec<_> = (10..30).collect();
let found_mixed = cache.multiget(mixed_keys).await;
assert_eq!(
found_mixed.len(),
10,
"Should only find the 10 existing keys"
);
assert_eq!(cache.metrics().hits, 30); assert_eq!(cache.metrics().misses, 10); }
#[tokio::test]
#[cfg(feature = "bulk")]
async fn test_async_multi_invalidate() {
let cache = new_test_cache(100);
let items: Vec<_> = (0..20).map(|i| (i, i.to_string(), 1)).collect();
cache.multi_insert(items).await;
assert_eq!(cache.metrics().current_cost, 20);
let keys_to_invalidate: Vec<_> = (5..15).collect();
cache.multi_invalidate(keys_to_invalidate).await;
let metrics = cache.metrics();
assert_eq!(metrics.current_cost, 10, "Cost should be reduced by 10");
assert_eq!(metrics.invalidations, 10);
for i in 5..15 {
assert!(cache.fetch(&i).await.is_none());
}
for i in (0..5).chain(15..20) {
assert!(cache.fetch(&i).await.is_some());
}
}
#[tokio::test]
#[cfg(feature = "bulk")]
async fn test_async_multi_insert_triggers_eviction() {
use futures_util::StreamExt;
use tokio::time;
let cache = new_test_cache(10);
let items: Vec<_> = (0..15).map(|i| (i, i.to_string(), 1)).collect();
cache.multi_insert(items).await;
assert_eq!(cache.metrics().current_cost, 15);
let deadline = time::Instant::now() + Duration::from_secs(2);
let mut final_cost = 0;
loop {
final_cost = cache.metrics().current_cost;
if final_cost <= 10 {
break; }
if time::Instant::now() > deadline {
panic!(
"Cache cost did not converge to capacity in time. Final cost: {}",
final_cost
);
}
time::sleep(Duration::from_millis(50)).await;
}
assert!(
final_cost <= 10,
"Janitor should bring cost to at or below capacity. Final cost: {}",
final_cost
);
assert!(
cache.metrics().evicted_by_capacity >= 5,
"Janitor should evict at least 5 items"
);
let mut total_keys = 0;
let mut stream = cache.iter_stream();
while let Some(_) = stream.next().await {
total_keys += 1;
}
assert_eq!(
total_keys as u64, final_cost,
"The number of items in the cache should equal the final cost"
);
}