#![cfg(feature = "cache-redis")]
use rs_zero::cache::CacheKey;
use rs_zero::cache_redis::{
RedisNodeConfig, RedisShardChoice, RedisShardPicker, RedisShardedCacheConfig,
RedisShardedCacheStore,
};
#[test]
fn sharded_config_rejects_missing_nodes() {
let error = RedisShardedCacheConfig::default()
.validate()
.expect_err("missing nodes");
assert!(error.to_string().contains("at least one redis shard"));
}
#[test]
fn sharded_store_selects_stable_node_for_same_key() {
let store = RedisShardedCacheStore::new(RedisShardedCacheConfig {
nodes: vec![
RedisNodeConfig::new("redis-a", "redis://127.0.0.1:6379"),
RedisNodeConfig::new("redis-b", "redis://127.0.0.1:6380"),
],
..RedisShardedCacheConfig::default()
})
.expect("store");
let key = CacheKey::new(store.namespace(), ["users", "42"]);
let first = store.shard_name_for_key(&key).expect("first shard");
let second = store.shard_name_for_key(&key).expect("second shard");
assert_eq!(first, second);
}
#[test]
fn weighted_picker_prefers_heavier_node_over_many_keys() {
let picker = RedisShardPicker::new(vec![
RedisShardChoice {
name: "light".to_string(),
weight: 1,
},
RedisShardChoice {
name: "heavy".to_string(),
weight: 8,
},
])
.expect("picker");
let mut heavy = 0;
let mut light = 0;
for index in 0..512 {
match picker
.select_name(&format!("cache:key:{index}"))
.expect("node")
{
"heavy" => heavy += 1,
"light" => light += 1,
other => panic!("unexpected shard {other}"),
}
}
assert!(heavy > light, "heavy={heavy} light={light}");
}