use oxcache::backend::memory::RedisBackend;
use oxcache::backend::{CacheReader, CacheWriter};
use std::time::{Duration, Instant};
fn get_redis_url() -> String {
std::env::var("REDIS_URL").unwrap_or_else(|_| "redis://127.0.0.1:6379".to_string())
}
fn generate_test_data(count: usize) -> Vec<(String, Vec<u8>, Option<Duration>)> {
(0..count)
.map(|i| {
(
format!("perf_test_key_{}", i),
format!("perf_test_value_{}", i).into_bytes(),
Some(Duration::from_secs(60)),
)
})
.collect()
}
#[tokio::test]
#[ignore = "性能测试需要 Redis 环境,使用 cargo test -- --ignored 运行"]
async fn test_pipeline_set_performance() {
let redis_url = get_redis_url();
let backend = RedisBackend::new(&redis_url)
.await
.expect("Failed to create Redis backend");
backend.clear().await.ok();
let test_data = generate_test_data(100);
let start = Instant::now();
backend.set_many(&test_data).await.expect("Pipeline SET failed");
let pipeline_duration = start.elapsed();
backend.clear().await.ok();
let start = Instant::now();
for (key, value, ttl) in &test_data {
backend
.set(key, value.clone(), *ttl)
.await
.expect("Individual SET failed");
}
let individual_duration = start.elapsed();
backend.clear().await.ok();
println!("Pipeline SET Performance:");
println!(" Pipeline: {:?}", pipeline_duration);
println!(" Individual: {:?}", individual_duration);
println!(
" Speedup: {:.2}x",
individual_duration.as_secs_f64() / pipeline_duration.as_secs_f64()
);
assert!(
pipeline_duration < individual_duration,
"Pipeline should be faster than individual operations"
);
}
#[tokio::test]
#[ignore = "性能测试需要 Redis 环境,使用 cargo test -- --ignored 运行"]
async fn test_pipeline_get_performance() {
let redis_url = get_redis_url();
let backend = RedisBackend::new(&redis_url)
.await
.expect("Failed to create Redis backend");
let test_data = generate_test_data(100);
backend.set_many(&test_data).await.expect("Failed to setup test data");
let keys: Vec<String> = test_data.iter().map(|(k, _, _)| k.clone()).collect();
let start = Instant::now();
let pipeline_results = backend.get_many(&keys).await.expect("Pipeline GET failed");
let pipeline_duration = start.elapsed();
let start = Instant::now();
let mut individual_results = Vec::new();
for key in &keys {
individual_results.push(backend.get(key).await.expect("Individual GET failed"));
}
let individual_duration = start.elapsed();
assert_eq!(pipeline_results.len(), individual_results.len());
backend.clear().await.ok();
println!("Pipeline GET Performance:");
println!(" Pipeline: {:?}", pipeline_duration);
println!(" Individual: {:?}", individual_duration);
println!(
" Speedup: {:.2}x",
individual_duration.as_secs_f64() / pipeline_duration.as_secs_f64()
);
assert!(
pipeline_duration < individual_duration,
"Pipeline should be faster than individual operations"
);
}
#[tokio::test]
#[ignore = "性能测试需要 Redis 环境,使用 cargo test -- --ignored 运行"]
async fn test_pipeline_delete_performance() {
let redis_url = get_redis_url();
let backend = RedisBackend::new(&redis_url)
.await
.expect("Failed to create Redis backend");
let test_data_1 = generate_test_data(100);
let test_data_2 = generate_test_data(100);
backend
.set_many(&test_data_1)
.await
.expect("Failed to setup test data 1");
let keys: Vec<String> = test_data_1.iter().map(|(k, _, _)| k.clone()).collect();
let start = Instant::now();
backend.delete_many(&keys).await.expect("Pipeline DELETE failed");
let pipeline_duration = start.elapsed();
backend
.set_many(&test_data_2)
.await
.expect("Failed to setup test data 2");
let start = Instant::now();
for key in &keys {
backend.delete(key).await.expect("Individual DELETE failed");
}
let individual_duration = start.elapsed();
backend.clear().await.ok();
println!("Pipeline DELETE Performance:");
println!(" Pipeline: {:?}", pipeline_duration);
println!(" Individual: {:?}", individual_duration);
println!(
" Speedup: {:.2}x",
individual_duration.as_secs_f64() / pipeline_duration.as_secs_f64()
);
assert!(
pipeline_duration < individual_duration,
"Pipeline should be faster than individual operations"
);
}
#[tokio::test]
#[ignore = "性能测试需要 Redis 环境,使用 cargo test -- --ignored 运行"]
async fn test_large_scale_pipeline_performance() {
let redis_url = get_redis_url();
let backend = RedisBackend::new(&redis_url)
.await
.expect("Failed to create Redis backend");
backend.clear().await.ok();
let test_data = generate_test_data(1000);
let start = Instant::now();
backend.set_many(&test_data).await.expect("Pipeline SET failed");
let set_duration = start.elapsed();
let keys: Vec<String> = test_data.iter().map(|(k, _, _)| k.clone()).collect();
let start = Instant::now();
let results = backend.get_many(&keys).await.expect("Pipeline GET failed");
let get_duration = start.elapsed();
assert_eq!(results.len(), 1000);
assert!(results.iter().all(|r| r.is_some()));
let start = Instant::now();
backend.delete_many(&keys).await.expect("Pipeline DELETE failed");
let delete_duration = start.elapsed();
let results = backend.get_many(&keys).await.expect("Failed to verify deletion");
assert!(results.iter().all(|r| r.is_none()));
println!("Large Scale Pipeline Performance (1000 keys):");
println!(" SET: {:?}", set_duration);
println!(" GET: {:?}", get_duration);
println!(" DELETE: {:?}", delete_duration);
println!(" Total: {:?}", set_duration + get_duration + delete_duration);
backend.clear().await.ok();
}
#[tokio::test]
#[ignore = "性能测试需要 Redis 环境,使用 cargo test -- --ignored 运行"]
async fn test_mixed_operations_performance() {
let redis_url = get_redis_url();
let backend = RedisBackend::new(&redis_url)
.await
.expect("Failed to create Redis backend");
backend.clear().await.ok();
let test_data = generate_test_data(500);
let total_start = Instant::now();
backend.set_many(&test_data).await.expect("Batch init failed");
let keys: Vec<String> = test_data.iter().map(|(k, _, _)| k.clone()).collect();
let _ = backend.get_many(&keys).await.expect("Batch read failed");
let updated_data: Vec<(String, Vec<u8>, Option<Duration>)> = test_data
.iter()
.map(|(k, _, ttl)| (k.clone(), format!("updated_{}", k).into_bytes(), *ttl))
.collect();
backend.set_many(&updated_data).await.expect("Batch update failed");
let delete_keys: Vec<String> = keys.iter().take(250).cloned().collect();
backend.delete_many(&delete_keys).await.expect("Batch delete failed");
let total_duration = total_start.elapsed();
println!("Mixed Operations Performance (500 keys):");
println!(" Total time: {:?}", total_duration);
backend.clear().await.ok();
}