extern crate oxcache;
use crate::common;
use oxcache::cached;
use oxcache::Cache;
use serde::{Deserialize, Serialize};
use serial_test::serial;
use std::time::Duration;
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
struct User {
id: u64,
name: String,
}
async fn setup_macro_env() -> Cache<String, Vec<u8>> {
if common::is_redis_available().await {
Cache::tiered(100, "redis://127.0.0.1:6379")
.await
.expect("Failed to create tiered cache")
} else {
panic!("Redis not available");
}
}
#[cached(service = "user_cache", ttl = 300)]
async fn get_user(id: u64) -> Result<User, String> {
tokio::time::sleep(Duration::from_millis(50)).await;
Ok(User {
id,
name: format!("User{}", id),
})
}
#[tokio::test]
#[serial]
async fn test_cached_macro_basic() {
if !common::is_redis_available().await {
println!("跳过 test_cached_macro_basic: Redis不可用");
return;
}
let cache = setup_macro_env().await;
cache.register_for_macro("user_cache").await;
let start = std::time::Instant::now();
let user = get_user(1).await.unwrap();
let duration = start.elapsed();
assert_eq!(user.id, 1);
assert!(duration >= Duration::from_millis(0));
let start = std::time::Instant::now();
let user = get_user(1).await.unwrap();
let duration = start.elapsed();
assert_eq!(user.id, 1);
assert!(duration < Duration::from_millis(10));
}
#[cached(service = "user_cache", key = "custom_user_{id}")]
async fn get_user_custom_key(id: u64) -> Result<User, String> {
Ok(User {
id,
name: "Custom".to_string(),
})
}
#[tokio::test]
#[serial]
async fn test_cached_macro_custom_key() {
if !common::is_redis_available().await {
println!("跳过 test_cached_macro_custom_key: Redis不可用");
return;
}
let cache = setup_macro_env().await;
cache.register_for_macro("user_cache").await;
let user = get_user_custom_key(99).await.unwrap();
assert_eq!(user.name, "Custom");
let user2 = get_user_custom_key(99).await.unwrap();
assert_eq!(user2.name, "Custom");
assert_eq!(user2.id, 99);
}
#[cached(service = "user_cache", cache_type = "l1-only", ttl = 30)]
async fn get_user_l1_only(id: u64) -> Result<User, String> {
tokio::time::sleep(Duration::from_millis(10)).await;
Ok(User {
id,
name: format!("L1User{}", id),
})
}
#[cached(service = "user_cache", cache_type = "l2-only", ttl = 30)]
async fn get_user_l2_only(id: u64) -> Result<User, String> {
tokio::time::sleep(Duration::from_millis(10)).await;
Ok(User {
id,
name: format!("L2User{}", id),
})
}
#[tokio::test]
#[serial]
async fn test_cached_macro_with_cache_type() {
if !common::is_redis_available().await {
println!("跳过 test_cached_macro_with_cache_type: Redis不可用");
return;
}
let cache = setup_macro_env().await;
cache.register_for_macro("user_cache").await;
let user1 = get_user_l1_only(100).await.unwrap();
assert_eq!(user1.name, "L1User100");
let user2 = get_user_l2_only(200).await.unwrap();
assert_eq!(user2.name, "L2User200");
let start = std::time::Instant::now();
let user1_cached = get_user_l1_only(100).await.unwrap();
let duration_l1 = start.elapsed();
let start = std::time::Instant::now();
let user2_cached = get_user_l2_only(200).await.unwrap();
let duration_l2 = start.elapsed();
assert!(
duration_l1 < Duration::from_millis(50),
"L1 cache should be fast"
);
assert!(
duration_l2 < Duration::from_millis(50),
"L2 cache should be fast"
);
assert_eq!(user1_cached.name, "L1User100");
assert_eq!(user2_cached.name, "L2User200");
}