use chrono::Utc;
use hitbox_backend::composition::CompositionPolicy;
use hitbox_backend::composition::policy::{RaceReadPolicy, RefillPolicy};
use hitbox_backend::{CacheBackend, Compose};
use hitbox_core::{BoxContext, CacheContext, CacheKey, CacheValue};
use crate::common::{TestBackend, TestOffloadManager};
use super::nested::TestValue;
#[tokio::test]
async fn test_compose_trait_basic_usage() {
let l1 = TestBackend::new();
let l2 = TestBackend::new();
let cache = l1.clone().compose(l2.clone(), TestOffloadManager);
let key = CacheKey::from_slice(&[("test", Some("key1"))]);
let value = CacheValue::new(
TestValue {
data: "compose_api".to_string(),
},
Some(Utc::now() + chrono::Duration::seconds(60)),
None,
);
let mut ctx: BoxContext = CacheContext::default().boxed();
cache
.set::<TestValue>(&key, &value, &mut ctx)
.await
.unwrap();
let mut ctx: BoxContext = CacheContext::default().boxed();
let result = cache.get::<TestValue>(&key, &mut ctx).await.unwrap();
assert!(result.is_some());
assert_eq!(
*result.unwrap().data(),
TestValue {
data: "compose_api".to_string()
}
);
assert!(l1.has(&key));
assert!(l2.has(&key));
}
#[tokio::test]
async fn test_compose_with_custom_policy() {
let l1 = TestBackend::new();
let l2 = TestBackend::new();
let policy = CompositionPolicy::new()
.read(RaceReadPolicy::new())
.refill(RefillPolicy::Never);
let cache = l1
.clone()
.compose_with(l2.clone(), TestOffloadManager, policy);
let key = CacheKey::from_str("test", "custom_policy");
let value = CacheValue::new(
TestValue {
data: "custom_value".to_string(),
},
Some(Utc::now() + chrono::Duration::seconds(60)),
None,
);
let mut ctx: BoxContext = CacheContext::default().boxed();
l2.set::<TestValue>(&key, &value, &mut ctx).await.unwrap();
let mut ctx: BoxContext = CacheContext::default().boxed();
let result = cache.get::<TestValue>(&key, &mut ctx).await.unwrap();
assert!(result.is_some());
assert_eq!(
*result.unwrap().data(),
TestValue {
data: "custom_value".to_string()
}
);
assert!(!l1.has(&key));
}
#[tokio::test]
async fn test_compose_nested_3_levels() {
let l1 = TestBackend::new();
let l2 = TestBackend::new();
let l3 = TestBackend::new();
let cache = l1.clone().compose(
l2.clone().compose(l3.clone(), TestOffloadManager),
TestOffloadManager,
);
let key = CacheKey::from_str("test", "nested_compose");
let value = CacheValue::new(
TestValue {
data: "nested_value".to_string(),
},
Some(Utc::now() + chrono::Duration::seconds(60)),
None,
);
let mut ctx: BoxContext = CacheContext::default().boxed();
cache
.set::<TestValue>(&key, &value, &mut ctx)
.await
.unwrap();
assert!(l1.has(&key), "L1 should have the value");
assert!(l2.has(&key), "L2 should have the value");
assert!(l3.has(&key), "L3 should have the value");
let mut ctx: BoxContext = CacheContext::default().boxed();
let result = cache.get::<TestValue>(&key, &mut ctx).await.unwrap();
assert_eq!(
*result.unwrap().data(),
TestValue {
data: "nested_value".to_string()
}
);
}
#[tokio::test]
async fn test_compose_with_builder_chaining() {
let l1 = TestBackend::new();
let l2 = TestBackend::new();
let cache = l1
.clone()
.compose(l2.clone(), TestOffloadManager)
.read(RaceReadPolicy::new())
.refill(RefillPolicy::Never);
let key = CacheKey::from_str("test", "chained");
let value = CacheValue::new(
TestValue {
data: "chained_value".to_string(),
},
Some(Utc::now() + chrono::Duration::seconds(60)),
None,
);
let mut ctx: BoxContext = CacheContext::default().boxed();
l2.set::<TestValue>(&key, &value, &mut ctx).await.unwrap();
let mut ctx: BoxContext = CacheContext::default().boxed();
let result = cache.get::<TestValue>(&key, &mut ctx).await.unwrap();
assert_eq!(
*result.unwrap().data(),
TestValue {
data: "chained_value".to_string()
}
);
assert!(!l1.has(&key));
}