crates/monetize-server/src/estate_order/tests/holger_ladder.rs
//! ★ **Holger's own size ladder** (lane L18, 2026-10-18): the ONE box that sells Gunnar lays a
//! Holger site too, and its order form and its ladder page offered GUNNAR's steps (Mini = a
//! 2-core front and a 4-core main with four 10 GB data disks) for Holger's three boxes. A site of
//! another product is sized on its own lifecycle's ladder, under the same step names; the shop's
//! own sites keep the shop's ladder.
use super::*;
fn shop_with_a_holger_site(name: &str) -> (Arc<crate::state::AppState>, EstateOrderConfig) {
let dir = tmp(name);
let reg = Registry::new()
.sells("gunnar", HoldPay::default())
.vendor(SitePay("sitepay-test2"))
.cloud(Arc::new(MockCloud::new()))
.shared_product(shop_product())
.home("gunnar", "gunnar-rs")
.estate(
"gunnar-rs",
crate::config::EstateConfig {
product: "gunnar".into(),
vendor: "holdpay".into(),
site: "gunnar.rs".into(),
..Default::default()
},
)
.estate(
"testh-holger-rs",
crate::config::EstateConfig {
product: "holger".into(),
vendor: "sitepay-test2".into(),
site: "testh.holger.rs".into(),
..Default::default()
},
);
let (state, ..) = build_in(
reg,
&dir,
EstateOrderConfig {
vendor: String::new(),
apex: String::new(),
lifecycle: "gunnar".into(),
..cfg()
},
FakeKit::new("PASS"),
None,
None,
);
let base = state.estates.cfg.clone().unwrap();
(state, base)
}
#[test]
fn a_holger_site_is_sized_on_holgers_own_ladder_and_gunnars_is_unchanged() {
let (state, base) = shop_with_a_holger_site("holger-ladder");
let own = lifecycle::find("holger")
.and_then(|l| l.ladder())
.expect("Holger names its own ladder");
let names = |l: &[LadderStep]| l.iter().map(|s| s.name.clone()).collect::<Vec<_>>();
assert_eq!(
names(&own),
names(&default_ladder()),
"the same step names (Mini to Gigantic)"
);
assert_ne!(own, default_ladder(), "never Gunnar's steps");
// Mini is Holger's own shape: what an order that names no size is laid at.
let shape = crate::testing::lifecycles::holger_shape();
assert_eq!(
(
own[0].front_plan.as_str(),
own[0].main_plan.as_str(),
own[0].main_data_gib
),
(
shape.front.plan.as_str(),
shape.main.plan.as_str(),
shape.main.disks[1].gib
)
);
assert!(
own.windows(2)
.all(|w| w[0].main_data_gib < w[1].main_data_gib),
"each step holds more data: {own:?}"
);
assert!(
lifecycle::find("gunnar").unwrap().ladder().is_none(),
"Gunnar keeps the shop's ladder"
);
let h = terms_on(&state, &base, Some("testh-holger-rs")).expect("the Holger site's terms");
assert_eq!(
h.ladder, own,
"the Holger site's terms carry Holger's ladder"
);
assert_eq!(
site::sizes_of_on(&state, Some("testh-holger-rs"), "mini").unwrap(),
own[0].sizes(),
"a Holger site ordered at Mini is Holger's Mini"
);
assert_eq!(
site::sizes_of_on(&state, Some("testh-holger-rs"), "Gigantic").unwrap(),
own[5].sizes()
);
let page =
ladder::ladder_on(&state, Some("testh-holger-rs"), "").expect("the Holger site's ladder");
assert_eq!(
page.steps
.iter()
.map(|p| p.step.clone())
.collect::<Vec<_>>(),
own,
"its page shows Holger's steps"
);
// Gunnar: unchanged.
let g = terms_on(&state, &base, Some("gunnar-rs")).expect("gunnar.rs's terms");
assert_eq!(g.ladder, base.ladder);
assert_eq!(base.ladder, default_ladder());
assert_eq!(
site::sizes_of_on(&state, Some("gunnar-rs"), "Mini").unwrap(),
base.ladder[0].sizes()
);
assert_eq!(
site::sizes_of(&state, "Mini").unwrap(),
base.ladder[0].sizes()
);
let gp = ladder::ladder_on(&state, Some("gunnar-rs"), "").expect("gunnar.rs's ladder");
assert_eq!(
gp.steps.iter().map(|p| p.step.clone()).collect::<Vec<_>>(),
base.ladder
);
}
/// ★ Lane L18: **the shop pairs each estate as its own product** — a Holger site's run hands the
/// pairing Holger's facts (its seeds, variant, sale proof and front feed), Gunnar's sites Gunnar's.
#[test]
fn a_holger_site_is_paired_as_holger_and_gunnars_as_gunnar() {
let (state, base) = shop_with_a_holger_site("holger-pairing-product");
let h = terms_on(&state, &base, Some("testh-holger-rs")).unwrap();
assert_eq!(
pairing_facts(&h),
crate::testing::lifecycles::holger_facts(),
"Holger's own facts: its contract and its sale proof"
);
let g = terms_on(&state, &base, Some("gunnar-rs")).unwrap();
assert_eq!(
pairing_facts(&g),
crate::testing::lifecycles::gunnar_facts()
);
}
/// ★ Owner 2026-10-23: every disk of a fresh Holger estate is UpCloud's `hdd` tier, the cheapest
/// for live servers (the front's system, main's system and data, the twin's system and data), and
/// the native lay names it (no template: the medium path). Only new lays and grown disks follow
/// it; laid disks keep their tier. The guest's copy (holger-monetize-guest) is pinned to this one.
#[test]
fn every_disk_of_a_fresh_holger_shape_is_hdd() {
// Its own lifecycles: under nextest (one process per test) no other test registered them.
crate::testing::lifecycles::install();
let shape = crate::testing::lifecycles::holger_shape();
let tiers: Vec<(&str, &str)> = [&shape.front, &shape.main, &shape.twin]
.iter()
.flat_map(|m| m.disks.iter().map(|d| (d.volume.as_str(), d.tier.as_str())))
.collect();
assert_eq!(tiers.len(), 5, "{tiers:?}");
assert!(tiers.iter().all(|(_, t)| *t == "hdd"), "{tiers:?}");
let c = EstateOrderConfig {
lifecycle: "holger".into(),
shape,
..cfg()
};
let plan = lifecycle::lay_plan_of(
&c,
"acme",
&EstateSizes {
main_data_gib: 240,
..Default::default()
},
"",
)
.expect("laid");
let laid: Vec<&str> = plan
.machines
.iter()
.flat_map(|m| m.disks.iter().map(|d| d.tier.as_str()))
.collect();
assert_eq!(laid, ["hdd"; 5], "{laid:?}");
}