use crate::adapter::net::behavior::meshos::snapshot::{MeshOsSnapshot, PeerHealthSnapshot};
use crate::adapter::net::behavior::meshos::state::MeshOsState;
use crate::adapter::net::behavior::meshos::{NodeHealth, NodeId};
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct LivenessDelta {
pub down: Vec<NodeId>,
pub up: Vec<NodeId>,
}
pub fn project_liveness(meshos: &MeshOsState) -> LivenessDelta {
let mut delta = LivenessDelta::default();
for (&node, &health) in &meshos.node_health {
match health {
NodeHealth::Healthy | NodeHealth::Degraded => delta.up.push(node),
NodeHealth::Unreachable => delta.down.push(node),
}
}
delta.down.sort_unstable();
delta.up.sort_unstable();
delta
}
pub fn project_liveness_from_snapshot(snapshot: &MeshOsSnapshot) -> LivenessDelta {
let mut delta = LivenessDelta::default();
for (&node, peer) in &snapshot.peers {
match peer.health {
Some(PeerHealthSnapshot::Unreachable) => delta.down.push(node),
Some(PeerHealthSnapshot::Healthy) | Some(PeerHealthSnapshot::Degraded) => {
delta.up.push(node)
}
None => {}
}
}
delta.down.sort_unstable();
delta.up.sort_unstable();
delta
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn unreachable_is_down_healthy_and_degraded_are_up() {
let mut meshos = MeshOsState::default();
meshos.node_health.insert(1, NodeHealth::Healthy);
meshos.node_health.insert(2, NodeHealth::Unreachable);
meshos.node_health.insert(3, NodeHealth::Degraded);
meshos.node_health.insert(4, NodeHealth::Unreachable);
let delta = project_liveness(&meshos);
assert_eq!(delta.down, vec![2, 4], "unreachable → down (sorted)");
assert_eq!(delta.up, vec![1, 3], "healthy + degraded → up (sorted)");
}
#[test]
fn degraded_stays_a_candidate_not_dropped() {
let mut meshos = MeshOsState::default();
meshos.node_health.insert(7, NodeHealth::Degraded);
let delta = project_liveness(&meshos);
assert_eq!(delta.up, vec![7]);
assert!(delta.down.is_empty());
}
#[test]
fn empty_health_yields_empty_delta() {
let delta = project_liveness(&MeshOsState::default());
assert_eq!(delta, LivenessDelta::default());
}
#[test]
fn snapshot_variant_classifies_peers_by_snapshot_health() {
use crate::adapter::net::behavior::meshos::snapshot::PeerSnapshot;
let mut snap = MeshOsSnapshot::default();
snap.peers.insert(
1,
PeerSnapshot {
health: Some(PeerHealthSnapshot::Healthy),
..Default::default()
},
);
snap.peers.insert(
2,
PeerSnapshot {
health: Some(PeerHealthSnapshot::Unreachable),
..Default::default()
},
);
snap.peers.insert(
3,
PeerSnapshot {
health: Some(PeerHealthSnapshot::Degraded),
..Default::default()
},
);
snap.peers.insert(4, PeerSnapshot::default());
let delta = project_liveness_from_snapshot(&snap);
assert_eq!(delta.down, vec![2], "only Unreachable is down");
assert_eq!(delta.up, vec![1, 3], "Healthy + Degraded are up");
assert!(
!delta.down.contains(&4) && !delta.up.contains(&4),
"a peer with no health sample is never classified (never pruned)",
);
}
}