use std::sync::atomic::{AtomicU64, Ordering};
use std::time::Duration;
use oxcache::backend::{RedisBackend, SyncCacheReader, SyncCacheWriter};
use oxcache::error::CacheError;
const REDIS_URL: &str = "redis://127.0.0.1:6379";
const KEY_PREFIX: &str = "test_redis_sync:";
static UID: AtomicU64 = AtomicU64::new(0);
fn unique_key(suffix: &str) -> String {
let id = UID.fetch_add(1, Ordering::SeqCst);
format!("{}{}_{}", KEY_PREFIX, id, suffix)
}
async fn make_backend() -> RedisBackend {
std::env::set_var("OXCACHE_ALLOW_INSECURE_REDIS", "I_UNDERSTAND_THE_RISKS");
RedisBackend::new(REDIS_URL)
.await
.expect("Failed to connect to Redis — start a Redis server (e.g. `redis-server`) before running this test")
}
#[test]
#[ignore = "requires Redis server; run with: cargo test --features redis --test redis_sync -- --ignored"]
fn test_redis_sync_get_set_multi_thread_runtime() {
let rt = tokio::runtime::Runtime::new().expect("failed to build multi-thread runtime");
rt.block_on(async {
let backend = make_backend().await;
let key = unique_key("sync_get_set");
SyncCacheWriter::set(&backend, &key, b"hello sync".to_vec(), None).expect("sync set failed");
let val = SyncCacheReader::get(&backend, &key).expect("sync get failed");
assert_eq!(val, Some(b"hello sync".to_vec()));
assert!(SyncCacheReader::exists(&backend, &key).expect("sync exists failed"));
SyncCacheWriter::delete(&backend, &key).expect("sync delete failed");
assert!(!SyncCacheReader::exists(&backend, &key).expect("sync exists after delete failed"));
});
}
#[test]
#[ignore = "requires Redis server; run with: cargo test --features redis --test redis_sync -- --ignored"]
fn test_redis_sync_get_current_thread_fails() {
let rt = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.expect("failed to build current-thread runtime");
rt.block_on(async {
let backend = make_backend().await;
let key = unique_key("sync_current_thread");
let result = SyncCacheReader::get(&backend, &key);
assert!(
matches!(result, Err(CacheError::NotSupported(_))),
"expected Err(NotSupported) on current-thread runtime, got {:?}",
result
);
let result = SyncCacheWriter::set(&backend, &key, b"v".to_vec(), None);
assert!(
matches!(result, Err(CacheError::NotSupported(_))),
"expected Err(NotSupported) for sync set on current-thread runtime, got {:?}",
result
);
});
}
#[test]
#[ignore = "requires Redis server; run with: cargo test --features redis --test redis_sync -- --ignored"]
fn test_redis_sync_set_with_ttl_expires() {
let rt = tokio::runtime::Runtime::new().expect("failed to build multi-thread runtime");
rt.block_on(async {
let backend = make_backend().await;
let key = unique_key("sync_ttl_expires");
SyncCacheWriter::set(&backend, &key, b"v".to_vec(), Some(Duration::from_secs(1)))
.expect("sync set with ttl failed");
assert!(SyncCacheReader::exists(&backend, &key).expect("sync exists failed"));
tokio::time::sleep(Duration::from_millis(1100)).await;
assert!(
!SyncCacheReader::exists(&backend, &key).expect("sync exists after expiry failed"),
"key should have expired"
);
});
}
#[test]
#[ignore = "requires Redis server; run with: cargo test --features redis --test redis_sync -- --ignored"]
fn test_redis_sync_expire() {
let rt = tokio::runtime::Runtime::new().expect("failed to build multi-thread runtime");
rt.block_on(async {
let backend = make_backend().await;
let key = unique_key("sync_expire");
SyncCacheWriter::set(&backend, &key, b"v".to_vec(), None).expect("sync set failed");
let ok = SyncCacheWriter::expire(&backend, &key, Duration::from_secs(50)).expect("sync expire failed");
assert!(ok, "expire should return true for existing key");
let ttl = SyncCacheReader::ttl(&backend, &key).expect("sync ttl failed");
assert!(ttl.is_some(), "ttl should be Some after expire");
let secs = ttl.unwrap().as_secs();
assert!(secs > 40 && secs <= 50, "ttl secs should be in (40, 50], got {}", secs);
let missing = unique_key("sync_expire_missing");
let ok = SyncCacheWriter::expire(&backend, &missing, Duration::from_secs(10)).expect("sync expire call failed");
assert!(!ok, "expire should return false for missing key");
SyncCacheWriter::delete(&backend, &key).expect("sync delete failed");
});
}