feat: distribution simulation tests #34

Merged
zacheryasc merged 11 commits from distribution-sim-tests into master 2026-02-13 13:18:39 +00:00
Showing only changes of commit 6197361b22 - Show all commits

View file

@ -484,3 +484,73 @@ fn large_cluster_registry_converges() {
result.actual
);
}
// ────────────────────────────────────────────────────────────────────────────
// 10. Three-way partition: cluster splits into 3 groups, heals, converges
// ────────────────────────────────────────────────────────────────────────────
#[test]
fn three_way_partition_heals_and_converges() {
// Given: 9 nodes split into 3 groups {0,1,2}, {3,4,5}, {6,7,8}.
// Each group registers a name during the partition. After healing,
// all 9 nodes should converge on all 3 names.
let config = DistributionSimConfig {
name: "three-way-partition".into(),
num_nodes: 9,
num_rounds: 140,
ticks_per_round: 3,
actors_per_node: 0,
network_faults: vec![
// Partition A vs B
NetworkFault::Partition {
round: 10,
partition: Partition {
side_a: vec![0, 1, 2],
side_b: vec![3, 4, 5, 6, 7, 8],
asymmetric: false,
},
},
// Partition B vs C (stacks with the above: now 3 groups isolated)
NetworkFault::Partition {
round: 10,
partition: Partition {
side_a: vec![3, 4, 5],
side_b: vec![6, 7, 8],
asymmetric: false,
},
},
NetworkFault::Heal { round: 60 },
],
action_schedule: vec![
(20, SimAction::RegisterName { node_idx: 0, name: "group-a-svc".into() }),
(20, SimAction::RegisterName { node_idx: 3, name: "group-b-svc".into() }),
(20, SimAction::RegisterName { node_idx: 6, name: "group-c-svc".into() }),
],
swim: distribution::swim::probe::SwimConfig {
probe_interval: 1,
probe_timeout: 3,
indirect_probes: 1,
// Must exceed partition duration (50 rounds × 3 ticks = 150 ticks)
suspicion_timeout: 200,
dead_reprobe_interval: 10,
},
..DistributionSimConfig::default()
};
let (_trace, nodes) = run_simulation_with_nodes(config);
let alive_count = nodes.iter().filter(|n| n.is_some()).count();
assert_eq!(alive_count, 9, "all 9 nodes should survive the three-way partition");
// After healing + gossip, all 3 names should be resolvable from every node
for (i, node) in nodes.iter().enumerate() {
if let Some(node) = node {
for name in &["group-a-svc", "group-b-svc", "group-c-svc"] {
assert!(
node.resolve_name(name).is_some(),
"node {i} should resolve '{name}' after three-way partition heals"
);
}
}
}
}