crates/monetize-admin/tests/money_flow.rs
//! ★ **THE MONEY FLOW on the ONE box's own program** (moved from monetize-impl's `money-flow`
//! crate in v2.0 P2 12.2, A28 M4, before that crate goes): its 18 cases, each named as it was
//! there, now over [`monetize_admin::linked()`] exactly, the state opened by
//! `monetize_server::cli::open_state` from the `monetize.toml` that `monetize_front::intake::apply_pull`
//! writes out of a FEED shaped as the ONE box's installer feeds it, with the SIGNED guests: the
//! Stripe guest (`vendor.stripe.<instance>.*`), the UpCloud guest (`cloud.upcloud.*`) and the
//! Gunnar guest (`plugin.gunnar.*`, pulled: `instance = "gunnar.rs"`). Fakes ONLY at the edges:
//!
//! * **Stripe** — `fake_stripe_serve` as a PROCESS (its control door is the buyer and Stripe's
//! dashboard; its signed events are POSTed to the box's `/callback/stripe/<instance>`);
//! * **UpCloud** — `mock-upcloud`, in process, dialled by the signed UpCloud guest;
//! * **the estates' boxes** — [`GunnarBox`], which signs its Fleet calls with its own key and
//! checks every order it pulls with `monetize_embed::fleet::verify_order` (signature under the
//! box's monetize key, addressee, replay, expiry), then verifies each fact and snapshot.
//!
//! What moved, against money-flow: `Linked::commercial()` (the native gunnar plugin, the linked
//! Stripe and UpCloud providers, the in-process FakeStripe) is `linked()` with the signed guests;
//! a free account is made through Stripe's 0 kr card check (A15), as main now does; the box's
//! gate is `verify_order` and the order bodies are decoded here, not by `gunnar_repair` (the
//! gunnar-repair half — that GUNNAR's `accept_order` takes each kind, its `sign_in::mail` words —
//! is gunnar's own to test; see gunnar `crates/gunnar-repair`). The estate orders' installer is
//! the stand-in kit and their DNS a recording file, as money-flow had them.
//!
//! Inputs (feature `trials`; a missing input FAILS by name): `MONETIZE_TRIAL_GUESTS`,
//! `MONETIZE_FAKE_STRIPE`; `cargo xtask trials` builds both and runs this after the 12 trials.
//! With `MONETIZE_TRIAL_OUT=<dir>` each case writes `money-flow-<case>.json` there. MOCK ONLY:
//! test keys, loopback everything.
#![cfg(feature = "trials")]
mod common;
use std::collections::BTreeMap;
use std::path::PathBuf;
use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::{Arc, Mutex};
use std::time::{Duration, Instant};
use common::{b64 as b64_bytes, inputs, sign_into, FakeStripe};
use ed25519_dalek::{Signer as _, SigningKey, VerifyingKey};
use mock_upcloud::estate::Estate;
use mock_upcloud::{Clock, Faults, Mock};
use monetize_embed::fleet::{
call, kind, verify_order, Ask, FleetCall, GrowGoAhead, GrowSetAsk, OrderAck, OrderRefusal,
OrdersAfter, Report,
};
use monetize_embed::{ActorTicket, EntitlementFact, Snapshot, PURPOSE_ESTATE, PURPOSE_ORDER};
use monetize_product::pull::ProductReport;
use monetize_product::{Growth, Servable, TenantId, TenantOwner};
use monetize_proto as pb;
use monetize_server::config::Config;
use monetize_server::custody::Custody;
use monetize_server::estate_order::{
self, phase, EstateOrderConfig, EstateOrders, EstateSizes, FileDns, InstallRequest,
InstallVerdict, Installer, VERDICT_FILE,
};
use monetize_server::state::AppState;
use monetize_server::testing::{http_post, TestServer};
use tonic::metadata::MetadataValue;
use tonic::Request;
const SK: &str = "sk_test_MONEYflowNEVERlive";
const WHSEC: &str = "whsec_test_MONEYflow";
const BEARER: &str = "money-flow-bearer-of-sufficient-length";
const GIB: u64 = 1 << 30;
const DAY: u64 = 86_400_000;
/// gunnar.rs: the estate whose main serves product gunnar's own tenants (`[products.gunnar] instance`).
const SAAS: &str = "gunnar.rs";
/// The zone the estates are laid in at the mock.
const ZONE: &str = "se-sto1";
/// One ONE box is built at a time: `linked()` reads its data root from the process's
/// environment (`MONETIZE_ADMIN_DATA`).
static BUILDING: Mutex<()> = Mutex::new(());
fn wall_ms() -> u64 {
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_millis() as u64
}
fn b64(k: [u8; 32]) -> String {
monetize_embed::signing::base64_encode(&k)
}
/// The appliance key of the shop's OWN Gunnar (gunnar.rs): `[products.gunnar] appliance_key`.
const APPLIANCE_SEED: [u8; 32] = [41; 32];
fn appliance_key_hex() -> String {
SigningKey::from_bytes(&APPLIANCE_SEED)
.verifying_key()
.to_bytes()
.iter()
.map(|b| format!("{b:02x}"))
.collect()
}
/// **The signed-in buyer's word** — what gunnar.rs's `Billing.MintActorTicket` hands its console
/// for `account`: one verb, `caps` for an order, minted under the shop's own Gunnar's appliance
/// key, fresh (wall clock: the product checks it against its own) and never spent before.
fn ticket(account: &str, purpose: &str, caps: BTreeMap<String, u64>) -> Vec<u8> {
ticket_under(APPLIANCE_SEED, account, purpose, caps)
}
/// [`ticket`] minted under the appliance key `seed` (a site's own main, ST-3).
fn ticket_under(
seed: [u8; 32],
account: &str,
purpose: &str,
caps: BTreeMap<String, u64>,
) -> Vec<u8> {
static NONCE: AtomicU64 = AtomicU64::new(0);
let nonce = format!(
"money-flow-{}-{}",
std::process::id(),
NONCE.fetch_add(1, Ordering::SeqCst)
);
let mut t = ActorTicket::unsigned(
"gunnar",
"gunnar",
account,
purpose,
nonce,
wall_ms() as i64,
5 * 60_000,
)
.covering(caps);
let sig = SigningKey::from_bytes(&seed).sign(&monetize_embed::ticket::ticket_message(&t));
t.signature = monetize_embed::signing::base64_encode(&sig.to_bytes());
serde_json::to_vec(&t).unwrap()
}
/// The account's `estate` ticket: Start, Status, Renew, ChangePlan, Purchases.
fn estate_ticket(account: &str) -> Vec<u8> {
ticket(account, PURPOSE_ESTATE, BTreeMap::new())
}
fn ten_gib() -> BTreeMap<String, u64> {
[("pack_bytes".to_string(), 10 * GIB)].into_iter().collect()
}
/// Prints how long the scenario took when it ends, passed or not.
struct Timed(&'static str, Instant);
impl Drop for Timed {
/// The case's time, and its VERDICT where `cargo xtask trials` gathers it
/// (`MONETIZE_TRIAL_OUT/money-flow-<case>.json`, the case named as libtest names its thread):
/// a case that panicked is a FAIL row.
fn drop(&mut self) {
use std::io::Write as _;
let ms = self.1.elapsed().as_millis();
// Straight to the process's stderr: libtest captures `eprintln!` of a passing test.
let _ = writeln!(std::io::stderr(), "MONEY-FLOW {ms:>6} ms {}", self.0);
if let (Some(dir), Some(case)) = (
std::env::var_os("MONETIZE_TRIAL_OUT"),
std::thread::current()
.name()
.map(|n| n.rsplit("::").next().unwrap_or(n).to_owned()),
) {
let dir = PathBuf::from(dir);
let _ = std::fs::create_dir_all(&dir);
let pass = !std::thread::panicking();
let detail = if pass {
self.0.to_string()
} else {
format!(
"{}: the case failed (its panic is in the test's output)",
self.0
)
};
let v = serde_json::json!({"name": format!("money-flow-{case}"), "trial": format!("money-flow/{case}"), "site": "gunnar", "where": "linked", "pass": pass, "detail": detail, "secs": (ms as f64 / 100.0).round() / 10.0});
let _ = std::fs::write(
dir.join(format!("money-flow-{case}.json")),
serde_json::to_vec_pretty(&v).unwrap(),
);
}
}
}
// ─── the estate side: a gunnar box on the pull channel ─────────────────────────────────────
/// **One gunnar box**: its fleet key, its health words, the orders it pulled — each through the
/// box's check (`monetize_embed::fleet::verify_order`: signature under the box's monetize key,
/// addressee, replay, expiry; an unknown kind is refused by its verb) — and what they did to it.
struct GunnarBox {
instance: String,
role: String,
key: SigningKey,
monetize: [u8; 32],
health: BTreeMap<String, String>,
last_seq: u64,
acks: Vec<OrderAck>,
/// The kinds it ran (the gate passed and the verb said ok).
ran: Vec<String>,
/// `kind: why` for every order the gate or the verb refused (acked not ok).
refused: Vec<String>,
/// Orders that do not verify under the box's monetize key: dropped, never acked.
forged: Vec<String>,
/// The verified entitlement facts it holds, by tenant (as this gunnar names it).
entitled: BTreeMap<String, EntitlementFact>,
/// Principals made by `add_principal`, and by which signup.
principals: BTreeMap<String, String>,
restated: Vec<u64>,
/// The main of a pulled product reports its product part (tenants, names, room).
reports_product: bool,
/// S10: the sign-in invites this box minted itself, `(account, secret)` — the estate's
/// own, never the shop's.
minted: Vec<(String, String)>,
/// S10: the mails this box sent itself, `(to, body)`.
mailed: Vec<(String, String)>,
}
impl GunnarBox {
fn new(instance: &str, role: &str, seed: [u8; 32], monetize_pubkey: [u8; 32]) -> Self {
let mut health = BTreeMap::new();
health.insert(
"serving".into(),
if role == "main" { "yes" } else { "no" }.into(),
);
health.insert("data".into(), "ok".into());
health.insert(
"serves_at".into(),
format!("10.6.0.{}:50051", if role == "main" { 10 } else { 12 }),
);
health.insert(
if role == "main" { "twin" } else { "primary" }.into(),
if role == "main" { "paired" } else { "live" }.into(),
);
GunnarBox {
instance: instance.into(),
role: role.into(),
key: SigningKey::from_bytes(&seed),
monetize: monetize_pubkey,
health,
last_seq: 0,
acks: Vec::new(),
ran: Vec::new(),
refused: Vec::new(),
forged: Vec::new(),
entitled: BTreeMap::new(),
principals: BTreeMap::new(),
restated: Vec::new(),
reports_product: false,
minted: Vec::new(),
mailed: Vec::new(),
}
}
fn public_key(&self) -> [u8; 32] {
self.key.verifying_key().to_bytes()
}
fn verifying(&self) -> VerifyingKey {
VerifyingKey::from_bytes(&self.monetize).unwrap()
}
fn set(&mut self, word: &str, value: &str) {
self.health.insert(word.into(), value.into());
}
fn signed(&self, which: &str, body: String, at: u64, pin: bool) -> pb::FleetSigned {
let c = FleetCall {
product: "gunnar".into(),
instance: self.instance.clone(),
role: self.role.clone(),
call: which.into(),
body,
at_unix_ms: at,
};
let signature = self
.key
.sign(&monetize_embed::fleet::fleet_call_message(&c))
.to_bytes()
.to_vec();
pb::FleetSigned {
product: c.product,
instance: c.instance,
role: c.role,
call: c.call,
body: c.body,
at_unix_ms: c.at_unix_ms,
signature,
box_key: if pin {
self.public_key().to_vec()
} else {
Vec::new()
},
}
}
/// What a pulled product's main says of its product: every principal is a person's tenant,
/// every name is taken, and there is room.
fn product_part(&self, now: u64) -> Option<String> {
if !self.reports_product {
return None;
}
let names: Vec<String> = self.principals.keys().cloned().collect();
let p = ProductReport {
tenants: names
.iter()
.map(|n| TenantOwner {
tenant: TenantId(n.clone()),
person: true,
seller: false,
})
.collect(),
names: names.clone(),
servable: Some(Servable::Measured {
servable_bytes: 1 << 40,
total_bytes: 2 << 40,
growth: Growth::Unknown("money-flow".into()),
ceilings: BTreeMap::new(),
}),
room: [("pack_bytes".to_string(), 1u64 << 40)]
.into_iter()
.collect(),
measured_unix_ms: now,
..Default::default()
};
Some(serde_json::to_string(&p).unwrap())
}
fn report_call(&mut self, at: u64, pin: bool) -> pb::FleetSigned {
let r = Report {
build: "gunnar-money-flow".into(),
health: self.health.clone(),
acked: std::mem::take(&mut self.acks),
twin_review: None,
product: self.product_part(at),
measured_unix_ms: at,
};
self.signed(call::REPORT, serde_json::to_string(&r).unwrap(), at, pin)
}
fn orders_call(&self, at: u64) -> pb::FleetSigned {
self.signed(
call::ORDERS,
serde_json::to_string(&OrdersAfter {
after: self.last_seq,
wait_ms: 0,
})
.unwrap(),
at,
false,
)
}
fn grow_set_call(&self, members: &[String], gib: u64, at: u64) -> pb::FleetSigned {
let body = serde_json::to_value(GrowSetAsk {
members: members.to_vec(),
gib,
})
.unwrap();
self.signed(
call::ASK,
serde_json::to_string(&Ask {
kind: monetize_embed::fleet::ask::GROW_SET.into(),
body,
})
.unwrap(),
at,
false,
)
}
/// **The box runs what it pulled**, as gunnar's puller does: an order that does not verify
/// under the monetize key is dropped unacked; one already run is skipped; one for another
/// box or past its time is acked refused; the rest run their verb, whose answer rides the
/// next report. Answers the kinds it ran.
fn run(&mut self, mut orders: Vec<pb::FleetOrder>, now: u64) -> Vec<String> {
orders.sort_by_key(|o| o.seq);
let mut ran = Vec::new();
for o in orders {
let so = monetize_server::services::fleet::order_of(&o);
let (ok, detail) = match verify_order(
&so,
&self.verifying(),
("gunnar", &self.instance, &self.role),
now,
self.last_seq,
) {
Err(OrderRefusal::Signature) => {
self.forged.push(format!(
"{}: the order does not verify under this box's monetize key",
o.kind
));
continue;
}
Err(OrderRefusal::Replayed { .. }) => continue,
Err(e) => {
self.last_seq = self.last_seq.max(o.seq);
(false, e.to_string())
}
Ok(()) => {
self.last_seq = o.seq;
self.verb(&o, now)
}
};
if ok {
self.ran.push(o.kind.clone());
ran.push(o.kind.clone());
} else {
self.refused.push(format!("{}: {detail}", o.kind));
}
self.acks.push(OrderAck {
seq: o.seq,
ok,
detail,
receipt_json: String::new(),
});
}
ran
}
/// The verb of an order that passed the check, read off its body as gunnar's box reads it.
fn verb(&mut self, o: &pb::FleetOrder, now: u64) -> (bool, String) {
use monetize_product::pull::order;
match o.kind.as_str() {
order::ENTITLEMENT => {
let fact: EntitlementFact = match serde_json::from_str(&o.body) {
Ok(f) => f,
Err(e) => return (false, format!("the fact does not parse: {e}")),
};
if let Err(e) = monetize_embed::signing::verify_fact(&fact, &self.verifying()) {
return (
false,
format!("the fact does not verify under this box's monetize key: {e}"),
);
}
let t = fact.tenant.0.clone();
self.hold(fact);
(true, format!("entitled {t}"))
}
order::ADD_PRINCIPAL => {
let a: monetize_product::pull::AddPrincipal = match serde_json::from_str(&o.body) {
Ok(a) => a,
Err(e) => return (false, format!("not an add_principal: {e}")),
};
match self.principals.get(&a.username) {
Some(by) if *by == a.signup => (true, a.username),
Some(_) => (false, format!("{} {}", order::TAKEN, a.username)),
None => {
self.principals.insert(a.username.clone(), a.signup);
(true, a.username)
}
}
}
kind::RESTATE_ENTITLEMENTS => {
if self.health.get("serving").map(String::as_str) != Some("yes") {
return (false, "this box does not serve".into());
}
let body: serde_json::Value = match serde_json::from_str(&o.body) {
Ok(b) => b,
Err(e) => return (false, format!("the body does not parse: {e}")),
};
let snap: Snapshot = match serde_json::from_value(body["snapshot"].clone()) {
Ok(s) => s,
Err(e) => return (false, format!("the snapshot does not parse: {e}")),
};
if let Err(e) = monetize_embed::signing::verify_snapshot(&snap, &self.verifying()) {
return (false, format!("the snapshot does not verify: {e}"));
}
let n = snap.facts.len();
for f in snap.facts {
self.hold(f);
}
self.restated.push(snap.issued_unix_ms);
(true, format!("restated {n} facts"))
}
kind::RECHARGE_FROM_TWIN => {
self.set("data", "ok");
self.set("serving", "yes");
self.set("recharge", "done");
(true, "recharged from the twin".into())
}
kind::FENCE_PRIMARY => {
self.set("serving", "fenced");
(true, "fenced".into())
}
kind::ADOPT_TWIN => {
self.set("twin", "paired");
(true, "adopted".into())
}
kind::REVIEW_TWIN => (true, "the twin is current".into()),
// The box's G16-d checks of a paid data step.
kind::GROW_GO_AHEAD => {
let b: GrowGoAhead = match serde_json::from_str(&o.body) {
Ok(b) => b,
Err(e) => return (false, format!("the go-ahead does not parse: {e}")),
};
let g = match monetize_embed::signing::verify_estate_growth(
b.go_ahead.as_bytes(),
&self.verifying(),
) {
Ok(g) => g,
Err(e) => {
return (
false,
format!("the step does not verify under this box's monetize key: {e}"),
)
}
};
if g.estate != self.instance || g.until_unix_ms <= now as i64 {
return (
false,
format!("the step is for {} until {}", g.estate, g.until_unix_ms),
);
}
let fits = if self.role == "main" {
b.data_gib == g.main_data_gib_per_member
} else {
b.data_gib >= g.main_data_gib_per_member
};
if !fits {
return (
false,
format!("{} GB a disk is not what {} is paid", b.data_gib, self.role),
);
}
(true, format!("grow to {} GB", b.data_gib))
}
// S10: the box mints a secret itself and mails the link — the shop never sees it. The
// link's shape is Gunnar's (`https://{host}/login?invite=…&user=…`, gunnar-repair
// `sign_in::link`, which gunnar's own tests hold).
kind::SIGN_IN_AGAIN => {
let a: monetize_embed::fleet::SignInAgain = match serde_json::from_str(&o.body) {
Ok(a) => a,
Err(e) => return (false, format!("not a sign_in_again: {e}")),
};
let secret = format!("minted-by-{}-{}", self.instance, o.seq);
let link = format!(
"https://{}/login?invite={secret}&user={}",
a.host, a.account
);
self.minted.push((a.account.clone(), secret));
self.mailed.push((a.to.clone(), link));
(true, format!("mailed {}", a.to))
}
other => (false, format!("no verb for {other}")),
}
}
/// Newer wins, per tenant; nothing is deleted.
fn hold(&mut self, f: EntitlementFact) {
let newer = self
.entitled
.get(&f.tenant.0)
.is_none_or(|h| f.issued_unix_ms.unwrap_or(0) >= h.issued_unix_ms.unwrap_or(0));
if newer {
self.entitled.insert(f.tenant.0.clone(), f);
}
}
}
// ─── the edges' fakes on the shop side ──────────────────────────────────────────────────────
/// The kit's stand-in: it writes a PASS verdict naming no box key, so every box pins its own
/// on its first call inside the install's window (G7).
struct StandInKit;
impl Installer for StandInKit {
fn install(&self, req: &InstallRequest) -> Result<InstallVerdict, String> {
let v = InstallVerdict {
verdict: "PASS".into(),
detail: "stand-in".into(),
receipt: serde_json::json!({"verdict": "PASS"}),
peers: Vec::new(),
appliance_keys: Default::default(),
ticket_key: String::new(),
};
std::fs::write(req.run.join(VERDICT_FILE), serde_json::to_vec(&v).unwrap())
.map_err(|e| e.to_string())?;
Ok(v)
}
/// The sale check (S4) stood in: this stand-in estate has no public front to read; the
/// shop's own pairing reads it (monetize-shop-pairing `sale_check`).
fn sale_check(
&self,
at: &monetize_server::estate_order::SaleCheckAt<'_>,
) -> Result<String, String> {
Ok(format!("stand-in: https://{} is not read here", at.host))
}
}
/// test2's site on the ONE box (ST-17): its own estate, Stripe account and main.
const TEST2: &str = "test2.gunnar.rs";
/// test2's main's ticket key (`[estates."test2.gunnar.rs"] appliance_key`).
const TEST2_APPLIANCE_SEED: [u8; 32] = [42; 32];
const TEST2_MAIN_SEED: [u8; 32] = [22; 32];
const HOME_BEARER: &str = "money-flow-gunnar-rs-estate-bearer-0123456789";
const TEST2_BEARER: &str = "money-flow-test2-estate-bearer-0123456789";
/// **The two sites the ONE box sells for** (owner 2026-10-11): gunnar.rs and test2, each with
/// its own Stripe account and its own main.
fn two_sites() -> String {
let t2: String = SigningKey::from_bytes(&TEST2_APPLIANCE_SEED)
.verifying_key()
.to_bytes()
.iter()
.map(|b| format!("{b:02x}"))
.collect();
format!(
r#"
[estates."{SAAS}"]
product = "gunnar"
vendor = "stripe/gunnar"
owner = "ignalina"
site = "gunnar.test"
[estates."{TEST2}"]
product = "gunnar"
vendor = "stripe/gunnar-test2"
owner = "ignalina"
site = "test2.gunnar.test"
appliance_key = "{t2}"
"#
)
}
/// The operator's fragment (`monetize.toml`): the sign-up plans money-flow sold, SE, FI and DK.
fn fragment() -> String {
r#"
[signups.gunnar.plans."gunnar/account"]
amount_minor = 0
currency = "Sek"
cap_bytes = 0
period_days = 0
[signups.gunnar.plans."gunnar/10gb-1m"]
amount_minor = 10000
currency = "Sek"
cap_bytes = 10737418240
period_days = 30
[signups.gunnar.plans."gunnar/10gb-1m-fi"]
amount_minor = 1000
currency = "Eur"
cap_bytes = 10737418240
period_days = 30
[signups.gunnar.plans."gunnar/10gb-1m-dk"]
amount_minor = 7500
currency = "Dkk"
cap_bytes = 10737418240
period_days = 30
"#
.to_string()
}
/// **The feed**, as the ONE box's installer sends it (private-monetize-ops `solo::feed_of`):
/// the SIGNED Stripe guest for each Stripe account the sites sell through, the SIGNED UpCloud
/// guest at the mock, the SIGNED Gunnar guest pulled from gunnar.rs's main (its fleet key and
/// its ticket key named, as money-flow's config named them), and the operator's fragment.
fn feed(
dir: &std::path::Path,
stripe: &str,
upcloud: u16,
main_key: [u8; 32],
extra: &str,
) -> BTreeMap<String, String> {
use guest_host::verify::sign::dev;
let inp = inputs();
let (ca_key, ca_der) = dev::mint_ca("money-flow-plugin-root").unwrap();
let signer = dev::new_ed25519_signer(&ca_key, &ca_der, "money-flow-signing").unwrap();
let signed =
|name: &str| sign_into(dir, &inp.guests.join(format!("{name}.wasm")), name, &signer);
let mut f = BTreeMap::new();
f.insert("plugin_root.money-flow".to_string(), b64_bytes(&ca_der));
let (sw, sp) = signed("stripe");
for instance in ["gunnar", "gunnar-test2"] {
let env = instance.to_ascii_uppercase().replace('-', "_");
let (key, hook) = (
format!("MONETIZE_STRIPE_{env}_SECRET_KEY"),
format!("MONETIZE_STRIPE_{env}_WEBHOOK_SECRET"),
);
f.insert(format!("vendor.stripe.{instance}.wasm"), b64_bytes(&sw));
f.insert(format!("vendor.stripe.{instance}.p7s"), b64_bytes(&sp));
f.insert(
format!("vendor.stripe.{instance}.toml"),
format!(
"enabled = true\ncountry = \"IE\"\ngrants = [\"http\", \"hmac\", \"state\"]\nhttp_hosts = [\"{stripe}\"]\nhmac_secrets = [\"{hook}\"]\nbase_url = \"{stripe}\"\nsuccess_url = \"https://gunnar.test/paid/{{reference}}\"\ncancel_url = \"https://gunnar.test/cancel/{{reference}}\"\nlivemode = false\ntax_code = \"txcd_10103001\"\nwebhook_secret = \"{hook}\"\n[[http_auth]]\nhost = \"{stripe}\"\nprefix = \"Bearer \"\nsecret = \"{key}\"\n"
),
);
f.insert(format!("secret.{key}"), SK.into());
f.insert(format!("secret.{hook}"), WHSEC.into());
}
let up = format!("http://127.0.0.1:{upcloud}");
let (uw, upp) = signed("upcloud");
f.insert("cloud.upcloud.wasm".into(), b64_bytes(&uw));
f.insert("cloud.upcloud.p7s".into(), b64_bytes(&upp));
// The mock's token is no account-wide credential: `allow_grow` is for production.
f.insert(
"cloud.upcloud.toml".into(),
format!("enabled = true\ncap = {{ monthly_minor = 10000000, currency = \"Eur\" }}\ncountry = \"FI\"\nzone = \"{ZONE}\"\nallow_grow = true\ngrants = [\"http\", \"state\"]\nhttp_hosts = [\"{up}\"]\napi_base = \"{up}\"\n[[http_auth]]\nhost = \"{up}\"\nprefix = \"Bearer \"\nsecret = \"upcloud_token\"\n"),
);
f.insert(
"secret.upcloud_token".into(),
"ucat_mock_money_flow_not_a_real_token".into(),
);
let (gw, gp) = signed("gunnar");
f.insert("plugin.gunnar.wasm".into(), b64_bytes(&gw));
f.insert("plugin.gunnar.p7s".into(), b64_bytes(&gp));
f.insert(
"plugin.gunnar.toml".into(),
format!("vendor = \"stripe/gunnar\"\ninstance = \"{SAAS}\"\ngrants = []\nappliance_key = \"{}\"\nfleet_keys = {{ main = \"{}\" }}\n", appliance_key_hex(), b64(main_key)),
);
f.insert(
"plugin.gunnar.prices".into(),
"[SE]\ndisk_gib_month = 2200\n".into(),
);
f.insert("monetize.toml".into(), format!("{}{extra}", fragment()));
f
}
// ─── the world ──────────────────────────────────────────────────────────────────────────────
/// Fields drop in order: the server, then the state (its UpCloud provider owns a blocking
/// client), then the runtime — all outside any async context.
struct World {
server: Option<TestServer>,
state: Arc<AppState>,
fake: FakeStripe,
_mock: Arc<Mock>,
channel: tonic::transport::Channel,
/// Time the test moves monetize's clock on by (real time underneath: Stripe signs with it).
skew: Arc<AtomicU64>,
/// gunnar.rs's main, the box that serves product gunnar's own tenants.
main: GunnarBox,
rt: tokio::runtime::Runtime,
_dir: PathBuf,
}
const MAIN_SEED: [u8; 32] = [21; 32];
impl World {
fn new(name: &str) -> World {
World::new_with(name, "")
}
/// [`World::new`] with `extra` appended to the ONE box's config (ST-17: [`two_sites`]).
fn new_with(name: &str, extra: &str) -> World {
let dir = PathBuf::from(env!("CARGO_TARGET_TMPDIR"))
.join(format!("money-flow-{name}-{}", std::process::id()));
let _ = std::fs::remove_dir_all(&dir);
std::fs::create_dir_all(dir.join("guests")).unwrap();
let rt = tokio::runtime::Builder::new_multi_thread()
.worker_threads(4)
.enable_all()
.build()
.unwrap();
let fake = FakeStripe::start(&inputs().fake_stripe, SK, WHSEC);
let mock = Mock::recording(Estate::new(Clock::new(1_000_000), Faults::none(), 11));
let port = rt
.block_on(mock_upcloud::serve(mock.clone(), "127.0.0.1:0"))
.unwrap()
.0;
let main_key = SigningKey::from_bytes(&MAIN_SEED)
.verifying_key()
.to_bytes();
let skew = Arc::new(AtomicU64::new(0));
let root = dir.join("data");
let state = {
let _one = BUILDING.lock().unwrap_or_else(|e| e.into_inner());
// As PID 1 does: monetize's token and key, then the feed taken in.
monetize_front::intake::prepare(&root).unwrap();
let refused = monetize_front::intake::apply_pull(
&root,
&feed(&dir.join("guests"), &fake.base(), port, main_key, extra),
)
.unwrap();
assert!(
refused.is_empty(),
"the ONE box refused part of the feed: {refused:#?}"
);
let path = root.join(monetize_front::intake::CONFIG_REL);
let cfg = Config::load(&path).unwrap_or_else(|e| {
panic!(
"{}: {e}\n{}",
path.display(),
std::fs::read_to_string(&path).unwrap_or_default()
)
});
std::env::set_var(monetize_admin::DATA_ENV, &root);
let linked = monetize_admin::linked();
let mut state = monetize_server::cli::open_state(&cfg, &linked)
.unwrap_or_else(|e| panic!("the ONE box does not open: {e:#}"));
// The Gunnar estate is laid and spoken of by the GUEST's lifecycle, never a native one
// (v2.0 P2: the natives go).
assert!(
monetize_server::estate_order::lifecycle::registered("gunnar").is_some(),
"the signed Gunnar guest brings its lifecycle: {:?}",
state.registry.start_refusals()
);
let k = skew.clone();
state.clock = Box::new(move || wall_ms() + k.load(Ordering::SeqCst));
// The shop's estate orders, as money-flow had them: the signed UpCloud guest lays, the
// stand-in kit installs, the DNS is a recording file.
let offer = EstateOrderConfig {
product: "gunnar".into(),
cloud: "upcloud".into(),
vendor: "stripe/gunnar".into(),
apex: "gunnar.rs".into(),
currency: "EUR".into(),
zone: ZONE.into(),
shop_door: "https://gunnar.monetize.test".into(),
..EstateOrderConfig::default()
};
state.estates = EstateOrders::with(
offer,
dir.join("estate-orders"),
Arc::new(StandInKit),
Arc::new(FileDns(dir.join("dns.json"))),
Custody::open(dir.join("custody")).unwrap(),
);
Arc::new(state)
};
let server = rt.block_on(TestServer::spawn(state.clone(), BEARER));
let channel = rt
.block_on(
tonic::transport::Channel::from_shared(server.endpoint())
.unwrap()
.connect(),
)
.unwrap();
let pk = state.signer_for("gunnar").public_key();
let mut main = GunnarBox::new(SAAS, "main", MAIN_SEED, pk);
main.reports_product = true;
let mut w = World {
server: Some(server),
state,
fake,
_mock: mock,
channel,
skew,
main,
rt,
_dir: dir,
};
let mut m = std::mem::replace(&mut w.main, GunnarBox::new(SAAS, "main", MAIN_SEED, pk));
w.report(&mut m);
w.main = m;
w
}
fn now(&self) -> u64 {
self.state.now()
}
fn later(&self, ms: u64) {
self.skew.fetch_add(ms, Ordering::SeqCst);
}
fn authed<T>(&self, m: T) -> Request<T> {
let mut r = Request::new(m);
r.metadata_mut().insert(
"authorization",
MetadataValue::try_from(format!("Bearer {BEARER}")).unwrap(),
);
r
}
fn fleet(&self) -> pb::fleet_client::FleetClient<tonic::transport::Channel> {
pb::fleet_client::FleetClient::new(self.channel.clone())
}
fn try_report(&self, b: &mut GunnarBox, pin: bool) -> Result<(), tonic::Status> {
let s = b.report_call(self.now(), pin);
let r = self.rt.block_on(self.fleet().report(s.clone()));
if r.is_err() {
// The acks ride the next report.
if let Ok(rep) = serde_json::from_str::<Report>(&s.body) {
let mut back = rep.acked;
back.append(&mut b.acks);
b.acks = back;
}
}
r.map(|_| ())
}
/// The box reports (its acks with it).
fn report(&self, b: &mut GunnarBox) {
self.try_report(b, false)
.unwrap_or_else(|e| panic!("{}/{} was not heard: {e}", b.instance, b.role));
}
fn orders(&self, b: &GunnarBox) -> Vec<pb::FleetOrder> {
let s = b.orders_call(self.now());
self.rt
.block_on(self.fleet().orders(s))
.unwrap_or_else(|e| panic!("{}/{} pulled nothing: {e}", b.instance, b.role))
.into_inner()
.orders
}
/// The box pulls its orders, runs them, and reports the acks. Answers the kinds it ran.
fn pull(&self, b: &mut GunnarBox) -> Vec<String> {
let orders = self.orders(b);
let ran = b.run(orders, wall_ms());
self.report(b);
ran
}
fn main_pulls(&mut self) -> Vec<String> {
let mut m = std::mem::replace(
&mut self.main,
GunnarBox::new(SAAS, "main", MAIN_SEED, [0; 32]),
);
let ran = self.pull(&mut m);
self.main = m;
ran
}
fn main_reports(&mut self) {
let mut m = std::mem::replace(
&mut self.main,
GunnarBox::new(SAAS, "main", MAIN_SEED, [0; 32]),
);
self.report(&mut m);
self.main = m;
}
fn ask_grow_set(
&self,
b: &GunnarBox,
members: &[String],
gib: u64,
) -> Result<String, tonic::Status> {
let s = b.grow_set_call(members, gib, self.now());
self.rt
.block_on(self.fleet().ask(s))
.map(|a| a.into_inner().words)
}
// ── Stripe (the fake as a process: its control door is the buyer and the dashboard) ──
/// The buyer pays `id` at Stripe's page; answers Stripe's signed event (not yet delivered).
fn pay(&self, id: &str) -> serde_json::Value {
let (st, ev) = self.fake.control("POST", &format!("/pay/{id}"));
assert_eq!(st, 200, "the fake Stripe's page refused to pay {id}: {ev}");
ev
}
/// Stripe's signed event delivered to `instance`'s own endpoint (`/callback/stripe/<instance>`).
fn deliver_event(&self, instance: &str, ev: &serde_json::Value) -> (u16, String) {
let headers = vec![
(
"Stripe-Signature".to_string(),
ev["signature"].as_str().unwrap_or_default().to_owned(),
),
("Content-Type".to_string(), "application/json".to_string()),
];
http_post(
self.server.as_ref().unwrap().addr,
&format!("/callback/stripe/{instance}"),
&headers,
ev["body"].as_str().unwrap_or_default().as_bytes(),
)
.unwrap()
}
/// `id` paid, and Stripe's `checkout.session.completed` delivered to gunnar's endpoint.
fn paid(&self, id: &str) -> (u16, String) {
let ev = self.pay(id);
self.deliver_event("gunnar", &ev)
}
/// The free account's 0 kr CARD CHECK (A15): the buyer checks a card on the `mode=setup`
/// page, and Stripe's signed `checkout.session.completed` is delivered (a card check is
/// settled by its RETURN page, the signup's status, never by the event: [`World::returns`]).
fn check_card(&self, session: &str, who: &str) -> (u16, String) {
self.check_card_at("gunnar", session, who)
}
/// [`World::check_card`] on `instance`'s Stripe account (a site's own).
fn check_card_at(&self, instance: &str, session: &str, who: &str) -> (u16, String) {
let (st, ev) = self.fake.control(
"POST",
&format!("/check-card/{session}/fp_money_flow_{who}"),
);
assert_eq!(
st, 200,
"the fake Stripe refused {who}'s card check on {session}: {ev}"
);
self.deliver_event(instance, &ev)
}
fn plans(&self, market: pb::Market) -> pb::SignupPlansResponse {
let mut c = pb::signup_client::SignupClient::new(self.channel.clone());
self.rt
.block_on(c.plans(self.authed(pb::SignupPlansRequest {
product: "gunnar".into(),
market: market as i32,
})))
.expect("Signup.Plans")
.into_inner()
}
fn start(
&self,
username: &str,
plan: &str,
market: pb::Market,
) -> Result<pb::StartSignupResponse, tonic::Status> {
self.start_as(username, plan, &format!("{username}@buyer.example"), market)
}
fn start_as(
&self,
username: &str,
plan: &str,
email: &str,
market: pb::Market,
) -> Result<pb::StartSignupResponse, tonic::Status> {
let mut c = pb::signup_client::SignupClient::new(self.channel.clone());
let req = pb::StartSignupRequest {
username: username.into(),
product: "gunnar".into(),
plan: plan.into(),
vendor: "stripe/gunnar".into(),
success_url: "https://gunnar.test/welcome".into(),
cancel_url: "https://gunnar.test/".into(),
email: email.into(),
market: market as i32,
};
self.rt
.block_on(c.start(self.authed(req)))
.map(|r| r.into_inner())
}
/// **A gunnar.rs account minted** — the page's first step for a visitor who has none, before
/// either kind of purchase (FLOW-TRACE J2: `signup.html` "Create your account" → the 0-SEK
/// `gunnar/account` plan): Stripe's 0 kr card check (A15: nothing charged), settled by the
/// return page; the main makes it from the `add_principal` it pulls; the signup is CREATED
/// with the address its sign-in mail goes to.
fn new_account(&mut self, username: &str, email: &str) {
let started = self
.start_as(username, "gunnar/account", email, pb::Market::Se)
.unwrap_or_else(|e| panic!("{username}: the account's Signup.Start: {e}"));
assert!(
self.fake.minted(&started.session),
"the 0 kr card check is the fake Stripe's: {started:?}"
);
let (code, said) = self.check_card(&started.session, username);
assert_eq!(code, 200, "{username}'s card check: {said}");
// The card check settles as the box's own loop (or the welcome page's poll) settles it.
self.until(&format!("{username}'s add_principal queued"), |w| {
w.returns("stripe/gunnar", &started.session);
w.queued_kinds(SAAS, "main")
.contains(&"add_principal".to_string())
});
assert_eq!(
self.main_pulls(),
["add_principal"],
"the main made {username}'s account: {:?}",
self.main.refused
);
monetize_server::signup::settle_pending(&self.state);
let st = self.status(&started.session);
assert_eq!(
st.state(),
pb::signup_status_response::State::Created,
"{username}: {st:?}"
);
}
fn estates(&self) -> pb::estate_order_client::EstateOrderClient<tonic::transport::Channel> {
pb::estate_order_client::EstateOrderClient::new(self.channel.clone())
}
/// `EstateOrder.Start` as the console sends it: `ticket` empty for a visitor nobody signed in.
fn estate_start(
&self,
company: &str,
email: &str,
account: &str,
ticket: Vec<u8>,
) -> Result<pb::EstateOrderStartResponse, tonic::Status> {
let req = pb::EstateOrderStartRequest {
company: company.into(),
email: email.into(),
account: account.into(),
actor_ticket: ticket,
..Default::default()
};
self.rt
.block_on(self.estates().start(self.authed(req)))
.map(|r| r.into_inner())
}
fn purchases(
&self,
account: &str,
ticket: Vec<u8>,
) -> Result<pb::EstateOrderPurchasesResponse, tonic::Status> {
let req = pb::EstateOrderPurchasesRequest {
account: account.into(),
actor_ticket: ticket,
};
self.rt
.block_on(self.estates().purchases(self.authed(req)))
.map(|r| r.into_inner())
}
/// **A private Gunnar bought SIGNED IN** (the console's `/auth/private/start`): the order
/// carries the account's `estate` ticket, so it is the PROVEN account's — then paid and
/// delivered as [`World::private_gunnar`] delivers one.
fn private_signed_in(&self, company: &str, account: &str) -> (GunnarBox, GunnarBox) {
let started = self
.estate_start(
company,
&format!("{account}@buyer.example"),
account,
estate_ticket(account),
)
.unwrap_or_else(|e| panic!("{account}: EstateOrder.Start {company}: {e}"));
let run = self
.state
.estates
.get(company)
.unwrap_or_else(|| panic!("no run for {company}: {started:?}"));
assert_eq!(run.account, account, "the order is the signed-in account's");
self.pay(&run.handle.as_ref().unwrap().id);
self.deliver(company)
}
/// **A 10 GB plan bought SIGNED IN** on `account`: `Purchase.Start` carrying the account's
/// `order` ticket covering exactly the caps bought → Stripe paid → the plan's signed
/// entitlement is an order gunnar.rs's main pulls and verifies.
fn plan_signed_in(&mut self, account: &str) {
// The main reports first, as a running main does every minute: the pulled product judges
// the buy on a FRESH report, however long this machine took to get here (a load-proof
// bound: no wall time between the last report and the buy is assumed).
self.main_reports();
let mut c = pb::purchase_client::PurchaseClient::new(self.channel.clone());
let req = pb::StartPurchaseRequest {
product: "gunnar".into(),
tenant: account.into(),
caps: ten_gib().into_iter().collect(),
vendor: "stripe/gunnar".into(),
payer: format!("{account}@buyer.example"),
market: pb::Market::Se as i32,
actor_ticket: ticket(account, PURPOSE_ORDER, ten_gib()),
..Default::default()
};
let started = self
.rt
.block_on(c.start(self.authed(req)))
.unwrap_or_else(|e| panic!("{account}: Purchase.Start, signed in: {e}"))
.into_inner();
let (code, said) = self.paid(&started.handle_id);
assert_eq!(code, 200, "{said}");
self.until(&format!("{account}'s plan entitlement queued"), |w| {
w.queued_kinds(SAAS, "main")
.contains(&"entitlement".to_string())
});
assert_eq!(
self.main_pulls(),
["entitlement"],
"{:?}",
self.main.refused
);
}
/// **nina, the OM-19 buyer** (h then i): her account minted first, acme1 bought signed in;
/// then, signed in again, acme2 and a 10 GB plan. Answers both estates' boxes.
fn nina_owns_two_private_gunnars_and_a_plan(&mut self) -> [(GunnarBox, GunnarBox); 2] {
self.new_account("nina", "nina@buyer.example");
let one = self.private_signed_in("acme1", "nina");
let two = self.private_signed_in("acme2", "nina");
self.plan_signed_in("nina");
[one, two]
}
/// The box pulls at monetize's (moved) clock, runs what it pulled, and reports.
fn pull_now(&self, b: &mut GunnarBox) -> Vec<String> {
let orders = self.orders(b);
let ran = b.run(orders, self.now());
self.report(b);
ran
}
/// **The buyer back on the return page** after a card check: the signup's status asked,
/// which settles it (the account is then an `add_principal` order its main pulls).
fn returns(&self, vendor: &str, session: &str) {
let mut c = pb::signup_client::SignupClient::new(self.channel.clone());
let _ = self
.rt
.block_on(c.status(self.authed(pb::SignupStatusRequest {
vendor: vendor.into(),
session: session.into(),
})));
}
fn status(&self, session: &str) -> pb::SignupStatusResponse {
let mut c = pb::signup_client::SignupClient::new(self.channel.clone());
self.rt
.block_on(c.status(self.authed(pb::SignupStatusRequest {
vendor: "stripe/gunnar".into(),
session: session.into(),
})))
.expect("Signup.Status")
.into_inner()
}
/// **A paid signup, the whole pulled way**: Start → Stripe's page paid → the signed webhook
/// → the account is an `add_principal` order gunnar.rs's main pulls → its ack → the signup
/// settles → the plan's signed entitlement is an order the main pulls and verifies.
/// Answers the Stripe session.
fn paid_signup(&mut self, username: &str, plan: &str, market: pb::Market) -> String {
let started = self
.start(username, plan, market)
.unwrap_or_else(|e| panic!("{username}: Signup.Start: {e}"));
assert!(
started.url.contains("checkout"),
"Stripe's hosted page: {}",
started.url
);
let (code, said) = self.paid(&started.session);
assert_eq!(code, 200, "{said}");
self.until(&format!("{username}'s add_principal queued"), |w| {
w.queued_kinds(SAAS, "main")
.contains(&"add_principal".to_string())
});
assert_eq!(
self.main_pulls(),
["add_principal"],
"the main made the account from the order it pulled"
);
monetize_server::signup::settle_pending(&self.state);
let st = self.status(&started.session);
assert_eq!(
st.state(),
pb::signup_status_response::State::Created,
"{username}: {st:?}"
);
started.session
}
/// A request carrying `bearer` (a site's own ONE bearer: the call is that site's).
fn as_bearer<T>(&self, bearer: &str, m: T) -> Request<T> {
let mut r = Request::new(m);
r.metadata_mut().insert(
"authorization",
MetadataValue::try_from(format!("Bearer {bearer}")).unwrap(),
);
r
}
/// **A site joins** (attach/enrol as the ONE box's front records it): its bearer names it,
/// and its main pins its key on its first call inside the window. Answers the main.
fn join(&self, estate: &str, bearer: &str, seed: [u8; 32]) -> GunnarBox {
let dir = self._dir.join("joined");
std::fs::create_dir_all(&dir).unwrap();
let rec = serde_json::json!({ "estate": estate, "product": "gunnar", "box_name": "main", "endpoint": "", "estate_ca_pem": "", "owner_key": "",
"enrolled_unix_ms": self.now(), "bearer_sha256": monetize_server::fleet::bearer_digest(bearer), "bearer_until_unix_ms": self.now() + 365 * DAY });
std::fs::write(dir.join(format!("{estate}.json")), rec.to_string()).unwrap();
let said = monetize_server::fleet::take_joined(&self.state, &dir);
assert!(said.iter().all(|l| !l.contains("REFUSED")), "{said:?}");
let pk = self.state.signer_for("gunnar").public_key();
let mut main = GunnarBox::new(estate, "main", seed, pk);
main.reports_product = true;
self.try_report(&mut main, true)
.unwrap_or_else(|e| panic!("{estate}'s main pins inside the window: {e}"));
main
}
/// A webhook to `instance`'s own endpoint (`/callback/stripe/<instance>`).
fn webhook_to(&self, instance: &str, ev: &serde_json::Value) -> (u16, String) {
self.deliver_event(instance, ev)
}
fn queued_kinds(&self, instance: &str, role: &str) -> Vec<String> {
self.state
.fleet
.guardian()
.unwrap()
.store
.queued(instance)
.into_iter()
.filter(|o| o.role == role)
.map(|o| o.kind)
.collect()
}
fn until(&self, what: &str, done: impl Fn(&World) -> bool) {
let began = Instant::now();
while !done(self) {
assert!(began.elapsed() < Duration::from_secs(20), "never: {what}");
std::thread::sleep(Duration::from_millis(10));
}
}
fn rows(&self, tenant: &str) -> pb::AccountRowsResponse {
let mut c = pb::accounts_client::AccountsClient::new(self.channel.clone());
self.rt
.block_on(c.rows(self.authed(pb::AccountRowsRequest {
product: "gunnar".into(),
tenant: tenant.into(),
})))
.expect("Accounts.Rows")
.into_inner()
}
fn accounts(&self) -> Vec<pb::AccountSummary> {
let mut c = pb::accounts_client::AccountsClient::new(self.channel.clone());
self.rt
.block_on(c.list(self.authed(pb::ListAccountsRequest {
product: "gunnar".into(),
limit: 100,
})))
.expect("Accounts.List")
.into_inner()
.accounts
}
// ── the private estate ──
/// **A private Gunnar bought and delivered**: the order is a Stripe hold, laid at the
/// UpCloud fake, installed by the stand-in kit; the estate's main and twin pin their own
/// keys on their first call inside the install's window (G7) and are heard; the hold is
/// captured. Answers the estate's two boxes.
fn private_gunnar(&self, company: &str, account: &str) -> (GunnarBox, GunnarBox) {
let run = estate_order::start_for(
&self.state,
company,
&format!("{account}@buyer.example"),
"",
account,
&EstateSizes::default(),
)
.expect("the order starts");
self.pay(&run.handle.as_ref().unwrap().id);
self.deliver(company)
}
/// **A paid order delivered**: driven until CAPTURED, the estate's main and twin pinning
/// their own keys on their first call once installed. Answers the two boxes.
fn deliver(&self, company: &str) -> (GunnarBox, GunnarBox) {
let pk = self.state.signer_for("gunnar").public_key();
let mut main = GunnarBox::new(company, "main", [31; 32], pk);
let mut twin = GunnarBox::new(company, "twin", [32; 32], pk);
let mut pinned = false;
let began = Instant::now();
loop {
estate_order::drive(&self.state, company);
let r = self.state.estates.get(company).unwrap();
if r.phase == phase::CAPTURED {
break;
}
assert!(
phase::is_open(&r.phase),
"{company} left the open phases at {}: {}",
r.phase,
r.why
);
// The signed UpCloud guest lays at the host's pace (about 15 s at the mock).
assert!(
began.elapsed() < Duration::from_secs(90),
"{company} stuck at {}: {}",
r.phase,
r.why
);
let guardian = self.state.fleet.guardian().unwrap();
let store = &guardian.store;
// Installed = the pin windows OPEN. `estate_installed` declares the estate first and
// opens each role's window after it, so `product_of` alone raced the windows: a
// loaded run pinned in between and was refused "not signed by a box this monetize
// knows" (r5-4 gate, 2026-10-11).
let windows_open = store.product_of(company).is_some()
&& store.pin_window(company, "main") > 0
&& store.pin_window(company, "twin") > 0;
if !pinned && windows_open {
// Installed: the boxes boot and call home, each pinning its own key.
self.try_report(&mut main, true)
.expect("the main pins inside the window");
self.try_report(&mut twin, true)
.expect("the twin pins inside the window");
pinned = true;
} else if pinned {
self.report(&mut main);
self.report(&mut twin);
}
std::thread::sleep(Duration::from_millis(20));
}
(main, twin)
}
fn drive_change(&self, company: &str, main: &mut GunnarBox, twin: &mut GunnarBox) {
let began = Instant::now();
loop {
self.report(main);
self.report(twin);
estate_order::drive(&self.state, company);
let r = self.state.estates.get(company).unwrap();
match r.change.as_ref() {
None => return,
Some(c) => assert!(
began.elapsed() < Duration::from_secs(90),
"the change is stuck at {}: {}",
c.status,
c.why
),
}
std::thread::sleep(Duration::from_millis(20));
}
}
}
impl Drop for World {
fn drop(&mut self) {
if let Some(s) = self.server.take() {
self.rt.block_on(s.stop());
}
}
}
// ─── the scenarios ──────────────────────────────────────────────────────────────────────────
/// a) ★ **A gunnar.rs account is bought and active**: Plans → Start → Stripe's paid webhook →
/// the ledger's fact → a signed entitlement order → the estate pulls it, verifies it and acks →
/// the account is active; SE, FI and DK are priced in their currencies with their VAT.
#[test]
fn a_paid_gunnar_rs_signup_becomes_a_verified_entitlement_the_estate_pulls_and_an_active_account() {
let _t = Timed(
"a) paid signup → verified entitlement → active account",
Instant::now(),
);
let mut w = World::new("a");
for (market, currency, words) in [
(pb::Market::Se, "Sek", "100.00 SEK"),
(pb::Market::Fi, "Eur", "10.00 EUR"),
(pb::Market::Dk, "Dkk", "75.00 DKK"),
] {
let offers = w.plans(market).plans;
assert!(
offers
.iter()
.any(|o| o.cap_bytes == 10 * GIB && o.price_words.contains(words)),
"{market:?} ({currency}): {offers:?}"
);
}
let mut sessions = Vec::new();
for (who, plan, market) in [
("alice", "gunnar/10gb-1m", pb::Market::Se),
("aino", "gunnar/10gb-1m-fi", pb::Market::Fi),
("dorte", "gunnar/10gb-1m-dk", pb::Market::Dk),
] {
let s = w.paid_signup(who, plan, market);
let ran = w.main_pulls();
assert_eq!(ran, ["entitlement"], "{who}: the main pulled the plan's entitlement and verified it under its monetize key: refused {:?}", w.main.refused);
let f = &w.main.entitled[who];
assert_eq!(
(f.state, f.caps.get("pack_bytes").copied()),
(monetize_embed::State::Paid, Some(10 * GIB)),
"{who}: {f:?}"
);
sessions.push((who, s));
}
// The poller adopts each listed tenant's fact onto the ONE ledger: the account is active.
monetize_server::poller::tick(&w.state);
for (who, _) in &sessions {
let rows = w.rows(who);
let acct = rows.account.clone().unwrap_or_default();
assert_eq!(
acct.state(),
pb::State::Paid,
"{who}: the account is active: {rows:?}"
);
assert!(
acct.paid_until_unix_ms.unwrap_or(0) > w.now() + 29 * DAY,
"{who}: paid a month: {acct:?}"
);
assert!(
rows.rows.iter().any(|r| r.kind == "purchase"),
"{who}: the sale is a row: {:?}",
rows.rows
);
}
// VAT: SE 25 %, FI 25.5 %, DK 25 %, each on its own currency's net.
let books = w.state.books.read().unwrap().clone();
let sales = monetize_server::signup::tax_sales(&w.state.signups, &books).unwrap();
for (who, session) in &sessions {
let rec = w
.state
.signups
.get("stripe/gunnar", session)
.unwrap()
.unwrap();
// The vendor's amount is what the buyer paid, VAT included.
let (gross, tax) = (rec.signup.amount, rec.signup.tax);
let net = monetize_pay::Money {
minor: gross.minor - tax.minor,
currency: gross.currency,
};
let (want_net, want_bp, cc) = match *who {
"alice" => (10_000, 2_500, "SE"),
"aino" => (1_000, 2_550, "FI"),
_ => (7_500, 2_500, "DK"),
};
assert_eq!(net.minor, want_net, "{who}: the plan's price, net");
let sale = sales
.iter()
.find(|s| s.reference.contains(session.as_str()))
.unwrap_or_else(|| panic!("{who}: no tax sale in {sales:?}"));
assert_eq!(
(sale.basis_points, sale.customer_country.as_str()),
(want_bp, cc),
"{who}: {sale:?}"
);
assert_eq!(
tax.minor,
(want_net * want_bp as u64 + 5_000) / 10_000,
"{who}: the VAT on {net:?}"
);
}
assert!(
w.main.forged.is_empty() && w.main.refused.is_empty(),
"forged {:?} refused {:?}",
w.main.forged,
w.main.refused
);
}
/// b) ★ **A private Gunnar is bought on a free gunnar account and its tenants are booked on
/// the ONE ledger**: a 0-SEK `gunnar/account` → an estate bought on it → laid at the UpCloud
/// fake → acme1's boxes pin inside the window (G7) → its main pulls its own orders → its tenant
/// is booked as `gunnar/@acme1/<ns>`.
#[test]
fn a_free_account_buys_a_private_gunnar_that_joins_and_whose_tenants_are_booked_as_at_acme1() {
let _t = Timed(
"b) 0-SEK account → private Gunnar → acme1 joins → @acme1 tenants",
Instant::now(),
);
let mut w = World::new("b");
// The free account: no card; gunnar.rs's main makes it from the order it pulls.
let account = w
.start("olle", "gunnar/account", pb::Market::Se)
.expect("a free account is started, pending on the main");
// The 0 kr card check (A15): nothing charged, the card checked, the account made by pull.
let (code, said) = w.check_card(&account.session, "olle");
assert_eq!(code, 200, "{said}");
w.until("olle's add_principal queued", |w| {
w.returns("stripe/gunnar", &account.session);
w.queued_kinds(SAAS, "main")
.contains(&"add_principal".to_string())
});
assert_eq!(
w.main_pulls(),
["add_principal"],
"the main made the account: {:?}",
w.main.refused
);
monetize_server::signup::settle_pending(&w.state);
let st = w.status(&account.session);
assert_eq!(
st.state(),
pb::signup_status_response::State::Created,
"{st:?}"
);
assert_eq!(
w.main.principals.keys().collect::<Vec<_>>(),
["olle"],
"one account, made once"
);
assert!(
!w.queued_kinds(SAAS, "main")
.contains(&"add_principal".to_string()),
"no second order"
);
// The estate, bought on that account: a row on (gunnar, olle) — G5.
let (mut main, _twin) = w.private_gunnar("acme1", "olle");
let rows = w.rows("olle");
assert!(
rows.rows
.iter()
.any(|r| r.kind == "instance" && r.id.contains("acme1")),
"the estate is a row on olle's account: {:?}",
rows.rows
);
assert!(
w.accounts()
.iter()
.any(|a| a.tenant == "olle" && a.instances == 1),
"Accounts.List counts it: {:?}",
w.accounts()
);
// A tenant of acme1, sold by the ONE shop: booked on the ONE ledger as gunnar/@acme1/bob.
let bob = TenantId::on_estate("acme1", "bob");
let mut c = pb::entitlement_client::EntitlementClient::new(w.channel.clone());
let fact = pb::EntitlementFact {
tenant: bob.0.clone(),
plan: "gunnar/@acme1/bob/2026-10-10+pack".into(),
state: pb::State::Paid as i32,
paid_until_unix_ms: Some(w.now() + 30 * DAY),
caps: [("pack_bytes".to_string(), 10 * GIB)].into_iter().collect(),
..Default::default()
};
let set =
w.rt.block_on(c.set(w.authed(pb::SetEntitlementRequest {
product: "gunnar".into(),
fact: Some(fact),
})))
.expect("Entitlement.Set")
.into_inner();
assert!(set.pushed, "queued for acme1's main: {}", set.push_error);
assert_eq!(
w.state
.ledger
.entitlement("gunnar", &bob.0)
.unwrap()
.map(|f| f.tenant),
Some(bob.clone()),
"booked as gunnar/@acme1/bob"
);
assert_eq!(
w.pull(&mut main),
["entitlement"],
"acme1's main pulled it: {:?}",
main.refused
);
assert_eq!(
main.entitled.keys().collect::<Vec<_>>(),
["bob"],
"as acme1's gunnar names it"
);
let saas = w.state.fleet.guardian().unwrap().store.queued(SAAS);
assert!(
saas.iter()
.all(|o| !o.body.contains("acme1") && !o.body.contains("\"bob\"")),
"nothing of acme1's went to gunnar.rs: {saas:?}"
);
}
/// c) ★ **A paid data step grows the estate, capped at what is paid and never smaller**
/// (G16-d): the step is held, paid, captured → a signed `grow_go_ahead` for acme1's main and
/// twin → each box asks `grow_set` over the Fleet channel: past paid is refused, smaller is
/// refused, the paid size is done.
#[test]
fn a_paid_data_step_sends_grow_go_ahead_and_grow_set_is_capped_at_paid_and_never_shrinks() {
let _t = Timed(
"c) data step → grow_go_ahead → grow_set capped",
Instant::now(),
);
let w = World::new("c");
let (mut main, mut twin) = w.private_gunnar("acme1", "olle");
let c = estate_order::change::change(
&w.state,
"acme1",
&EstateSizes {
main_data_gib: 30,
..EstateSizes::default()
},
)
.expect("the data step is quoted and held");
w.pay(&c.handle.as_ref().unwrap().id);
w.drive_change("acme1", &mut main, &mut twin);
let run = w.state.estates.get("acme1").unwrap();
assert_eq!(
run.growth.as_ref().map(|g| g.main_data_gib),
Some(30),
"the go-ahead is signed: {:#?}",
run.history
);
let g = w.state.fleet.guardian().unwrap().clone();
let pk = VerifyingKey::from_bytes(&w.state.signer_for("gunnar").public_key()).unwrap();
let mut paid = BTreeMap::new();
for role in ["main", "twin"] {
let go: Vec<_> = g
.store
.orders_for("acme1", role, 0)
.into_iter()
.filter(|o| o.kind == kind::GROW_GO_AHEAD)
.collect();
assert_eq!(go.len(), 1, "{role}: {go:?}");
let body: GrowGoAhead = serde_json::from_str(&go[0].body).unwrap();
let signed = monetize_embed::signing::verify_estate_growth(body.go_ahead.as_bytes(), &pk)
.expect("the go-ahead verifies under the gunnar key");
assert_eq!(signed.estate, "acme1");
paid.insert(role, body.data_gib);
}
assert_eq!(paid["main"], 30);
assert!(
paid["twin"] >= 4 * 30,
"the twin holds main's whole set: {paid:?}"
);
let disks = |role: &str| -> Vec<u64> {
w.state
.estates
.get("acme1")
.unwrap()
.laid
.unwrap()
.machine(role)
.unwrap()
.disks
.iter()
.skip(1)
.map(|d| d.gib)
.collect()
};
let e = w.ask_grow_set(&main, &[], 40).unwrap_err();
assert!(
e.message().contains("paid to 30 GB a disk"),
"past paid: {e}"
);
let words = w
.ask_grow_set(&twin, &[], 0)
.expect("the twin first, to its paid size");
assert!(words.contains("acme1 grew twin data"), "{words}");
let words = w
.ask_grow_set(&main, &[], 0)
.expect("main's own, to what is paid");
assert!(words.contains("30 GiB"), "{words}");
assert!(
disks("main").iter().all(|g| *g == 30),
"read back: {:?}",
disks("main")
);
let e = w.ask_grow_set(&main, &[], 20).unwrap_err();
assert!(e.message().contains("never shrinks"), "smaller: {e}");
}
/// c′) **The estate's own gate takes the growth go-ahead**: a paid step reaches the box that
/// grows, as an order it verifies and runs. What the SERVER owes is proven here (the order
/// queued for the box, signed under its monetize key, addressed to it, in time, with the paid
/// size); that GUNNAR's own gate knows the kind is gunnar's own test, gunnar-repair
/// `order::tests::a_grow_go_ahead_order_carries_monetizes_signed_step_and_this_roles_size`
/// (and `exec::tests::a_twin_grows_on_the_go_ahead_…` for the verb). money-flow ran both halves
/// through `gunnar_repair::accept_order`; monetize links no gunnar crate.
#[test]
fn a_sold_estates_box_accepts_the_grow_go_ahead_order_through_gunnars_own_gate() {
let _t = Timed("c') the box's check accepts grow_go_ahead", Instant::now());
let w = World::new("c2");
let (mut main, mut twin) = w.private_gunnar("acme1", "olle");
let c = estate_order::change::change(
&w.state,
"acme1",
&EstateSizes {
main_data_gib: 30,
..EstateSizes::default()
},
)
.unwrap();
w.pay(&c.handle.as_ref().unwrap().id);
w.drive_change("acme1", &mut main, &mut twin);
let ran = w.pull(&mut main);
assert_eq!(
ran,
[kind::GROW_GO_AHEAD],
"the box's check refused the paid go-ahead: {:?}",
main.refused
);
}
/// d) ★ **Renewal, unpaid expiry and refund each move the entitlement the estate holds**: a
/// renewal extends it, an unpaid month suspends it, a refund withdraws it — every change an
/// order the main pulls and verifies.
#[test]
fn renewal_extends_unpaid_expiry_suspends_and_a_refund_withdraws_the_entitlement_by_order() {
let _t = Timed(
"d) renewal / unpaid expiry / refund → orders",
Instant::now(),
);
let mut w = World::new("d");
// Renewal: alice's month, then another bought on the same account.
w.paid_signup("alice", "gunnar/10gb-1m", pb::Market::Se);
assert_eq!(w.main_pulls(), ["entitlement"], "{:?}", w.main.refused);
monetize_server::poller::tick(&w.state);
let first = w.main.entitled["alice"].paid_until_unix_ms.unwrap();
let mut c = pb::purchase_client::PurchaseClient::new(w.channel.clone());
let started =
w.rt.block_on(c.start(w.authed(pb::StartPurchaseRequest {
product: "gunnar".into(),
tenant: "alice".into(),
vendor: "stripe/gunnar".into(),
payer: "alice@buyer.example".into(),
market: pb::Market::Se as i32,
renew: true,
..Default::default()
})))
.expect("Purchase.Start renew")
.into_inner();
let (code, said) = w.paid(&started.handle_id);
assert_eq!(code, 200, "{said}");
w.until("the renewal's entitlement queued", |w| {
w.queued_kinds(SAAS, "main")
.contains(&"entitlement".to_string())
});
assert_eq!(w.main_pulls(), ["entitlement"], "{:?}", w.main.refused);
let renewed = w.main.entitled["alice"].paid_until_unix_ms.unwrap();
assert!(
renewed >= first + 28 * DAY,
"renewed a calendar month on: {first} → {renewed}"
);
// Refund: cecilia's whole payment back at Stripe → her paid time is taken back by order.
let s = w.paid_signup("cecilia", "gunnar/10gb-1m", pb::Market::Se);
assert_eq!(w.main_pulls(), ["entitlement"]);
monetize_server::poller::tick(&w.state);
let gross = w
.state
.signups
.get("stripe/gunnar", &s)
.unwrap()
.unwrap()
.signup
.amount
.minor;
// The refund made by hand in Stripe's dashboard: its signed `charge.refunded` delivered.
let (st, ev) = w.fake.control("POST", &format!("/refund/{s}/{gross}"));
assert_eq!(st, 200, "the dashboard's refund: {ev}");
let (code, said) = w.deliver_event("gunnar", &ev);
assert_eq!(code, 200, "{said}");
w.until("the withdrawal queued", |w| {
w.queued_kinds(SAAS, "main")
.contains(&"entitlement".to_string())
});
assert_eq!(w.main_pulls(), ["entitlement"], "{:?}", w.main.refused);
let c = &w.main.entitled["cecilia"];
assert!(
c.paid_until_unix_ms.unwrap() <= w.now() && c.state != monetize_embed::State::Paid,
"the refund withdrew the paid time: {c:?}"
);
// Unpaid expiry: bert pays one month and not the next.
w.paid_signup("bert", "gunnar/10gb-1m", pb::Market::Se);
assert_eq!(w.main_pulls(), ["entitlement"]);
monetize_server::poller::tick(&w.state);
let until = w.main.entitled["bert"].paid_until_unix_ms.unwrap();
w.later(until.saturating_sub(w.now()) + 60 * DAY);
w.main_reports();
monetize_server::poller::tick(&w.state);
w.main_reports();
monetize_server::poller::tick(&w.state);
w.main_pulls();
let bert = &w.main.entitled["bert"];
assert!(
matches!(
bert.state,
monetize_embed::State::Suspended | monetize_embed::State::Retention
),
"an unpaid month suspends: {bert:?}"
);
}
/// e) ★ **A gunnar estate refuses what holger's key signed** (G8): an order signed with
/// holger's product key is dropped as forged, and a gunnar-signed order carrying a
/// holger-signed fact is refused by the fact's own signature.
#[test]
fn a_gunnar_estate_refuses_an_order_or_a_fact_signed_with_holgers_product_key() {
let _t = Timed("e) wrong product key refused", Instant::now());
let mut w = World::new("e");
let holger = w.state.signer_for("holger");
let gunnar = w.state.signer_for("gunnar");
assert_ne!(
holger.public_key(),
gunnar.public_key(),
"one key per product"
);
let now = w.now();
let fact = |s: &monetize::Signer| {
s.sign_fact(EntitlementFact {
tenant: TenantId("mallory".into()),
plan: "gunnar/forged".into(),
state: monetize_embed::State::Paid,
paid_until_unix_ms: Some(now + 365 * DAY),
caps: [("pack_bytes".to_string(), 1u64 << 40)]
.into_iter()
.collect(),
source: "operator".into(),
signature: Vec::new(),
issued_unix_ms: None,
issued_signature: Vec::new(),
})
};
let order = |s: &monetize::Signer, seq: u64, f: &EntitlementFact| {
let o = s.sign_order(monetize_embed::fleet::SignedOrder {
seq,
product: "gunnar".into(),
instance: SAAS.into(),
role: "main".into(),
kind: "entitlement".into(),
body: serde_json::to_string(f).unwrap(),
issued_unix_ms: now,
not_after_unix_ms: now + DAY,
signature: Vec::new(),
});
monetize_server::services::fleet::order_pb(&o)
};
let ran = w
.main
.run(vec![order(holger, 1_000_001, &fact(holger))], wall_ms());
assert!(
ran.is_empty() && w.main.forged.len() == 1,
"holger's order is not monetize's for gunnar: {:?}",
w.main.forged
);
assert_eq!(w.main.last_seq, 0, "a forged order moves nothing");
let ran = w
.main
.run(vec![order(gunnar, 1_000_002, &fact(holger))], wall_ms());
assert!(ran.is_empty(), "{ran:?}");
assert!(
w.main.refused.iter().any(|r| r.contains("does not verify")),
"the holger-signed fact is refused: {:?}",
w.main.refused
);
assert!(!w.main.entitled.contains_key("mallory"));
// And what the shop itself queues for gunnar verifies: a gunnar fact under the gunnar key.
w.main_reports();
assert!(w.main.acks.is_empty());
}
/// f) ★ **After a repair the estate gets its REAL entitlements back** (G16-a, M-D28 reversed):
/// main data lost → the case → a human presses recharge → the main pulls the recharge, then a
/// signed `restate_entitlements` whose snapshot is acme1's tenants from the ONE ledger.
#[test]
fn after_a_recharge_restate_entitlements_carries_the_real_snapshot_from_the_one_ledger() {
let _t = Timed(
"f) recharge → restate_entitlements real snapshot",
Instant::now(),
);
let w = World::new("f");
// The estate's guardian is the Gunnar GUEST's (ops 100-102), through the pulled product.
let (mut main, mut twin) = w.private_gunnar("acme1", "olle");
let at = w.now();
let book = |tenant: &str| {
let f = w.state.signer_for("gunnar").sign_fact_at(
EntitlementFact {
tenant: TenantId(tenant.into()),
plan: format!("gunnar/{tenant}/pack"),
state: monetize_embed::State::Paid,
paid_until_unix_ms: Some(at + 30 * DAY),
caps: [("pack_bytes".to_string(), 10 * GIB)].into_iter().collect(),
source: "payment:stripe:pi_money_flow".into(),
signature: Vec::new(),
issued_unix_ms: None,
issued_signature: Vec::new(),
},
at,
);
w.state.ledger.set_entitlement("gunnar", &f).unwrap();
f
};
let bob = book(&TenantId::on_estate("acme1", "bob").0);
book(&TenantId::on_estate("bolt", "eve").0);
book("saas-team");
w.later(30_000);
main.set("data", "lost");
main.set("serving", "no");
w.report(&mut main);
w.report(&mut twin);
monetize_server::fleet::tick(&w.state);
monetize_server::fleet::tick(&w.state);
let mut console = pb::guardian_client::GuardianClient::new(w.channel.clone());
let cases =
w.rt.block_on(console.cases(w.authed(pb::GuardianCasesRequest {
instance: "acme1".into(),
})))
.unwrap()
.into_inner();
let case = cases
.estates
.first()
.and_then(|e| e.cases.first())
.cloned()
.unwrap_or_else(|| panic!("no case: {cases:?}"));
assert_eq!(case.finding_code, "main_data_lost", "{case:?}");
w.rt.block_on(console.press(w.authed(pb::GuardianPressRequest {
instance: "acme1".into(),
remedy: "recharge_from_twin".into(),
case_id: String::new(),
principal: "rickard".into(),
strong: true,
})))
.expect("the button");
monetize_server::fleet::tick(&w.state);
assert_eq!(
w.pull(&mut main),
[kind::RECHARGE_FROM_TWIN],
"{:?}",
main.refused
);
w.later(1_000);
monetize_server::fleet::tick(&w.state);
assert_eq!(
w.pull(&mut main),
[kind::RESTATE_ENTITLEMENTS],
"{:?}",
main.refused
);
assert_eq!(main.restated.len(), 1);
assert_eq!(
main.entitled.keys().collect::<Vec<_>>(),
["bob"],
"acme1's own tenant, never bolt's or the SaaS one"
);
assert_eq!(
main.entitled["bob"],
w.state
.signer_for("gunnar")
.on_estate(&bob, "acme1")
.unwrap(),
"the ledger's fact, as acme1 names it"
);
}
/// h) ★ **A new visitor buys a PRIVATE Gunnar first, and the account that owns it is minted**
/// (OM-19, PLAN §3c): the page offers BOTH a plan stop and a private instance; a checkout that
/// carries only an email is refused with a sign-in offer and holds nothing; the visitor's
/// gunnar.rs account is minted first (FLOW-TRACE J2: account-first, the free `gunnar/account`,
/// its sign-in mail's address on record), and the private Gunnar bought signed in books on the
/// ONE ledger under (gunnar, nina).
#[test]
fn a_new_visitor_offered_a_plan_and_a_private_gunnar_buys_the_private_first_on_a_minted_account() {
let _t = Timed(
"h) new visitor → private Gunnar first → minted account owns it",
Instant::now(),
);
let mut w = World::new("h");
// Both stops on the one page.
assert!(
w.plans(pb::Market::Se)
.plans
.iter()
.any(|o| o.cap_bytes == 10 * GIB),
"the plan stop"
);
let sells =
w.rt.block_on(w.estates().sells(w.authed(pb::EstateOrderSellsRequest {})))
.expect("EstateOrder.Sells")
.into_inner();
assert!(
sells.estates,
"the private stop: a private Gunnar is sold here"
);
// An email is no identity: nothing is held for a visitor nobody signed in.
let e = w
.estate_start("acme1", "nina@buyer.example", "nina", Vec::new())
.expect_err("a private Gunnar for a bare email");
assert_eq!(e.code(), tonic::Code::Unauthenticated, "{e}");
assert!(
e.message().contains("sign in"),
"the refusal offers sign-in: {e}"
);
assert!(
w.state.estates.get("acme1").is_none(),
"nothing held, nothing reserved"
);
// The account first: minted, made on the main, its sign-in address on record.
w.new_account("nina", "nina@buyer.example");
assert_eq!(w.main.principals.keys().collect::<Vec<_>>(), ["nina"]);
assert_eq!(
w.state
.signups
.email_of("gunnar", "nina")
.unwrap()
.as_deref(),
Some("nina@buyer.example"),
"the sign-in link's address"
);
// The private Gunnar, bought signed in: the order is nina's and books on (gunnar, nina).
let _boxes = w.private_signed_in("acme1", "nina");
let run = w.state.estates.get("acme1").unwrap();
assert_eq!(
(run.phase.as_str(), run.account.as_str(), run.email.as_str()),
(phase::CAPTURED, "nina", "nina@buyer.example")
);
let rows = w.rows("nina");
assert!(
rows.rows
.iter()
.any(|r| r.kind == "instance" && r.id.contains("acme1")),
"the estate is a row on nina's account: {:?}",
rows.rows
);
assert!(
w.accounts()
.iter()
.any(|a| a.tenant == "nina" && a.instances == 1),
"Accounts.List: {:?}",
w.accounts()
);
let bought = w
.purchases("nina", estate_ticket("nina"))
.expect("EstateOrder.Purchases, signed in");
assert_eq!(
bought
.estates
.iter()
.map(|e| e.company.as_str())
.collect::<Vec<_>>(),
["acme1"],
"{bought:?}"
);
}
/// i) ★ **The SAME account, signed in, buys a 2nd private Gunnar AND a 10 GB plan** (OM-19; the
/// integrator's scenario h at a3afc5d, now through the buyer's own doors): `EstateOrder.Start`
/// with the account's `estate` ticket, `Purchase.Start` with its `order` ticket covering 10 GB →
/// two runs, two estates laid apart, every row on the one (gunnar, nina) account. Auth is the
/// linkage: another account's ticket, or a spent one, buys nothing on nina's.
#[test]
fn the_same_account_signed_in_buys_a_second_private_gunnar_and_a_plan_all_on_one_account() {
let _t = Timed(
"i) same account, signed in → 2nd private Gunnar + 10 GB plan",
Instant::now(),
);
let mut w = World::new("i");
let _boxes = w.nina_owns_two_private_gunnars_and_a_plan();
let runs: Vec<_> = estate_order::list(&w.state)
.into_iter()
.filter(|r| r.account == "nina")
.collect();
assert_eq!(runs.len(), 2, "two orders on nina's account");
assert_ne!(runs[0].reference, runs[1].reference);
assert!(
runs.iter().all(|r| r.phase == phase::CAPTURED),
"{:?}",
runs.iter().map(|r| &r.phase).collect::<Vec<_>>()
);
let hosts = |r: &monetize_server::estate_order::EstateRun| {
r.laid
.as_ref()
.unwrap()
.machines
.iter()
.map(|m| m.hostname.clone())
.collect::<std::collections::BTreeSet<_>>()
};
assert!(
hosts(&runs[0]).is_disjoint(&hosts(&runs[1])),
"two estates share no box: {:?} {:?}",
hosts(&runs[0]),
hosts(&runs[1])
);
assert_eq!(
w.main.entitled["nina"].caps.get("pack_bytes").copied(),
Some(10 * GIB),
"the plan is nina's: {:?}",
w.main.entitled.get("nina")
);
let rows = w.rows("nina");
for company in ["acme1", "acme2"] {
assert!(
rows.rows
.iter()
.any(|r| r.kind == "instance" && r.id.contains(company)),
"{company} is a row on nina's account: {:?}",
rows.rows
);
}
assert!(
rows.rows.iter().any(|r| r.kind == "purchase"),
"the plan is a row beside the instances: {:?}",
rows.rows
);
let listed = w.accounts();
assert!(
listed
.iter()
.any(|a| a.tenant == "nina" && a.instances == 2),
"{listed:?}"
);
assert!(
listed
.iter()
.all(|a| a.tenant == "nina" || a.instances == 0),
"no instance on another account: {listed:?}"
);
// Auth is the linkage, never the email.
let e = w
.estate_start(
"acme3",
"nina@buyer.example",
"nina",
estate_ticket("mallory"),
)
.expect_err("another account's ticket");
assert_eq!(e.code(), tonic::Code::Unauthenticated, "{e}");
assert!(w.state.estates.get("acme3").is_none());
let mut c = pb::purchase_client::PurchaseClient::new(w.channel.clone());
let req = pb::StartPurchaseRequest {
product: "gunnar".into(),
tenant: "nina".into(),
caps: [("pack_bytes".to_string(), 20 * GIB)].into_iter().collect(),
vendor: "stripe/gunnar".into(),
market: pb::Market::Se as i32,
actor_ticket: ticket(
"mallory",
PURPOSE_ORDER,
[("pack_bytes".to_string(), 20 * GIB)].into_iter().collect(),
),
..Default::default()
};
let e =
w.rt.block_on(c.start(w.authed(req)))
.expect_err("a plan on nina's account with mallory's ticket");
assert_eq!(e.code(), tonic::Code::PermissionDenied, "{e}");
let once = estate_ticket("nina");
w.purchases("nina", once.clone())
.expect("the ticket, first spent");
let e = w
.purchases("nina", once)
.expect_err("the same ticket again");
assert_eq!(
e.code(),
tonic::Code::Unauthenticated,
"a spent ticket proves nothing: {e}"
);
}
/// j) ★ **The same email signing up again is refused with a sign-in offer** (OM-19 (4), PLAN
/// §3c: "never email matching, never a silent merge"): a second account is not made for an
/// address that already has one — free or paid, whatever its case or spaces — the words offer
/// sign-in and never name the account; nothing is queued, nothing charged. Another address is
/// still welcome, and a bare-email private checkout is refused the same way.
#[test]
fn the_same_email_signing_up_again_is_refused_with_a_sign_in_offer_and_no_second_account() {
let _t = Timed(
"j) duplicate email → refused, offered sign-in",
Instant::now(),
);
let mut w = World::new("j");
w.new_account("olle", "o.berg@buyer.example");
for (email, plan) in [
("o.berg@buyer.example", "gunnar/account"),
(" O.Berg@Buyer.EXAMPLE ", "gunnar/account"),
("o.berg@buyer.example", "gunnar/10gb-1m"),
] {
let e = w.start_as("nils", plan, email, pb::Market::Se).expect_err(&format!(
"OM-19 (j) OPEN: Signup.Start took {email:?} ({plan}) for a SECOND account — the address already has one (olle); §3c: refuse, offer sign-in"
));
assert!(
matches!(
e.code(),
tonic::Code::FailedPrecondition | tonic::Code::AlreadyExists
),
"{plan} {email:?}: {e}"
);
assert!(
e.message().to_lowercase().contains("sign in"),
"the refusal offers sign-in: {e}"
);
assert!(
!e.message().contains("olle"),
"the refusal never names the account: {e}"
);
}
assert!(
!w.queued_kinds(SAAS, "main")
.contains(&"add_principal".to_string()),
"no second account queued"
);
assert_eq!(w.main.principals.keys().collect::<Vec<_>>(), ["olle"]);
let e = w
.estate_start("acme9", "o.berg@buyer.example", "nils", Vec::new())
.expect_err("a bare-email private checkout");
assert!(e.message().contains("sign in"), "{e}");
assert!(w.state.estates.get("acme9").is_none());
w.start_as(
"nils",
"gunnar/account",
"nils@buyer.example",
pb::Market::Se,
)
.expect("another address is a new account");
}
/// k) ★ **The account menu: what one account owns** (OM-19, §3c "Account menu = ownership"):
/// `Accounts.Rows` for nina is the plan (paid, a month) and BOTH instances — each captured,
/// on its own host, with its paid-until; `EstateOrder.Purchases` (what gunnar.rs's console
/// reads, FLOW-TRACE OM-22) lists the same two and the 10 GB room. Another account sees none
/// of it, and nina's purchases are not another's to read.
/// ★ **A purchase after a quiet spell is judged on the main's NEXT report, never on wall time**
/// (lead lane, 2026-10-25: cases k, l and m failed three times at load 300+ with "main silent
/// 93–126 s (bound 90 s)"). A running main reports every minute; the World's main reports when
/// a step needs it, so a buy is preceded by its report, however long the machine took before it.
/// RED: after 95 s with no report, the signed-in plan was refused as an old report.
#[test]
fn a_plan_bought_after_a_quiet_spell_is_judged_on_the_mains_next_report() {
let _t = Timed(
"load: a quiet spell before a signed-in plan",
Instant::now(),
);
let mut w = World::new("quiet");
w.new_account("pia", "pia@buyer.example");
// A quiet spell longer than the pulled product's 90 s report bound, in real time (the
// product judges a report by the wall clock, not by monetize's): a loaded box's minute.
std::thread::sleep(Duration::from_secs(95));
w.plan_signed_in("pia");
}
#[test]
fn the_account_menu_lists_the_plan_and_both_private_gunnars_of_that_account_only() {
let _t = Timed("k) account menu → plan + both instances", Instant::now());
let mut w = World::new("k");
let _boxes = w.nina_owns_two_private_gunnars_and_a_plan();
w.new_account("olle", "o.berg@buyer.example");
monetize_server::poller::tick(&w.state);
let rows = w.rows("nina");
let acct = rows.account.clone().unwrap_or_default();
assert_eq!(
(acct.state(), acct.instances),
(pb::State::Paid, 2),
"{acct:?}"
);
assert!(
acct.paid_until_unix_ms.unwrap_or(0) > w.now() + 29 * DAY,
"the plan's month: {acct:?}"
);
assert!(
rows.rows.iter().any(|r| r.kind == "purchase"),
"the plan: {:?}",
rows.rows
);
let mut inst: Vec<pb::AccountInstance> = rows
.rows
.iter()
.filter(|r| r.kind == "instance")
.filter_map(|r| r.instance.clone())
.collect();
inst.sort_by(|a, b| a.company.cmp(&b.company));
assert_eq!(
inst.iter().map(|i| i.company.as_str()).collect::<Vec<_>>(),
["acme1", "acme2"],
"{:?}",
rows.rows
);
for i in &inst {
assert_eq!(i.phase, phase::CAPTURED, "{i:?}");
assert!(
!i.host.is_empty() && !i.paid_until.is_empty(),
"name and paid-until: {i:?}"
);
}
assert_ne!(inst[0].host, inst[1].host);
let menu = w
.purchases("nina", estate_ticket("nina"))
.expect("EstateOrder.Purchases, signed in");
let mut owned: Vec<&str> = menu.estates.iter().map(|e| e.company.as_str()).collect();
owned.sort();
assert_eq!(owned, ["acme1", "acme2"], "{menu:?}");
assert!(
menu.estates
.iter()
.all(|e| !e.paid_until.is_empty() && !e.host.is_empty()),
"{menu:?}"
);
assert!(
menu.rooms.iter().any(|r| r.cap_bytes == 10 * GIB),
"the 10 GB room: {menu:?}"
);
let mut c = pb::accounts_client::AccountsClient::new(w.channel.clone());
let olle =
w.rt.block_on(c.rows(w.authed(pb::AccountRowsRequest {
product: "gunnar".into(),
tenant: "olle".into(),
})))
.map(|r| r.into_inner().rows)
.unwrap_or_default();
assert!(
olle.iter()
.all(|r| r.kind != "instance" && r.kind != "purchase"),
"nothing of nina's on olle's: {olle:?}"
);
assert!(w
.purchases("olle", estate_ticket("olle"))
.expect("olle's own")
.estates
.is_empty());
let e = w
.purchases("nina", estate_ticket("olle"))
.expect_err("nina's menu with olle's ticket");
assert_eq!(e.code(), tonic::Code::Unauthenticated, "{e}");
}
/// l) ★ **A renewal from the account menu lands as a SIGNED order the right estate pulls**
/// (OM-19, §3c: F4 "queued as signed orders at the ONE monetize, the estate pulls"): nina renews
/// acme2 inside its window with her `estate` ticket → paid → captured, paid-until moved → a new
/// order addressed to acme2, pulled over `Fleet.Orders`, verifying under the `monetize_pubkey`
/// the kit gave acme2 and passing the box's check; acme1 gets nothing.
#[test]
fn a_renewal_from_the_account_queues_a_signed_order_only_the_renewed_estate_pulls() {
let _t = Timed(
"l) renew from the account → signed order for the right estate",
Instant::now(),
);
let mut w = World::new("l");
let [(mut m1, mut t1), (mut m2, mut t2)] = w.nina_owns_two_private_gunnars_and_a_plan();
// What delivery queued is pulled now: what comes after is the renewal's.
for b in [&mut m1, &mut t1, &mut m2, &mut t2] {
w.pull(b);
}
let g = w.state.fleet.guardian().unwrap().clone();
// Orders not yet acked, addressed to the estate's two boxes.
let pending = |instance: &str| {
["main", "twin"]
.iter()
.map(|role| g.store.orders_for(instance, role, 0).len())
.sum::<usize>()
};
assert_eq!(
(pending("acme1"), pending("acme2")),
(0, 0),
"delivery's orders are all pulled"
);
let paid = w.state.estates.get("acme2").unwrap().paid_until_ms;
// Its renewal opens 30 days before the paid period ends.
w.later(paid.saturating_sub(w.now()).saturating_sub(29 * DAY));
let renew = |t: Vec<u8>| {
w.rt.block_on(w.estates().renew(w.authed(pb::EstateOrderRenewRequest {
company: "acme2".into(),
actor_ticket: t,
})))
};
let e = renew(estate_ticket("mallory")).expect_err("acme2 renewed by another account");
assert_eq!(e.code(), tonic::Code::Unauthenticated, "{e}");
renew(estate_ticket("nina")).expect("nina renews acme2 from her account");
let handle = w
.state
.estates
.get("acme2")
.unwrap()
.renewal
.expect("the renewal is held")
.handle
.id;
w.pay(&handle);
let began = Instant::now();
loop {
for b in [&mut m1, &mut t1, &mut m2, &mut t2] {
w.report(b);
}
estate_order::drive(&w.state, "acme2");
let run = w.state.estates.get("acme2").unwrap();
if !run.renewals.is_empty() {
break;
}
assert!(
began.elapsed() < Duration::from_secs(90),
"the renewal is not captured: {} {}",
run.phase,
run.why
);
std::thread::sleep(Duration::from_millis(20));
}
let run = w.state.estates.get("acme2").unwrap();
assert!(
run.paid_until_ms > paid,
"paid until moved on: {paid} → {}",
run.paid_until_ms
);
let (queued1, queued2) = (pending("acme1"), pending("acme2"));
let ran: Vec<String> = [&mut m2, &mut t2]
.into_iter()
.flat_map(|b| w.pull_now(b))
.collect();
assert!(
queued2 > 0 && !ran.is_empty(),
"OM-19 (l) OPEN: the captured renewal of acme2 queued NO signed order for acme2 ({queued2} queued; ran {ran:?}, refused {:?} {:?}) — \
§3c: a renew from the account menu lands as a signed order the estate pulls; estate_order/term.rs captures, moves paid-until and mails, and queues nothing",
m2.refused,
t2.refused
);
assert!(
m2.forged.is_empty() && t2.forged.is_empty(),
"every order verifies under monetize_pubkey: {:?} {:?}",
m2.forged,
t2.forged
);
assert_eq!(queued1, 0, "nothing of acme2's renewal reached acme1");
}
/// l′) **An upgrade from the account menu reaches only the estate it bought** (OM-19 F4; the
/// integrator's h, now through `EstateOrder.ChangePlan` with nina's ticket): a data step on
/// acme2 → held, paid, captured → a signed `grow_go_ahead` acme2's main and twin pull over
/// `Fleet.Orders`, verify under their `monetize_pubkey` and pass the box's check; acme1 pulls
/// nothing of it, and nobody else may change acme2.
#[test]
fn an_upgrade_from_the_account_sends_a_signed_grow_go_ahead_only_to_that_estate() {
let _t = Timed(
"l') upgrade from the account → grow_go_ahead to that estate only",
Instant::now(),
);
let mut w = World::new("l2");
let [(mut m1, mut t1), (mut m2, mut t2)] = w.nina_owns_two_private_gunnars_and_a_plan();
for b in [&mut m1, &mut t1, &mut m2, &mut t2] {
w.pull(b);
}
let change = |t: Vec<u8>| {
let req = pb::EstateOrderChangePlanRequest {
company: "acme2".into(),
sizes: Some(pb::EstateSizes {
main_data_gib: 30,
..Default::default()
}),
actor_ticket: t,
test_order: false,
};
w.rt.block_on(w.estates().change_plan(w.authed(req)))
};
for (who, t) in [
("nobody", Vec::new()),
("mallory", estate_ticket("mallory")),
] {
let e = change(t).expect_err(who);
assert_eq!(e.code(), tonic::Code::Unauthenticated, "{who}: {e}");
}
change(estate_ticket("nina")).expect("nina's data step on acme2");
let id = w
.state
.estates
.get("acme2")
.unwrap()
.change
.and_then(|c| c.handle)
.expect("the step is held")
.id;
w.pay(&id);
w.drive_change("acme2", &mut m2, &mut t2);
let pk = VerifyingKey::from_bytes(&w.state.signer_for("gunnar").public_key()).unwrap();
let g = w.state.fleet.guardian().unwrap().clone();
let go = g
.store
.orders_for("acme2", "main", 0)
.into_iter()
.find(|o| o.kind == kind::GROW_GO_AHEAD)
.expect("acme2's main's go-ahead is queued");
let body: GrowGoAhead = serde_json::from_str(&go.body).unwrap();
assert_eq!(
monetize_embed::signing::verify_estate_growth(body.go_ahead.as_bytes(), &pk)
.expect("signed for acme2")
.estate,
"acme2"
);
assert!(
["main", "twin"]
.iter()
.all(|r| g.store.orders_for("acme1", r, 0).is_empty()),
"nothing queued for acme1"
);
assert_eq!(
w.pull(&mut m2),
[kind::GROW_GO_AHEAD],
"acme2's main: refused {:?} forged {:?}",
m2.refused,
m2.forged
);
assert_eq!(
w.pull(&mut t2),
[kind::GROW_GO_AHEAD],
"acme2's twin: refused {:?} forged {:?}",
t2.refused,
t2.forged
);
assert!(
w.pull(&mut m1).is_empty() && w.pull(&mut t1).is_empty(),
"acme1 pulled nothing of acme2's step"
);
}
/// m) ★ **S10 (owner 2026-10-11 05:53Z): a RESEND sign-in link travels as a SIGNED ORDER the
/// estate mints and mails itself** — nina asks acme2's new sign-in link from her account with
/// her `estate` ticket (`EstateOrder.SendSignInAgain`, the instance row's button); nobody else
/// may. The shop queues a `sign_in_again` order for acme2's main — whose account, which
/// address, which host, and NO secret; the main pulls it over `Fleet.Orders`, verifies it under
/// the `monetize_pubkey` the kit gave acme2 and passes the box's check, then mints the fresh
/// invite and mails the link itself (gunnar's own words for it are gunnar-repair `sign_in`'s
/// tests). acme1 and acme2's twin pull nothing of it, and the shop
/// never holds the resend's secret. (The FIRST link stays the shop's: OM-21 decision A.)
#[test]
fn a_resend_sign_in_link_is_a_signed_order_the_estates_main_mints_and_mails() {
let _t = Timed(
"m) resend sign-in link → signed order the estate mints and mails",
Instant::now(),
);
let mut w = World::new("m");
let [(mut m1, mut t1), (mut m2, mut t2)] = w.nina_owns_two_private_gunnars_and_a_plan();
for b in [&mut m1, &mut t1, &mut m2, &mut t2] {
w.pull(b);
}
let resend = |t: Vec<u8>| {
w.rt.block_on(
w.estates()
.send_sign_in_again(w.authed(pb::EstateOrderSignInAgainRequest {
company: "acme2".into(),
actor_ticket: t,
})),
)
};
for (who, t) in [
("nobody", Vec::new()),
("mallory", estate_ticket("mallory")),
] {
let e = resend(t).expect_err(who);
assert_eq!(e.code(), tonic::Code::Unauthenticated, "{who}: {e}");
}
assert!(
!w.queued_kinds("acme2", "main")
.contains(&"sign_in_again".to_string()),
"a refused ask queues nothing"
);
let words = resend(estate_ticket("nina"))
.unwrap_or_else(|e| panic!("S10 (m) OPEN: nina's resend for acme2 is not a signed order the estate pulls — the shop asks its installer to mint it and mails it itself: {e}"))
.into_inner()
.words;
let host = w.state.estates.cfg.as_ref().unwrap().host_of("acme2");
assert!(words.contains(&host), "{words}");
let g = w.state.fleet.guardian().unwrap().clone();
let o = g
.store
.orders_for("acme2", "main", 0)
.into_iter()
.find(|o| o.kind == "sign_in_again")
.expect("a sign_in_again order is queued for acme2's main");
let body: serde_json::Value = serde_json::from_str(&o.body).unwrap();
assert_eq!(
(
body["account"].as_str(),
body["to"].as_str(),
body["host"].as_str()
),
(
Some("nina"),
Some("nina@buyer.example"),
Some(host.as_str())
),
"{body}"
);
assert!(
!o.body.contains("invite") && !o.body.contains("secret"),
"the order carries no login secret: {}",
o.body
);
assert!(
g.store
.orders_for("acme2", "twin", 0)
.iter()
.all(|o| o.kind != "sign_in_again"),
"only the main mints"
);
assert!(
["main", "twin"]
.iter()
.all(|r| g.store.orders_for("acme1", r, 0).is_empty()),
"nothing queued for acme1"
);
assert_eq!(
w.pull(&mut m2),
["sign_in_again"],
"acme2's main: refused {:?} forged {:?}",
m2.refused,
m2.forged
);
assert!(m2.forged.is_empty(), "verified under monetize_pubkey");
let (to, mail) = m2
.mailed
.last()
.cloned()
.expect("the estate mailed the link itself");
let (account, secret) = m2
.minted
.last()
.cloned()
.expect("the estate minted the invite itself");
assert_eq!(
(to.as_str(), account.as_str()),
("nina@buyer.example", "nina")
);
assert!(
mail.contains(&format!("https://{host}/login?invite={secret}&user=nina")),
"the same link shape as the first: {mail}"
);
let run = w.state.estates.get("acme2").unwrap();
assert!(
run.history.iter().all(|t| !t.note.contains(&secret)),
"the shop never held the secret"
);
assert!(g
.store
.queued("acme2")
.iter()
.all(|o| !o.body.contains(&secret)));
assert!(
w.pull(&mut t2).is_empty() && w.pull(&mut m1).is_empty() && w.pull(&mut t1).is_empty(),
"acme2's twin and acme1 pulled nothing of it"
);
}
/// g) ★ **Twice is once**: a duplicate Stripe webhook and re-driven orders change nothing —
/// the same ledger rows, the same queue, the same entitlement on the box.
#[test]
fn a_duplicate_webhook_and_re_driven_orders_change_nothing() {
let _t = Timed("g) idempotence", Instant::now());
let mut w = World::new("g");
let s = w.paid_signup("alice", "gunnar/10gb-1m", pb::Market::Se);
assert_eq!(w.main_pulls(), ["entitlement"]);
monetize_server::poller::tick(&w.state);
let ledger_before = w.state.ledger.export_rows().map(|r| r.len()).unwrap_or(0);
let queue_before = w.state.fleet.guardian().unwrap().store.queued(SAAS).len();
let held = w.main.entitled["alice"].clone();
let rec_before = format!(
"{:?}",
w.state
.signups
.get("stripe/gunnar", &s)
.unwrap()
.unwrap()
.state
);
for _ in 0..2 {
let (code, said) = w.paid(&s);
assert_eq!(code, 200, "{said}");
}
monetize_server::signup::settle_pending(&w.state);
monetize_server::poller::tick(&w.state);
// Re-driven: the same orders pulled again from 0 run nothing new.
let all = {
let g = w.state.fleet.guardian().unwrap();
g.store
.orders_for(SAAS, "main", 0)
.iter()
.map(monetize_server::services::fleet::order_pb)
.collect::<Vec<_>>()
};
assert!(w.main.run(all, wall_ms()).is_empty(), "replays run nothing");
assert_eq!(w.main_pulls(), Vec::<String>::new(), "nothing new to pull");
assert_eq!(
w.state.ledger.export_rows().map(|r| r.len()).unwrap_or(0),
ledger_before,
"no new ledger row"
);
assert_eq!(
w.state.fleet.guardian().unwrap().store.queued(SAAS).len(),
queue_before,
"no new order queued"
);
assert_eq!(
w.main.entitled["alice"], held,
"the box holds the same fact"
);
assert_eq!(
format!(
"{:?}",
w.state
.signups
.get("stripe/gunnar", &s)
.unwrap()
.unwrap()
.state
),
rec_before
);
assert_eq!(w.main.principals.len(), 1, "one account");
}
/// n) ★ **S8 (2026-10-11): a sold estate's LOST front is restored from its own daily backup,
/// not laid again** — the buyer's `EstateOrder.RestoreFront` (its `estate` ticket; the dead
/// front signs nothing) or the operator's guardian button. The front was laid with UpCloud's
/// daily backup (S6); its disk holds the estate's own keys, so what comes back is the SAME
/// front: nothing paired, no material taken, no order for main or the twin; their firewall
/// and the estate's DNS follow it to its new address. No backup yet: refused naming the
/// fallback (the re-lay with a one-time token).
#[test]
fn a_lost_front_is_restored_from_its_daily_backup_by_its_buyer_or_the_operator_and_keeps_its_keys()
{
use mock_upcloud::net::{firewall_admits, Admit};
use monetize_server::estate_order::EstateDns as _;
let _t = Timed(
"n) lost front → restored from its daily backup → same keys, estate healthy",
Instant::now(),
);
let mut w = World::new("n");
w.new_account("nina", "nina@buyer.example");
let (mut main, mut twin) = w.private_signed_in("acme1", "nina");
let run = w.state.estates.get("acme1").unwrap();
let laid = run.laid.clone().unwrap();
let front = laid.machine("front").unwrap().clone();
w._mock
.estate
.lock()
.unwrap()
.write_on(&front.disks[0].id, "acme1's front: its own keys")
.unwrap();
let ask = |w: &World, account: &str| {
let req = pb::EstateOrderRestoreFrontRequest {
company: "acme1".into(),
actor_ticket: estate_ticket(account),
};
w.rt.block_on(w.estates().restore_front(w.authed(req)))
.map(|r| r.into_inner())
};
let queued = |w: &World| ["main", "twin"].map(|r| w.queued_kinds("acme1", r));
let orders_before = queued(&w);
// No daily backup yet: refused, naming the fallback. The mock's clock runs 1000x real time
// and the signed UpCloud guest lays at the host's pace, so the front's first 03:00 backup
// may already be taken: any is removed here, and this half asks with none. **The clock is
// FROZEN for this half** (R6-FIX-2, 2026-10-27: at 1000x a 03:00 passed between the delete
// and the ask, the ask's own settle took a fresh backup, and the restore succeeded). Under
// one lock: the clock is stopped just past the next 03:00 (a frozen mock still advances on
// its reads, halfway to a pending transition, never a day), that 03:00's backup is taken
// and removed; the ask then meets no backup however long the host takes. The clock runs on
// at its own speed from where it stood.
let speed = w._mock.estate.lock().unwrap().clock.speed_milli();
{
let mut e = w._mock.estate.lock().unwrap();
const AT_0300: u64 = 3 * 3_600_000;
let now = e.clock.now_ms();
let past_next_0300 = if now < AT_0300 {
AT_0300
} else {
(now - AT_0300) / DAY * DAY + DAY + AT_0300
} + 1;
e.clock = Clock::virtual_only();
e.clock.advance_ms(past_next_0300);
e.settle();
let taken: Vec<String> = e
.storages_matching(&[], false)
.into_iter()
.filter(|s| {
s.kind == mock_upcloud::estate::StorageKind::Backup
&& s.origin.as_deref() == Some(front.disks[0].id.as_str())
})
.map(|s| s.uuid.clone())
.collect();
for b in taken {
e.delete_storage(&b).unwrap();
}
}
let frozen = w._mock.estate.lock().unwrap().clock.now_ms();
std::thread::sleep(Duration::from_millis(50)); // 50 s of the 1000x clock: none of it passes now
assert_eq!(
w._mock.estate.lock().unwrap().clock.now_ms(),
frozen,
"the clock is frozen for the no-backup half"
);
let none = ask(&w, "nina").unwrap_err();
assert_eq!(none.code(), tonic::Code::FailedPrecondition, "{none:?}");
assert!(
none.message()
.contains(estate_order::sold::RESTORE_FALLBACK),
"{}",
none.message()
);
{
let mut e = w._mock.estate.lock().unwrap();
let at = e.clock.now_ms();
e.clock = Clock::new(speed);
e.clock.advance_ms(at);
}
// 03:00: UpCloud backs the front's disk up.
{
let mut e = w._mock.estate.lock().unwrap();
e.clock.advance_ms(DAY);
e.settle();
}
// The front DIES: deleted at the provider with its disk (its backups are kept).
let mock = w._mock.clone();
let settle_until = |what: &str, done: &dyn Fn(&Estate) -> bool| {
for _ in 0..200 {
let mut e = mock.estate.lock().unwrap();
e.clock.advance_ms(30_000);
e.settle();
if done(&e) {
return;
}
}
panic!("never: {what}");
};
mock.estate
.lock()
.unwrap()
.stop_server(&front.server, true)
.unwrap();
settle_until("the front stopped", &|e| {
e.server(&front.server)
.is_some_and(|s| s.state == "stopped")
});
mock.estate
.lock()
.unwrap()
.delete_server(&front.server, true)
.unwrap();
settle_until("the front gone", &|e| e.server(&front.server).is_none());
// Not the buyer: refused, nothing restored.
assert!(
ask(&w, "olle").is_err(),
"only the estate's own account restores its front"
);
// The buyer restores it; main and twin are heard (the estate it comes back into stands).
w.report(&mut main);
w.report(&mut twin);
let said = ask(&w, "nina").expect("restored from its backup");
assert!(
said.moved && said.words.contains("its own keys kept"),
"{}",
said.words
);
assert_ne!(
said.public_ipv4, front.public_ipv4,
"a new server at a new address"
);
let run = w.state.estates.get("acme1").unwrap();
let restored = run.laid.as_ref().unwrap().machine("front").unwrap().clone();
assert_eq!(restored.public_ipv4, said.public_ipv4);
assert_eq!(run.phase, phase::CAPTURED, "the sale stands: {}", run.why);
{
let e = w._mock.estate.lock().unwrap();
assert_eq!(
e.written_on(&restored.disks[0].id),
Some("acme1's front: its own keys"),
"its OWN keys came back — nothing to trust again"
);
for role in ["main", "twin"] {
let m = e.server(&laid.machine(role).unwrap().server).unwrap();
assert_eq!(
laid.machine(role),
run.laid.as_ref().unwrap().machine(role),
"{role} untouched"
);
assert_eq!(
firewall_admits(
m.firewall_on,
&m.rules,
"udp",
&restored.utility_ipv4,
51820,
40000
),
Admit::Accept,
"{role} takes the relay from the restored front"
);
}
}
let dns = FileDns(w._dir.join("dns.json")).listed().unwrap();
assert!(
!dns.is_empty() && dns.iter().all(|d| d.value == restored.public_ipv4),
"the estate's names follow the front: {dns:?}"
);
// The estate goes on as before: main and twin report and pull; nothing was queued for them
// (no pairing, no material, no recharge).
w.pull_now(&mut main);
w.pull_now(&mut twin);
assert_eq!(
queued(&w),
orders_before,
"nothing re-trusted: no order for main or the twin"
);
// The OPERATOR's button, the next night: the guardian's `restore_front` takes the same
// path in place (the made-again front's own daily), the case done once main is heard.
{
let mut e = w._mock.estate.lock().unwrap();
e.clock.advance_ms(DAY);
e.settle();
e.write_on(&restored.disks[0].id, "spoilt").unwrap();
}
let g = w.state.fleet.guardian().unwrap().clone();
let shop = monetize_server::fleet::ShopWorld { state: &w.state };
let case = g
.press(
&shop,
"acme1",
monetize_product::guardian::Remedy::RestoreFront,
"",
"rickard",
true,
w.now(),
)
.expect("the operator presses");
g.tick(&shop, w.now());
w.later(1_000);
w.report(&mut main);
w.report(&mut twin);
g.tick(&shop, w.now());
let case = g.store.case(&case.id).unwrap();
assert_eq!(format!("{:?}", case.state), "Done", "{:#?}", case.log);
assert!(
case.log
.iter()
.any(|l| l.words.contains("the operator (rickard)")),
"{:#?}",
case.log
);
assert_eq!(
w._mock
.estate
.lock()
.unwrap()
.written_on(&restored.disks[0].id),
Some("acme1's front: its own keys"),
"in place, its keys back"
);
assert_eq!(
w.state
.estates
.get("acme1")
.unwrap()
.laid
.unwrap()
.machine("front")
.unwrap(),
&restored,
"the same front"
);
}
/// l) ★ **The operator's TEST BUTTON buys a real gunnar.rs account with nobody at a page**
/// (owner 2026-10-11: "a test button that creates a real account, fires up exactly like from
/// the signup page … no AI is involved"): Gunnar's OWN declared button → the sign-up path on the
/// ONE box → Stripe's test card on the TEST key (a confirmed intent, no hosted page) → the very
/// pull a paid webhook leads to → the account is made and its 10 GiB entitlement is pulled,
/// verified and active. The run is kept with its lines; the ledger's fact is the signup's.
#[test]
fn the_operators_test_button_buys_a_real_gunnar_rs_account_on_the_test_key_with_nobody_at_a_page() {
let _t = Timed(
"l) test button → Stripe's test card → the account made by pull",
Instant::now(),
);
let mut w = World::new("test-button");
let offers = monetize_server::test_purchase::actions(&w.state, "gunnar");
let hosted = offers
.iter()
.find(|o| o.id == "hosted-10gb")
.unwrap_or_else(|| panic!("Gunnar declares its hosted test button: {offers:?}"));
assert!(
hosted.runnable,
"the money-flow key is a TEST key: {hosted:?}"
);
assert!(
offers.iter().any(|o| o.id == "private-small" && o.runnable),
"{offers:?}"
);
let run = monetize_server::test_purchase::start(
&w.state,
"gunnar",
"hosted-10gb",
&hosted.site,
false,
)
.expect("pressed: a test key needs no live confirmation");
assert!(run.refused.is_empty(), "{run:?}");
assert_eq!(run.vendor, "stripe/gunnar");
assert!(
run.session.starts_with("pi_"),
"the test card's intent is the session: {run:?}"
);
// The fake as a process keeps its request log to itself; what it says of the keys it saw
// is the dashboard's word: never a live key. (money-flow also read the intent's form,
// `payment_method=pm_card_visa`, `confirm=true`, and that no checkout session was minted:
// the session above is the intent itself, `pi_…`, and the server's own test-button tests hold
// the form.)
let (st, seen) = w.fake.control("GET", "/seen-keys");
assert_eq!(
(st, seen["live_key_seen"].as_u64()),
(200, Some(0)),
"never a live key: {seen}"
);
// From here it is the paid webhook's own path: the main pulls the account, then its entitlement.
w.until("the test account's add_principal queued", |w| {
w.queued_kinds(SAAS, "main")
.contains(&"add_principal".to_string())
});
assert_eq!(
w.main_pulls(),
["add_principal"],
"the main made the account from the order it pulled"
);
monetize_server::signup::settle_pending(&w.state);
assert_eq!(
w.status(&run.session).state(),
pb::signup_status_response::State::Created
);
assert_eq!(
w.main_pulls(),
["entitlement"],
"refused {:?}",
w.main.refused
);
let f = &w.main.entitled[&run.username];
assert_eq!(
(f.state, f.caps.get("pack_bytes").copied()),
(monetize_embed::State::Paid, Some(10 * GIB)),
"{f:?}"
);
let seen =
monetize_server::test_purchase::view(&w.state, &w.state.tests.get(&run.id).expect("kept"));
assert_eq!(
(seen.state.as_str(), seen.signup_state.as_str()),
("done", "CREATED"),
"{seen:?}"
);
assert!(w.main.forged.is_empty() && w.main.refused.is_empty());
}
/// o) ★ **TWO SITES ON ONE BOX** (STINKY ST-17, ST-3..ST-6): gunnar.rs and test2.gunnar.rs both
/// joined, each calling with its own ONE bearer. On test2: an account is made by TEST2's main
/// (never gunnar.rs's), booked `@test2.gunnar.rs/nina`; the same address then gets its own
/// account on gunnar.rs (one account per site); a 10 GB plan bought signed in on test2 is
/// checked under TEST2's ticket key, bills TEST2's own Stripe account, and its entitlement is
/// pulled by TEST2's main; a test2 ticket presented by gunnar.rs is refused.
#[test]
fn two_sites_on_one_box_each_make_bill_and_deliver_on_their_own_estate() {
let _t = Timed(
"o) two sites: accounts, plans and money on each site's own estate",
Instant::now(),
);
let w = World::new_with("two-sites", &two_sites());
let mut t2 = w.join(TEST2, TEST2_BEARER, TEST2_MAIN_SEED);
let _home = w.join(SAAS, HOME_BEARER, MAIN_SEED);
// ── an account on test2 ──
let mut c = pb::signup_client::SignupClient::new(w.channel.clone());
let req = |name: &str, host: &str| pb::StartSignupRequest {
username: name.into(),
product: "gunnar".into(),
plan: "gunnar/account".into(),
success_url: format!("https://{host}/welcome?session={{session}}"),
cancel_url: format!("https://{host}/"),
email: "nina@buyer.example".into(),
market: pb::Market::Se as i32,
..Default::default()
};
let started =
w.rt.block_on(c.start(w.as_bearer(TEST2_BEARER, req("nina", "test2.gunnar.test"))))
.expect("test2's account Start")
.into_inner();
let (code, said) = w.check_card_at("gunnar-test2", &started.session, "nina");
assert_eq!(code, 200, "test2's card check: {said}");
w.until("nina's add_principal queued for test2's main", |w| {
w.returns("stripe/gunnar-test2", &started.session);
w.queued_kinds(TEST2, "main")
.contains(&"add_principal".to_string())
});
assert!(
w.queued_kinds(SAAS, "main").is_empty(),
"gunnar.rs's main is never asked for test2's account"
);
assert_eq!(
w.pull(&mut t2),
["add_principal"],
"test2's main made the account: {:?}",
t2.refused
);
// The ack may be settling it behind the report already (one settle per session at a time).
w.until("test2's nina is CREATED", |w| {
monetize_server::signup::settle_pending(&w.state);
w.state
.signups
.get(monetize_server::signup::ACCOUNT_VENDOR, &started.session)
.ok()
.flatten()
.is_some_and(|r| !r.state.is_pending())
});
let rec = w
.state
.signups
.get(monetize_server::signup::ACCOUNT_VENDOR, &started.session)
.unwrap()
.expect("kept");
assert_eq!(
rec.estate.as_deref(),
Some(TEST2),
"the record keeps its site"
);
assert!(
matches!(
rec.state,
monetize_server::signup::SignupState::Created { .. }
),
"{:?}",
rec.state
);
// ── the same address on gunnar.rs: its own account there (ST-6), made by gunnar.rs's main ──
let home =
w.rt.block_on(c.start(w.as_bearer(HOME_BEARER, req("nina", "gunnar.test"))))
.expect("one account per SITE: gunnar.rs has none yet")
.into_inner();
let (code, said) = w.check_card(&home.session, "nina-home");
assert_eq!(code, 200, "gunnar.rs's card check: {said}");
w.until("nina's add_principal queued for gunnar.rs's main", |w| {
w.returns("stripe/gunnar", &home.session);
w.queued_kinds(SAAS, "main")
.contains(&"add_principal".to_string())
});
let again =
w.rt.block_on(c.start(w.as_bearer(TEST2_BEARER, req("nina2", "test2.gunnar.test"))))
.expect_err("test2 already has nina's account");
assert_eq!(
again.message(),
monetize_server::signup::words::EMAIL_HAS_ACCOUNT
);
// ── a 10 GB plan on test2, signed in: test2's key, test2's Stripe, test2's main ──
let mut p = pb::purchase_client::PurchaseClient::new(w.channel.clone());
let buy = |seed: [u8; 32]| pb::StartPurchaseRequest {
product: "gunnar".into(),
tenant: "nina".into(),
caps: ten_gib().into_iter().collect(),
payer: "nina@buyer.example".into(),
market: pb::Market::Se as i32,
actor_ticket: ticket_under(seed, "nina", PURPOSE_ORDER, ten_gib()),
..Default::default()
};
let refused =
w.rt.block_on(p.start(w.as_bearer(HOME_BEARER, buy(TEST2_APPLIANCE_SEED))))
.expect_err("a test2 ticket is not gunnar.rs's");
assert!(
matches!(
refused.code(),
tonic::Code::PermissionDenied | tonic::Code::Unauthenticated
),
"{refused:?}"
);
let bought =
w.rt.block_on(p.start(w.as_bearer(TEST2_BEARER, buy(TEST2_APPLIANCE_SEED))))
.expect("test2's plan Start")
.into_inner();
assert_eq!(
bought.handle_vendor, "stripe/gunnar-test2",
"billed through TEST2's own Stripe account: {bought:?}"
);
assert!(
bought.reference.contains(&format!("@{TEST2}/nina")),
"booked on test2's nina: {}",
bought.reference
);
let ev = w.pay(&bought.handle_id);
let (code, said) = w.webhook_to("gunnar-test2", &ev);
assert_eq!(code, 200, "{said}");
w.until("test2's nina's entitlement queued for test2's main", |w| {
w.queued_kinds(TEST2, "main")
.contains(&"entitlement".to_string())
});
assert!(
!w.queued_kinds(SAAS, "main")
.contains(&"entitlement".to_string()),
"gunnar.rs's main is never handed test2's plan"
);
assert_eq!(w.pull(&mut t2), ["entitlement"], "{:?}", t2.refused);
let f = &t2.entitled["nina"];
assert_eq!(f.caps.get("pack_bytes").copied(), Some(10 * GIB), "{f:?}");
}
/// p) ★ **The owner's walk on test2, the ONE box's Accounts page** (T-OWNERFLOW, the owner's own
/// purchase 2026-10-26: alica on test2.gunnar.rs, then rickardtest; ALICA part 2): a visitor on
/// test2 pays a 1-month 10 GB plan through TEST2's own Stripe account, then, signed in, orders a
/// private Gunnar there. The Accounts page must say what happened: the account's vendor is the
/// one that took the money (`stripe/gunnar-test2`, not the product's `stripe/gunnar`), the purchase
/// row says the same, the mode is said (the vendor's own key: test here) even with no drawn sale
/// that says it, the plan's paid-until is the plan's month and the instance row has its own term.
#[test]
fn owner_walk_on_test2_the_accounts_page_names_the_sites_vendor_the_mode_and_each_rows_term() {
let _t = Timed(
"p) owner's walk on test2: the Accounts page",
Instant::now(),
);
let w = World::new_with("owner-walk", &two_sites());
let mut t2 = w.join(TEST2, TEST2_BEARER, TEST2_MAIN_SEED);
let _home = w.join(SAAS, HOME_BEARER, MAIN_SEED);
// ── alica's 10 GB plan on test2, a visitor: TEST2's Stripe account, TEST2's main ──
let mut c = pb::signup_client::SignupClient::new(w.channel.clone());
let req = pb::StartSignupRequest {
username: "alica".into(),
product: "gunnar".into(),
plan: "gunnar/10gb-1m".into(),
success_url: "https://test2.gunnar.test/welcome?session={session}".into(),
cancel_url: "https://test2.gunnar.test/".into(),
email: "alica@mock.invalid".into(),
market: pb::Market::Se as i32,
..Default::default()
};
let started =
w.rt.block_on(c.start(w.as_bearer(TEST2_BEARER, req)))
.expect("test2's paid plan Start")
.into_inner();
let ev = w.pay(&started.session);
let (code, said) = w.webhook_to("gunnar-test2", &ev);
assert_eq!(code, 200, "{said}");
w.until("alica's add_principal queued for test2's main", |w| {
w.queued_kinds(TEST2, "main")
.contains(&"add_principal".to_string())
});
assert!(
w.pull(&mut t2).contains(&"add_principal".to_string()),
"test2's main made alica: {:?}",
t2.refused
);
w.until("test2's alica is CREATED", |w| {
monetize_server::signup::settle_pending(&w.state);
w.state
.signups
.get("stripe/gunnar-test2", &started.session)
.ok()
.flatten()
.is_some_and(|r| !r.state.is_pending())
});
// ── rickardtest, signed in on test2: TEST2's ticket key, TEST2's Stripe account ──
let order = pb::EstateOrderStartRequest {
company: "rickardtest".into(),
account: "alica".into(),
actor_ticket: ticket_under(
TEST2_APPLIANCE_SEED,
"alica",
PURPOSE_ESTATE,
BTreeMap::new(),
),
..Default::default()
};
w.rt.block_on(w.estates().start(w.as_bearer(TEST2_BEARER, order)))
.expect("rickardtest, signed in on test2");
let run = w.state.estates.get("rickardtest").expect("the run");
assert_eq!(
run.email, "alica@mock.invalid",
"the order mails the account's own address"
);
w.pay(&run.handle.as_ref().unwrap().id);
let _boxes = w.deliver("rickardtest");
monetize_server::poller::tick(&w.state);
// ── the Accounts page ──
let listed = w.accounts();
let acct = listed
.iter()
.find(|a| a.tenant.ends_with("/alica") || a.tenant == "alica")
.cloned()
.unwrap_or_else(|| panic!("alica is not on the Accounts page: {listed:?}"));
let rows = w.rows(&acct.tenant);
let purchase = rows
.rows
.iter()
.find(|r| r.kind == "purchase" && r.id.contains(&started.session))
.unwrap_or_else(|| panic!("the plan's purchase row: {:?}", rows.rows));
assert!(
purchase.id.contains("stripe/gunnar-test2"),
"the purchase's own id keeps the vendor that took the money: {purchase:?}"
);
// ALICA F1: the label is the vendor of the account's SITE, and the purchase row's own.
assert_eq!(
acct.vendor, "stripe/gunnar-test2",
"the account's Stripe cell names test2's account (the money went there): {acct:?}"
);
assert_eq!(
purchase.vendor, "stripe/gunnar-test2",
"the purchase row names the vendor in its own reference: {purchase:?}"
);
// ALICA F2: the mode is the vendor key's own when no drawn sale says it (test keys here).
assert_eq!(
acct.livemode,
Some(false),
"the mode is said (the fake's test key): {acct:?}"
);
// Each row its own term: the plan's month on the subscription, the instance's on its row.
// The month runs from when the vendor took the money (its clock: the fake Stripe pays at a
// fixed time of its own, never this box's now).
let paid_at = w
.state
.signups
.get("stripe/gunnar-test2", &started.session)
.ok()
.flatten()
.map(|r| r.signup.paid_at_unix_ms)
.expect("alica's paid signup") as u64;
let month = acct.paid_until_unix_ms.unwrap_or(0);
assert!(
month > paid_at + 29 * DAY && month < paid_at + 31 * DAY,
"the plan's month from its payment at {paid_at}: {acct:?}"
);
let inst = rows
.rows
.iter()
.find(|r| r.kind == "instance" && r.id.contains("rickardtest"))
.and_then(|r| r.instance.clone())
.unwrap_or_else(|| panic!("the instance row: {:?}", rows.rows));
assert!(
!inst.paid_until.is_empty(),
"the instance row names its own term: {inst:?}"
);
let ins = rows.rows.iter().find(|r| r.kind == "instance").unwrap();
assert_eq!(
ins.vendor, "stripe/gunnar-test2",
"the instance was billed through test2's account: {ins:?}"
);
}