use std::collections::BTreeSet;
use shep_client::shep_core::protocol::ProcessInfo;
use crate::daemon::Daemon;
use crate::error::Error;
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct Generation {
pids: BTreeSet<u32>,
rows: u32,
}
impl Generation {
pub async fn of<D: Daemon>(daemon: &D, sheep: &str) -> Result<Self, Error> {
let flock = daemon.describe(sheep).await?;
Ok(Self::of_infos(&flock.iter().collect::<Vec<_>>()))
}
#[must_use]
pub fn instances(&self) -> u32 {
self.rows
}
pub(crate) fn of_infos(infos: &[&ProcessInfo]) -> Self {
Self {
pids: infos.iter().filter_map(|info| info.pid).collect(),
rows: u32::try_from(infos.len()).unwrap_or(u32::MAX),
}
}
pub(crate) fn is_new(&self, info: &ProcessInfo) -> bool {
info.pid.is_some_and(|pid| !self.pids.contains(&pid))
}
pub(crate) fn holds(&self, info: &ProcessInfo) -> bool {
info.pid.is_some_and(|pid| self.pids.contains(&pid))
}
pub(super) fn has_turned_over(
&self,
flock: &[ProcessInfo],
accept: fn(&ProcessInfo) -> bool,
) -> bool {
let count_holds = self.instances() == 0
|| u32::try_from(flock.len()).is_ok_and(|listed| listed == self.instances());
!flock.is_empty()
&& count_holds
&& flock.iter().all(|info| self.is_new(info) && accept(info))
}
}
#[cfg(test)]
mod tests {
use shep_client::shep_core::status::ProcStatus;
use super::*;
use crate::verify::test_support::{Listings, instance};
#[tokio::test(start_paused = true)]
async fn a_generation_is_the_pids_that_are_serving() {
let daemon = Listings::new(vec![vec![
instance(1, ProcStatus::Online, 12835),
instance(2, ProcStatus::Online, 12836),
ProcessInfo::builder(3, "web", ProcStatus::WaitingRestart).build(),
]]);
let generation = Generation::of(&daemon, "web").await.unwrap();
assert_eq!(
generation,
Generation {
pids: [12835, 12836].into_iter().collect(),
rows: 3,
}
);
}
}