use crate::adapter::net::behavior::fold::NodeId;
use crate::adapter::net::redex::{PlacementStrategy, ReplicationConfig, ReplicationConfigError};
use super::quorum::ReplicaSet;
pub const COLOCATE_WITH_STRICT_KEY: &str = "colocate-with-strict";
pub fn colocated_island_config(factor: u8) -> ReplicationConfig {
ReplicationConfig::new()
.with_factor(factor)
.with_placement(PlacementStrategy::ColocationStrict)
}
pub fn pinned_island_replicas(
replicas: impl IntoIterator<Item = NodeId>,
) -> Result<(ReplicationConfig, ReplicaSet), ReplicationConfigError> {
let mut nodes: Vec<NodeId> = replicas.into_iter().collect();
nodes.sort_unstable();
nodes.dedup();
let config = ReplicationConfig::new().with_placement(PlacementStrategy::Pinned(nodes.clone()));
config.validate()?;
Ok((config, ReplicaSet::new(nodes)))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn colocated_config_uses_colocation_strict() {
let cfg = colocated_island_config(3);
assert_eq!(cfg.placement, PlacementStrategy::ColocationStrict);
assert_eq!(cfg.factor, 3);
cfg.validate().expect("colocation-strict config is valid");
}
#[test]
fn pinned_replicas_yield_matching_config_and_quorum_set() {
let (cfg, set) = pinned_island_replicas([5, 1, 3]).expect("valid pinned set");
assert_eq!(
cfg.placement,
PlacementStrategy::Pinned(vec![1, 3, 5]),
"pinned config carries the normalized fault-domain set",
);
assert_eq!(cfg.effective_factor(), 3);
assert_eq!(set.members(), &[1, 3, 5]);
assert_eq!(set.quorum_threshold(), 2);
}
#[test]
fn duplicate_replicas_are_normalized_not_rejected() {
let (cfg, set) = pinned_island_replicas([7, 7, 9]).expect("dedups to a valid set");
assert_eq!(cfg.effective_factor(), 2);
assert_eq!(set.members(), &[7, 9]);
}
#[test]
fn empty_replica_set_is_rejected() {
assert!(pinned_island_replicas([]).is_err());
}
}