use serde::{Deserialize, Serialize};
use super::judgement::Judgement;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum CondState {
Ok,
Firing,
Unobservable,
}
impl From<&Judgement> for CondState {
fn from(j: &Judgement) -> CondState {
match j {
Judgement::Established => CondState::Firing,
Judgement::NotEstablished { .. } => CondState::Ok,
Judgement::NotAsked | Judgement::Unobservable { .. } => CondState::Unobservable,
}
}
}
impl From<Judgement> for CondState {
fn from(j: Judgement) -> CondState {
CondState::from(&j)
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Transition {
pub rule: String,
pub from: Option<CondState>,
pub to: CondState,
pub at: String,
pub evidence: String,
}
#[derive(Debug, Clone, Serialize)]
pub struct WatchdogSummary {
pub ticks: u64,
pub transitions: u64,
pub facts_evicted: u64,
pub firing: Vec<String>,
pub unobservable: Vec<String>,
}
impl WatchdogSummary {
pub fn judgement(&self) -> Judgement {
if !self.firing.is_empty() {
return Judgement::Established;
}
if !self.unobservable.is_empty() {
return Judgement::Unobservable {
reason: format!(
"{} rule(s) ended unobservable: {}",
self.unobservable.len(),
self.unobservable.join("; ")
),
};
}
Judgement::NotEstablished {
reason: "every rule ended ok".into(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::report::judgement_exit_code;
fn summary(firing: &[&str], unobservable: &[&str]) -> WatchdogSummary {
WatchdogSummary {
ticks: 2,
transitions: 3,
facts_evicted: 0,
firing: firing.iter().map(|r| r.to_string()).collect(),
unobservable: unobservable.iter().map(|r| r.to_string()).collect(),
}
}
#[test]
fn watchdog_summary_json_shape_is_pinned() {
assert_eq!(
serde_json::to_value(summary(&["rate-above v1/** 5"], &["dropped"])).unwrap(),
serde_json::json!({
"ticks": 2,
"transitions": 3,
"facts_evicted": 0,
"firing": ["rate-above v1/** 5"],
"unobservable": ["dropped"],
})
);
}
#[test]
fn a_bounded_run_ends_firing_then_unobservable_then_clean() {
let exit = |s: &WatchdogSummary| judgement_exit_code(&s.judgement());
assert_eq!(exit(&summary(&["a"], &["b"])), 1);
assert_eq!(exit(&summary(&[], &["b"])), 2);
assert_eq!(exit(&summary(&[], &[])), 0);
assert_eq!(
summary(&[], &["b", "c"]).judgement(),
Judgement::Unobservable {
reason: "2 rule(s) ended unobservable: b; c".into()
}
);
}
}