use super::*;
use crate::opslog::{DRIFT_EXIT, YOG_DRIFT};
fn p(s: &str) -> PathBuf {
PathBuf::from(s)
}
#[test]
fn nothing_found_writes_nothing() {
assert!(entries("TS", "/state", &[]).is_empty());
}
#[test]
fn one_line_per_kind_carries_every_root_it_names() {
let found = [
Drift::Unannounced(p("/ws/b")),
Drift::Desync(p("/ws/a")),
Drift::Unannounced(p("/ws/a")),
Drift::Unannounced(p("/ws/b")), ];
let out = entries("TS", "/state", &found);
assert_eq!(out.len(), 2, "two kinds, two lines: {out:?}");
assert_eq!(
out[0].argv,
vec![YOG_DRIFT.to_string(), "desync".to_string()]
);
assert_eq!(out[0].stderr, "/ws/a\n");
assert_eq!(out[0].cwd, "/state");
assert_eq!(out[0].ts, "TS");
assert_eq!(out[0].exit, DRIFT_EXIT);
assert_eq!(
out[1].argv,
vec![YOG_DRIFT.to_string(), "unannounced".to_string()]
);
assert_eq!(out[1].stderr, "/ws/a\n/ws/b\n", "both roots, deduped");
}
#[test]
fn every_kind_names_itself_and_its_root() {
let all = [
Drift::Desync(p("/a")),
Drift::Unannounced(p("/b")),
Drift::Unenumerated(p("/c")),
Drift::Late(p("/state"), 7),
];
let kinds: Vec<&str> = all.iter().map(Drift::kind).collect();
assert_eq!(kinds, ["desync", "unannounced", "unenumerated", "late"]);
let roots: Vec<&Path> = all.iter().map(Drift::root).collect();
assert_eq!(
roots,
[
Path::new("/a"),
Path::new("/b"),
Path::new("/c"),
Path::new("/state")
]
);
assert_eq!(entries("TS", "/state", &all).len(), 4);
}
#[test]
fn only_the_pass_that_stops_keeping_cadence_is_a_finding() {
assert_eq!(late_edge(Some(3), false), Some(3), "the edge into lateness");
assert_eq!(
late_edge(Some(3), true),
None,
"still late says nothing new"
);
assert_eq!(late_edge(None, true), None, "recovery is not a drift row");
assert_eq!(late_edge(None, false), None, "and neither is keeping it");
}
#[test]
fn a_late_pass_carries_how_late_it_was() {
let out = entries("TS", "/state", &[Drift::Late(p("/state"), 12)]);
assert_eq!(out[0].argv, vec![YOG_DRIFT.to_string(), "late".to_string()]);
assert_eq!(out[0].stderr, "/state (12 s pass)\n");
}
#[test]
fn the_promise_a_pass_is_held_to_is_its_own_sweeps_period() {
use crate::app::dirty::Sweep;
let c = crate::app::Cadence::default();
assert_eq!(c.late_pass(Sweep::Full), c.full_sweep);
assert_eq!(c.late_pass(Sweep::Cheap), c.cheap_sweep);
assert_eq!(c.late_pass(Sweep::None), c.cheap_sweep);
let t0 = std::time::Instant::now();
let three_seconds = t0 + Duration::from_secs(3);
assert_eq!(
lateness(t0, three_seconds, c.late_pass(Sweep::Cheap)),
Some(3)
);
assert_eq!(lateness(t0, three_seconds, c.late_pass(Sweep::Full)), None);
}
#[test]
fn lateness_fires_only_at_the_cadence_it_promised() {
let late_pass = crate::app::Cadence::default().late_pass(crate::app::dirty::Sweep::Cheap);
let t0 = std::time::Instant::now();
let a_hair_early = (t0 + late_pass)
.checked_sub(Duration::from_millis(1))
.unwrap();
assert_eq!(lateness(t0, a_hair_early, late_pass), None);
assert_eq!(
lateness(t0, t0 + late_pass, late_pass),
Some(late_pass.as_secs())
);
assert_eq!(lateness(t0 + late_pass, t0, late_pass), None);
}
#[test]
fn the_staleness_line_is_silent_until_two_full_sweeps_are_missed() {
let stale = crate::app::Cadence::default().stale_after();
assert_eq!(stale_label(Duration::from_secs(0), stale), None);
let a_hair_fresh = stale.checked_sub(Duration::from_millis(1)).unwrap();
assert_eq!(stale_label(a_hair_fresh, stale), None);
assert_eq!(
stale_label(stale, stale),
Some(format!("derivation {} s behind", stale.as_secs()))
);
}