extern crate alloc;
use super::super::support::vv;
use crate::metis::{Cut, Dot, DotSet, Stability, UnknownStation, VersionVector};
#[track_caller]
fn d(station: u32, counter: u64) -> Dot {
Dot::from_parts(station, counter).expect("test literal names the non-dot counter zero")
}
fn cut(dots: &[(u32, u64)]) -> Cut {
let mut have = DotSet::new();
for &(station, count) in dots {
for dot in 1..=count {
let _ = have.insert(d(station, dot));
}
}
Cut::floor_of(&have)
}
#[test]
fn test_watermark_is_common_knowledge() {
let mut tracker = Stability::new([1, 2, 3]);
tracker.report(1, &vv(&[(1, 3), (2, 1)])).unwrap();
tracker.report(2, &vv(&[(1, 2), (2, 4), (3, 1)])).unwrap();
tracker.report(3, &vv(&[(1, 5), (2, 2)])).unwrap();
assert_eq!(tracker.watermark(), vv(&[(1, 2), (2, 1)]));
}
#[test]
fn test_watermark_requires_every_report() {
let mut tracker = Stability::new([1, 2]);
tracker.report(1, &vv(&[(1, 9), (2, 9)])).unwrap();
assert_eq!(tracker.watermark(), VersionVector::new());
}
#[test]
fn test_unknown_station_is_refused_unchanged() {
let mut tracker = Stability::new([1, 2]);
tracker.report(1, &vv(&[(1, 1)])).unwrap();
let before = tracker.clone();
let refused = tracker.report(7, &vv(&[(1, 5)]));
assert_eq!(refused, Err(UnknownStation { station: 7 }));
assert_eq!(tracker, before);
}
#[test]
fn test_stale_report_is_absorbed() {
let mut tracker = Stability::new([1, 2]);
tracker.report(1, &vv(&[(1, 4)])).unwrap();
tracker.report(2, &vv(&[(1, 4)])).unwrap();
let high = tracker.watermark();
assert_eq!(high, vv(&[(1, 4)]));
tracker.report(1, &vv(&[(1, 2)])).unwrap();
assert_eq!(tracker.watermark(), high);
}
#[test]
fn test_empty_roster_watermark_is_bottom() {
let tracker = Stability::new(core::iter::empty::<u32>());
assert_eq!(tracker.watermark(), VersionVector::new());
}
#[test]
fn test_report_cut_and_report_agree_on_the_watermark() {
let mut witnessed = Stability::new([1, 2]);
witnessed.report_cut(1, &cut(&[(1, 3), (2, 1)])).unwrap();
witnessed.report_cut(2, &cut(&[(1, 2), (2, 4)])).unwrap();
let mut bare = Stability::new([1, 2]);
bare.report(1, &vv(&[(1, 3), (2, 1)])).unwrap();
bare.report(2, &vv(&[(1, 2), (2, 4)])).unwrap();
assert_eq!(witnessed.watermark(), bare.watermark());
assert_eq!(witnessed.watermark(), vv(&[(1, 2), (2, 1)]));
}
#[test]
fn test_watermark_cut_is_witnessed_only_when_every_report_was() {
let mut tracker = Stability::new([1, 2]);
tracker.report_cut(1, &cut(&[(1, 4), (2, 2)])).unwrap();
tracker.report_cut(2, &cut(&[(1, 3), (2, 5)])).unwrap();
let watermark = tracker.watermark_cut().expect("all reports witnessed");
assert_eq!(watermark.as_vector(), &vv(&[(1, 3), (2, 2)]));
assert_eq!(watermark.as_vector(), &tracker.watermark());
tracker.report(1, &vv(&[(1, 9)])).unwrap();
assert!(tracker.watermark_cut().is_none());
tracker.report_cut(2, &cut(&[(2, 9)])).unwrap();
assert!(tracker.watermark_cut().is_none());
}
#[test]
fn test_watermark_cut_fresh_and_empty_are_bottom() {
let tracker = Stability::new([1, 2]);
assert_eq!(tracker.watermark_cut(), Some(Cut::bottom()));
let empty = Stability::new(core::iter::empty::<u32>());
assert_eq!(empty.watermark_cut(), Some(Cut::bottom()));
}
#[test]
fn test_reports_reader_exposes_the_straggler() {
let mut tracker = Stability::new([2, 1]);
tracker.report(1, &vv(&[(1, 6)])).unwrap();
let slots: alloc::vec::Vec<_> = tracker.reports().collect();
assert_eq!(slots.len(), 2);
assert_eq!(slots[0], (1, &vv(&[(1, 6)])));
assert_eq!(slots[1], (2, &VersionVector::new()));
}