extern crate alloc;
use alloc::collections::BTreeMap;
use alloc::vec::Vec;
use super::super::fabric::Fabric;
use super::super::replica::Replica;
use super::super::{Note, act, assert_converged, crash, fleet_of, resync};
use super::{ROSTER, horizon};
#[test]
fn a_mid_window_crash_rehydrates_and_the_fleet_seals() {
let depth = horizon(2);
let mut fleet = fleet_of(&ROSTER, depth);
let mut fabric = Fabric::new(0xC4A5_84E5, &ROSTER, 8);
for station in ROSTER {
let _ = act(&mut fabric, &mut fleet, station, |replica, out| {
replica.insert_visible(0, out)
});
}
fabric.drain(&mut fleet);
let _ = act(&mut fabric, &mut fleet, 1, |replica, out| {
replica.try_declare(out)
})
.expect("a settled watermark self-supports the declaration");
let mut guard = 0;
while !fleet[&1].adopted() {
assert!(fabric.step(&mut fleet), "the fabric must keep moving");
guard += 1;
assert!(guard < 10_000, "adoption must arrive under a live fabric");
}
let _ = act(&mut fabric, &mut fleet, 1, |replica, out| {
replica.insert_visible(1, out)
});
let _ = act(&mut fabric, &mut fleet, 3, |replica, out| {
replica.insert_visible(0, out)
});
for _ in 0..4 {
let _ = fabric.step(&mut fleet);
}
crash(&mut fleet, &ROSTER, depth, 1);
assert!(
fleet[&1].adopted(),
"adoption re-derives from the journal: the witness is re-earned by \
re-running adopt over the rebuilt record, never restored from disk"
);
resync(&mut fabric, &fleet, 1);
fabric.drain(&mut fleet);
for replica in fleet.values() {
assert_eq!(
replica.generation(),
2,
"replica {} seals the window it crashed inside",
replica.id()
);
}
assert_converged(&fleet);
crash(&mut fleet, &ROSTER, depth, 1);
resync(&mut fabric, &fleet, 1);
fabric.drain(&mut fleet);
assert_converged(&fleet);
let _ = act(&mut fabric, &mut fleet, 1, |replica, out| {
replica.insert_visible(0, out)
});
fabric.drain(&mut fleet);
assert_converged(&fleet);
}
#[test]
fn a_persisted_but_unsent_mint_reaches_the_fleet_through_repair() {
let depth = horizon(2);
let mut fleet = fleet_of(&ROSTER, depth);
let mut fabric = Fabric::new(0x0DD5_E47D, &ROSTER, 0);
let _ = act(&mut fabric, &mut fleet, 1, |replica, out| {
replica.insert_visible(0, out)
});
fabric.drain(&mut fleet);
let unsent = {
let replica = fleet.get_mut(&2).expect("roster member");
let mut dead_outbox = Vec::new();
replica.insert_visible(1, &mut dead_outbox)
};
crash(&mut fleet, &ROSTER, depth, 2);
assert!(
fleet[&2].text().store().locus(unsent).is_some(),
"the journal is the source of record for the unsent mint"
);
for station in [1, 3] {
assert!(
fleet[&station].text().store().locus(unsent).is_none(),
"the fabric never carried the unsent mint to station {station}"
);
}
resync(&mut fabric, &fleet, 2);
fabric.drain(&mut fleet);
assert_converged(&fleet);
let _ = act(&mut fabric, &mut fleet, 1, |replica, out| {
replica.try_declare(out)
})
.expect("the repaired watermark self-supports the declaration");
fabric.drain(&mut fleet);
for replica in fleet.values() {
assert_eq!(replica.generation(), 2, "the repaired fleet seals");
}
assert_converged(&fleet);
}
fn assert_record_exact(fleet: &BTreeMap<u32, Replica>, unique: usize, context: &str) {
for replica in fleet.values() {
assert_eq!(
replica.log_len(),
unique,
"{context}: replica {} log never compounds",
replica.id()
);
assert_eq!(
replica.journal_data_notes(),
unique,
"{context}: replica {} journal data never compounds",
replica.id()
);
assert_eq!(
replica.volatile_data_notes(),
0,
"{context}: replica {} fences every data note by drain",
replica.id()
);
}
}
#[test]
fn alternating_restarts_keep_the_record_bounded() {
let depth = horizon(2);
let mut fleet = fleet_of(&ROSTER, depth);
let mut fabric = Fabric::new(0xB07D_ED42, &ROSTER, 3);
let mut mints = 0usize;
for round in 0..3 {
for station in ROSTER {
let _ = act(&mut fabric, &mut fleet, station, |replica, out| {
replica.insert_visible(round, out)
});
mints += 1;
}
}
let deleted = act(&mut fabric, &mut fleet, 1, |replica, out| {
replica.delete_visible(0, out)
});
assert!(deleted.is_some(), "the plane has an element to delete");
mints += 1;
fabric.drain(&mut fleet);
assert_record_exact(&fleet, mints, "post-tape");
let mut frozen: Option<BTreeMap<u32, usize>> = None;
for cycle in 0..4usize {
let station = ROSTER[cycle % ROSTER.len()];
crash(&mut fleet, &ROSTER, depth, station);
resync(&mut fabric, &fleet, station);
fabric.drain(&mut fleet);
assert_record_exact(&fleet, mints, "crash cycle");
let totals: BTreeMap<u32, usize> = fleet
.iter()
.map(|(&id, replica)| (id, replica.journal_notes_len()))
.collect();
if let Some(frozen) = &frozen {
assert_eq!(
frozen, &totals,
"cycle {cycle}: a no-effect repair round fences nothing at all"
);
}
frozen = Some(totals);
}
assert_converged(&fleet);
let _ = act(&mut fabric, &mut fleet, 1, |replica, out| {
replica.try_declare(out)
})
.expect("a settled watermark self-supports the declaration");
let mut adopter = None;
while adopter.is_none() {
assert!(
fabric.step(&mut fleet),
"the confirmation round must complete from in-flight traffic"
);
adopter = ROSTER.iter().copied().find(|id| fleet[id].adopted());
}
let adopter = adopter.expect("just found");
let native_mints = 2usize;
let _ = act(&mut fabric, &mut fleet, adopter, |replica, out| {
replica.insert_visible(0, out)
});
let _ = act(&mut fabric, &mut fleet, adopter, |replica, out| {
replica.insert_visible(1, out)
});
fabric.drain(&mut fleet);
for replica in fleet.values() {
assert_eq!(replica.generation(), 2, "the window sealed everywhere");
}
assert_record_exact(&fleet, native_mints, "post-seal");
assert_converged(&fleet);
}
#[test]
fn a_restart_never_undercuts_a_spoken_stamp() {
let depth = horizon(2);
let mut fleet = fleet_of(&ROSTER, depth);
let mut fabric = Fabric::new(0x57A4_9CA5, &ROSTER, 0);
for station in ROSTER {
let _ = act(&mut fabric, &mut fleet, station, |replica, out| {
replica.insert_visible(0, out)
});
}
fabric.drain(&mut fleet);
let _ = act(&mut fabric, &mut fleet, 1, |replica, out| {
replica.try_declare(out)
})
.expect("a settled watermark self-supports the declaration");
let mut adopter = None;
while adopter.is_none() {
assert!(fabric.step(&mut fleet), "the rounds must complete");
adopter = ROSTER.iter().copied().find(|id| fleet[id].adopted());
}
let adopter = adopter.expect("just found");
let stamp_of = |outbox: &[Note]| {
outbox
.iter()
.find_map(|note| match note {
Note::Native { stamp, .. } => Some(*stamp),
_ => None,
})
.expect("a native op emits a stamped note")
};
let mut insert_stamp = None;
for _ in 0..12 {
let mut outbox = Vec::new();
let _ = fleet
.get_mut(&adopter)
.expect("roster member")
.insert_visible(0, &mut outbox);
insert_stamp = Some(stamp_of(&outbox));
fabric.post(adopter, outbox);
}
let insert_stamp = insert_stamp.expect("the native inserts ran");
let mut delete_stamp = insert_stamp;
for _ in 0..12 {
let mut outbox = Vec::new();
let _ = fleet
.get_mut(&adopter)
.expect("roster member")
.delete_visible(0, &mut outbox);
delete_stamp = stamp_of(&outbox);
fabric.post(adopter, outbox);
}
assert!(delete_stamp > insert_stamp, "the clock is monotone live");
let mut served = Vec::new();
fleet[&adopter].reserve_logs(&mut served);
for note in &served {
if let Note::Native { stamp, .. } = note {
assert!(
*stamp <= delete_stamp,
"a re-served stamp is an already-spoken stamp"
);
}
}
crash(&mut fleet, &ROSTER, depth, adopter);
let mut outbox = Vec::new();
let _ = fleet
.get_mut(&adopter)
.expect("roster member")
.insert_visible(0, &mut outbox);
let post_restart = stamp_of(&outbox);
fabric.post(adopter, outbox);
assert!(
post_restart > delete_stamp,
"the journaled stamps re-derive the clock past the note-only stamp"
);
resync(&mut fabric, &fleet, adopter);
fabric.drain(&mut fleet);
for replica in fleet.values() {
assert_eq!(replica.generation(), 2, "the window sealed");
}
crash(&mut fleet, &ROSTER, depth, adopter);
let dot = {
let mut outbox = Vec::new();
let dot = fleet
.get_mut(&adopter)
.expect("roster member")
.insert_visible(0, &mut outbox);
fabric.post(adopter, outbox);
dot
};
let fresh = fleet[&adopter]
.text()
.store()
.locus(dot)
.expect("just woven")
.rank;
assert!(
fresh > post_restart && fresh > delete_stamp,
"the checkpoint watermark dominates the re-based window's stamps"
);
resync(&mut fabric, &fleet, adopter);
fabric.drain(&mut fleet);
assert_converged(&fleet);
}