#![allow(deprecated)]
#[cfg(feature = "l2-redis")]
mod tests {
use oxcache::backend::l2::L2Backend;
use oxcache::client::l2::L2Client;
use oxcache::client::ttl_control::TtlControl;
use oxcache::client::two_level::TwoLevelClient;
use oxcache::config::L2Config;
use oxcache::{CacheExt, CacheOps};
use secrecy::SecretString;
use std::sync::Arc;
async fn get_test_l2_client() -> Arc<L2Client> {
let config = L2Config {
connection_string: SecretString::new("redis://127.0.0.1:6379".to_string()),
mode: oxcache::config::RedisMode::Standalone,
default_ttl: Some(300),
..Default::default()
};
let backend = Arc::new(
L2Backend::new(&config)
.await
.expect("Failed to create L2 backend"),
);
Arc::new(
L2Client::new(
"test_ttl_service".to_string(),
backend,
oxcache::serialization::SerializerEnum::Json(
oxcache::serialization::JsonSerializer::new(),
),
)
.await
.expect("Failed to create L2 client"),
)
}
async fn get_test_two_level_client() -> Arc<TwoLevelClient> {
use oxcache::backend::l1::L1Backend;
use oxcache::config::{L1Config, TwoLevelConfig};
let l1_config = L1Config {
max_capacity: 10000, ..Default::default()
};
let l1 = Arc::new(L1Backend::new(l1_config.max_capacity));
let l2_config = L2Config {
connection_string: SecretString::new("redis://127.0.0.1:6379".to_string()),
mode: oxcache::config::RedisMode::Standalone,
default_ttl: Some(300),
..Default::default()
};
let l2_backend = Arc::new(
L2Backend::new(&l2_config)
.await
.expect("Failed to create L2 backend"),
);
let two_level_config = TwoLevelConfig {
..Default::default()
};
Arc::new(
TwoLevelClient::new(
"test_ttl_service".to_string(),
two_level_config,
l1,
l2_backend,
oxcache::serialization::SerializerEnum::Json(
oxcache::serialization::JsonSerializer::new(),
),
)
.await
.expect("Failed to create TwoLevel client"),
)
}
#[tokio::test]
async fn test_get_l1_ttl_basic() {
let client = get_test_two_level_client().await;
let test_key = "oxcache:test:l1:ttl:get";
client.set(test_key, &"value", Some(300)).await.unwrap();
let ttl = client.get_l1_ttl(test_key).await.unwrap();
assert!(ttl.is_some());
assert!(ttl.unwrap() > 0);
assert!(ttl.unwrap() <= 300);
let ttl = client.get_l1_ttl("nonexistent_key").await.unwrap();
assert!(ttl.is_none());
let _ = client.delete(test_key).await;
}
#[tokio::test]
async fn test_get_l1_ttl_not_exists() {
let client = get_test_two_level_client().await;
let ttl = client
.get_l1_ttl("definitely_not_exists_key_12345")
.await
.unwrap();
assert!(ttl.is_none());
}
#[tokio::test]
async fn test_refresh_l1_ttl() {
let client = get_test_two_level_client().await;
let test_key = "oxcache:test:l1:ttl:refresh";
client.set(test_key, &"value", Some(60)).await.unwrap();
let result = client.refresh_l1_ttl(test_key, 600).await.unwrap();
assert!(result);
let ttl = client.get_l1_ttl(test_key).await.unwrap();
assert!(ttl.is_some());
assert!(ttl.unwrap() > 500);
let _ = client.delete(test_key).await;
}
#[tokio::test]
async fn test_refresh_l1_ttl_not_exists() {
let client = get_test_two_level_client().await;
let result = client.refresh_l1_ttl("nonexistent_key", 600).await.unwrap();
assert!(!result);
}
#[tokio::test]
async fn test_get_l2_ttl_basic() {
let client = get_test_l2_client().await;
let test_key = "oxcache:test:ttl:get";
client.set(test_key, &"value", Some(300)).await.unwrap();
let ttl = client.get_l2_ttl(test_key).await.unwrap();
assert!(ttl.is_some());
assert!(ttl.unwrap() > 0);
assert!(ttl.unwrap() <= 300);
let ttl = client.get_l2_ttl("nonexistent_key").await.unwrap();
assert!(ttl.is_none());
let _ = client.delete(test_key).await;
}
#[tokio::test]
async fn test_get_l2_ttl_not_exists() {
let client = get_test_l2_client().await;
let ttl = client
.get_l2_ttl("definitely_not_exists_key_12345")
.await
.unwrap();
assert!(ttl.is_none());
}
#[tokio::test]
async fn test_refresh_l2_ttl() {
let client = get_test_l2_client().await;
let test_key = "oxcache:test:ttl:refresh";
client.set(test_key, &"value", Some(60)).await.unwrap();
let result = client.refresh_l2_ttl(test_key, 600).await.unwrap();
assert!(result);
let ttl = client.get_l2_ttl(test_key).await.unwrap();
assert!(ttl.is_some());
assert!(ttl.unwrap() > 500);
let _ = client.delete(test_key).await;
}
#[tokio::test]
async fn test_refresh_l2_ttl_not_exists() {
let client = get_test_l2_client().await;
let result = client.refresh_l2_ttl("nonexistent_key", 600).await.unwrap();
assert!(!result);
}
#[tokio::test]
async fn test_touch_basic() {
let client = get_test_l2_client().await;
let test_key = "oxcache:test:touch:basic";
client.set(test_key, &"value", Some(120)).await.unwrap();
let initial_ttl = client.get_l2_ttl(test_key).await.unwrap();
assert!(initial_ttl.is_some());
let result = client.touch(test_key).await.unwrap();
assert!(result);
let new_ttl = client.get_l2_ttl(test_key).await.unwrap();
assert!(new_ttl.is_some());
let _ = client.delete(test_key).await;
}
#[tokio::test]
async fn test_touch_not_exists() {
let client = get_test_l2_client().await;
let result = client.touch("nonexistent_touch_key").await.unwrap();
assert!(!result);
}
#[tokio::test]
async fn test_get_ttl_l2_only() {
let client = get_test_l2_client().await;
let test_key = "oxcache:test:ttl:getttl";
client.set(test_key, &"value", Some(180)).await.unwrap();
let ttl = client.get_ttl(test_key).await.unwrap();
assert!(ttl.is_some());
assert!(ttl.unwrap() > 0);
assert!(ttl.unwrap() <= 180);
let _ = client.delete(test_key).await;
}
#[tokio::test]
async fn test_refresh_ttl() {
let client = get_test_l2_client().await;
let test_key = "oxcache:test:ttl:refresttl";
client.set(test_key, &"value", Some(60)).await.unwrap();
let result = client.refresh_ttl(test_key, 600).await.unwrap();
assert!(result);
let ttl = client.get_ttl(test_key).await.unwrap();
assert!(ttl.is_some());
assert!(ttl.unwrap() > 500);
let _ = client.delete(test_key).await;
}
#[tokio::test]
async fn test_ttl_expiration() {
let client = get_test_l2_client().await;
let test_key = "oxcache:test:ttl:expire";
client.set(test_key, &"temporary", Some(1)).await.unwrap();
let value: Option<String> = client.get(test_key).await.unwrap();
assert!(value.is_some());
assert_eq!(value.unwrap(), "temporary");
tokio::time::sleep(tokio::time::Duration::from_secs(2)).await;
let value: Option<String> = client.get(test_key).await.unwrap();
assert!(value.is_none());
let ttl = client.get_l2_ttl(test_key).await.unwrap();
assert!(ttl.is_none());
}
#[tokio::test]
async fn test_multiple_keys_ttl() {
let client = get_test_l2_client().await;
let test_prefix = "oxcache:test:ttl:multi";
for i in 1..=5 {
let key = format!("{}:{}", test_prefix, i);
let ttl = i * 60; client
.set(&key, &format!("value{}", i), Some(ttl))
.await
.unwrap();
}
for i in 1..=5 {
let key = format!("{}:{}", test_prefix, i);
let ttl = client.get_l2_ttl(&key).await.unwrap();
assert!(ttl.is_some());
let expected_min = (i * 60) - 10; assert!(ttl.unwrap() >= expected_min);
let _ = client.delete(&key).await;
}
}
#[tokio::test]
async fn test_l1_ttl_expiration() {
let client = get_test_two_level_client().await;
let test_key = "oxcache:test:l1:ttl:expire";
client.set(test_key, &"temporary", Some(1)).await.unwrap();
let value: Option<String> = client.get(test_key).await.unwrap();
assert!(value.is_some());
assert_eq!(value.unwrap(), "temporary");
tokio::time::sleep(tokio::time::Duration::from_secs(2)).await;
let value: Option<String> = client.get(test_key).await.unwrap();
assert!(value.is_none());
let ttl = client.get_l1_ttl(test_key).await.unwrap();
assert!(ttl.is_none());
}
#[tokio::test]
async fn test_l1_multiple_keys_ttl() {
let client = get_test_two_level_client().await;
let test_prefix = "oxcache:test:l1:ttl:multi";
for i in 1..=5 {
let key = format!("{}:{}", test_prefix, i);
let ttl = i * 60; client
.set(&key, &format!("value{}", i), Some(ttl))
.await
.unwrap();
}
for i in 1..=5 {
let key = format!("{}:{}", test_prefix, i);
let ttl = client.get_l1_ttl(&key).await.unwrap();
assert!(ttl.is_some());
let expected_min = (i * 60) - 10; assert!(ttl.unwrap() >= expected_min);
let _ = client.delete(&key).await;
}
}
#[tokio::test]
async fn test_l1_l2_ttl_consistency() {
let client = get_test_two_level_client().await;
let test_key = "oxcache:test:ttl:consistency";
client.set(test_key, &"value", Some(300)).await.unwrap();
let l1_ttl = client.get_l1_ttl(test_key).await.unwrap();
let l2_ttl = client.get_l2_ttl(test_key).await.unwrap();
assert!(l1_ttl.is_some());
assert!(l2_ttl.is_some());
let l1_value = l1_ttl.unwrap();
let l2_value = l2_ttl.unwrap();
let diff = (l1_value as i64 - l2_value as i64).abs();
assert!(diff < 10, "L1 and L2 TTL should be close");
let _ = client.delete(test_key).await;
}
#[tokio::test]
async fn test_refresh_both_ttls() {
let client = get_test_two_level_client().await;
let test_key = "oxcache:test:ttl:refresh_both";
client.set(test_key, &"value", Some(60)).await.unwrap();
let result = client.refresh_ttl(test_key, 600).await.unwrap();
assert!(result);
let l1_ttl = client.get_l1_ttl(test_key).await.unwrap();
assert!(l1_ttl.is_some());
assert!(l1_ttl.unwrap() > 500);
let l2_ttl = client.get_l2_ttl(test_key).await.unwrap();
assert!(l2_ttl.is_some());
assert!(l2_ttl.unwrap() > 500);
let _ = client.delete(test_key).await;
}
}