crates/monetize-server/src/estate_order/tests/held_stopped.rs
//! ★ **SEC-S1 (sec review 2026-11-01): the guardian never starts what monetize stopped on
//! purpose.** BOX-START's start pass (e9d2d1b1) started every silent box the provider read
//! `stopped` — also the boxes the term itself had stopped: an estate unpaid past its grace, or
//! cancelled by its buyer at the end of its paid period, ran free until its deletion date.
//! Monetize knows why it stopped them (the run's phase and its `stopped` list), and the guardian
//! asks it before it starts anything: the estate stays stopped, its disks kept, nothing laid.
use super::*;
/// `acme` delivered, its fleet row known to the guardian with auto-fix ON (the start pass
/// needs no auto-fix; a rebuild would), and every box heard.
fn guarded(name: &str) -> (Rig, Vec<String>) {
let r = delivered(name, cfg());
r.state
.fleet
.link("gunnar", &crate::testing::guardian::GUARDIAN);
let run = r.state.estates.get("acme").unwrap();
let g = r.state.fleet.guardian().unwrap();
if g.store.product_of(run.fleet_name()).is_none() {
g.store.declare(run.fleet_name(), "gunnar").unwrap();
}
g.store.set_auto_fix(run.fleet_name(), true).unwrap();
// Every box laid has its fleet key (as the install pins them): the guardian knows its roles.
for (i, m) in run.laid.as_ref().unwrap().machines.iter().enumerate() {
let key = monetize::sign::Signer::from_bytes(&[40 + i as u8; 32]).public_key();
g.store
.register_key(
run.fleet_name(),
&m.role,
&monetize_embed::signing::base64_encode(&key),
)
.unwrap();
}
let servers = server_ids(&run);
drive(&r.state, "acme");
(r, servers)
}
/// The guardian's ticks for `minutes` (one a minute, the boxes silent: a stopped box calls
/// nobody), its provider looks asked inline. Its lines.
fn silent_ticks(r: &Rig, minutes: u64) -> Vec<String> {
let mut lines = Vec::new();
for _ in 0..minutes {
r.clock.fetch_add(60_000, Ordering::SeqCst);
lines.extend(crate::fleet::tick(&r.state));
}
lines
}
fn no_start(r: &Rig, servers: &[String], lines: &[String]) {
assert!(
servers.iter().all(|s| !r.cloud.running(s)),
"the term's stop stands: {lines:#?}"
);
assert!(
!lines.iter().any(|l| l.contains("guardian.started")),
"nothing is started: {lines:#?}"
);
let g = r.state.fleet.guardian().unwrap();
assert!(
g.store
.cases_of("acme")
.iter()
.all(|c| c.finding.code != monetize_guardian::STOPPED_AT_PROVIDER),
"no start case: {:#?}",
g.store.cases_of("acme")
);
assert!(
r.cloud
.calls
.lock()
.unwrap()
.iter()
.all(|c| !matches!(c, monetize::testing::CloudCall::Power(_, true))),
"no power-on was asked"
);
}
/// RED: unpaid past its grace, the term stops every server (SUSPENDED); an hour of the
/// guardian's ticks starts none of them.
#[test]
fn an_estate_the_term_stopped_for_nonpayment_stays_stopped_through_the_start_pass() {
let (r, servers) = guarded("held-unpaid");
let paid = r.state.estates.get("acme").unwrap().paid_until_ms;
at(&r, paid);
let run = at(&r, paid + 14 * DAY);
assert_eq!(run.phase, phase::SUSPENDED);
assert!(
servers.iter().all(|s| !r.cloud.running(s)),
"every server is stopped"
);
let lines = silent_ticks(&r, 60);
no_start(&r, &servers, &lines);
// Renewed and paid: the term starts the boxes itself, as before.
assert_eq!(r.state.estates.get("acme").unwrap().phase, phase::SUSPENDED);
}
/// RED: cancelled by its buyer, stopped at the end of its paid period: stays stopped.
#[test]
fn an_estate_its_buyer_cancelled_stays_stopped_through_the_start_pass() {
let (r, servers) = guarded("held-cancelled");
let paid = r.state.estates.get("acme").unwrap().paid_until_ms;
cancel(&r.state, "acme").expect("cancelled");
let run = at(&r, paid);
assert_eq!(run.phase, phase::SUSPENDED, "{:#?}", run.history);
let lines = silent_ticks(&r, 60);
no_start(&r, &servers, &lines);
}
/// The guardian says why it leaves the estate alone (the run's own words), and the shop's
/// world answers it for every role; a running estate is held by nothing.
#[test]
fn the_shops_world_says_why_it_holds_an_estate_stopped() {
use monetize_guardian::World as _;
let (r, _) = guarded("held-why");
let world = crate::fleet::ShopWorld { state: &r.state };
assert_eq!(
world.estate_held("acme"),
None,
"a paid, running estate is held by nothing"
);
assert_eq!(world.box_held("acme", "main"), None);
let paid = r.state.estates.get("acme").unwrap().paid_until_ms;
at(&r, paid);
at(&r, paid + 14 * DAY);
let world = crate::fleet::ShopWorld { state: &r.state };
let why = world.estate_held("acme").expect("held by the term");
assert!(why.contains("unpaid"), "{why}");
assert!(
world
.box_held("acme", "main")
.is_some_and(|w| w.contains("term")),
"the run's stopped list names the main"
);
}