crates/monetize-fast/tests/facts_drive_the_estate.rs
//! ★ **The fast test lays what the product's facts say** (A28 H14, lane N3): monetize-fast
//! names no product. A product kind it has never heard of, registered with the server's
//! lifecycle registry (as a signed guest's `lifecycle.facts` is, by `guest_lifecycle::follow`),
//! is laid, given its media and declared on the ONE box by its own names.
//!
//! Its own test binary: the lifecycle registry is process-wide.
use std::sync::Arc;
use monetize_server::estate_order::lifecycle::{self, EstateLifecycle, UpdatePlan};
use monetize_cloud::lay::EstatePlan;
use monetize_server::estate_order::{EstateOrderConfig, EstateSizes, Shape};
/// A product of three machines with names of its own (no Holger, no Gunnar).
struct Trio;
fn shape() -> Shape {
let m = |host: &str, plan: &str, role: &str| serde_json::json!({"hostname": format!("{host}-{{company}}"), "title": host, "plan": plan, "role_label": role, "disks": []});
serde_json::from_value(serde_json::json!({
"front": m("trio-door", "STARTER-2xCPU-4GB", "front"),
"main": m("trio-core", "8xCPU-32GB", "primary"),
"twin": m("trio-mirror", "STARTER-1xCPU-2GB", "twin"),
}))
.expect("a shape")
}
impl EstateLifecycle for Trio {
fn kind(&self) -> &str {
"trio"
}
fn lay_plan(&self, _: &EstateOrderConfig, _: &str, _: &EstateSizes, _: &str) -> Result<EstatePlan, String> {
Err("not laid in this test".into())
}
fn update_plan(&self) -> UpdatePlan {
UpdatePlan {
order: vec!["twin".into(), "main".into(), "front".into()],
app_medium: "trio".into(),
front_medium: "trio-door".into(),
front_role: "front".into(),
keep_medium: "trio-keep".into(),
front_keep_medium: "trio-door-keep".into(),
upgraded_by_shop: vec!["main".into(), "twin".into()],
live_slot: false,
}
}
fn medium_kind(&self, role: &str) -> String {
if role == "front" { "trio-door".into() } else { "trio".into() }
}
fn backup_roles(&self) -> Vec<String> {
vec!["main".into()]
}
fn default_shape(&self) -> Option<Shape> {
Some(shape())
}
}
#[test]
fn a_product_the_fast_test_never_heard_of_is_laid_by_its_own_facts() {
assert!(monetize_fast::estate_of("trio", "acme", "10.13").is_err(), "no lifecycle yet: refused by name");
lifecycle::register("trio", Arc::new(Trio));
let e = monetize_fast::estate_of("trio", "acme", "10.13").expect("its facts name its estate");
assert_eq!(e.iter().map(|l| (l.role, l.hostname.as_str(), l.cores, l.mem_mb)).collect::<Vec<_>>(), vec![("front", "trio-door-acme", 2, 4096), ("main", "trio-core-acme", 8, 32768), ("twin", "trio-mirror-acme", 1, 2048)]);
let kinds: Vec<(String, String)> = monetize_fast::one_box::media_kinds("trio").expect("its media").iter().map(|(k, p)| (k.to_string(), p.to_string())).collect();
let want = [("trio-door", "trio-door-"), ("trio", "trio-core-"), ("trio-keep", "trio-core-"), ("trio-door-keep", "trio-door-")];
assert_eq!(kinds, want.iter().map(|(k, p)| (k.to_string(), p.to_string())).collect::<Vec<_>>());
let d = monetize_fast::one_box::declaration("trio", "acme", &monetize_fast::one_box::RunNet { gateway: "10.13.15.254", one_ip: "10.13.8.90", ports: monetize_fast::one_box::ports_of(0).unwrap() }, "PEM", &["grpc".to_string()], &[]);
assert!(d.contains("[products.trio]") && d.contains("[vendors.stripe.trio]") && d.contains("MONETIZE_STRIPE_TRIO_SECRET_KEY"), "{d}");
for other in ["holger", "gunnar"] {
assert!(!d.to_lowercase().contains(other), "the trio's ONE box names no {other}: {d}");
}
lifecycle::unregister("trio");
}