holger-estate-front/tests/sweep_buy_flow.rs
//! ★ **The shared buy flow on Holger's site, end to end, and never a call to the ONE box by
//! name** (lane TEST-SWEEP-PRODUCTS, 2026-10-24): sign-up (free and paid), pay, welcome, grow
//! and cancel, each through the front's REAL provider (`buy::HolgerSite`, mounted by
//! `buy::relay_router`) over the shared relay, against the shared fake ONE box and fake Stripe
//! (monetize-site-buy `testkit`). The primary's buy doors are stood in on loopback exactly as
//! `holgers_site_runs_the_shared_buy_flow.rs` stands them in.
//!
//! What "never a call to `monetize.ignalina.dk`" means here, measured and not assumed: the ONE
//! box the site is fed is the fake on loopback, every shop call of the flow is in the fake's
//! book (so the flow did call a ONE box, and it was this one), every way back and every page
//! the site handed out is on Holger's own origin, and no address the flow produced or recorded
//! names the real ONE box. Addresses are `*.mock.invalid`.
//!
//! The fake's `Purchase.Cancel` closes an unpaid order and refuses a paid one (testkit); its
//! `EstateOrder.Cancel` answers UNIMPLEMENTED, so that leg proves the relay carries the cancel
//! and answers the refusal in words. A visitor's cancel stops at the door.
#![cfg(all(feature = "console", feature = "metered"))]
use std::collections::BTreeMap;
use std::sync::{Arc, Mutex};
use axum::http::{HeaderMap, StatusCode};
use monetize_site_buy::testkit::{
FakeOneBox, BUNDLE, BUNDLE_BYTES, FREE_BYTES, FREE_ROW, PAID_ROW,
};
use serde_json::{json, Value};
use tower::ServiceExt as _;
const BEARER: &str = "holger-site-bearer-for-the-sweep";
const PERSON: &str = "Bearer person-token-of-x14";
const CONSOLE: &str = "console-token-for-the-sweep";
const ORIGIN: &str = "https://holger.mock.invalid";
/// The real ONE box's name: it must appear nowhere in the flow.
const THE_ONE_BOX: &str = "ignalina";
fn hex(b: &[u8]) -> String {
b.iter().map(|x| format!("{x:02x}")).collect()
}
/// The primary's buy doors, as holger main answers them (the same stand-in as the sibling test).
async fn primary(fake: FakeOneBox) -> String {
use axum::routing::{get, post};
let me = {
let fake = fake.clone();
move |h: HeaderMap| {
let fake = fake.clone();
async move {
if h.get("authorization").and_then(|v| v.to_str().ok()) != Some(PERSON) {
return axum::Json(json!({"who": "visitor"}));
}
let caps = fake
.book()
.accounts
.get("x14")
.map(|a| a.caps.clone())
.unwrap_or_default();
axum::Json(
json!({"who": "person", "account": "x14", "tenant": "x14", "bound": true, "caps": caps}),
)
}
}
};
let account = {
let fake = fake.clone();
move |h: HeaderMap,
axum::extract::Query(q): axum::extract::Query<BTreeMap<String, String>>| {
let fake = fake.clone();
async move {
if h.get("authorization").and_then(|v| v.to_str().ok())
!= Some(&format!("Bearer {CONSOLE}"))
{
return (
StatusCode::UNAUTHORIZED,
axum::Json(json!({"error": "the console asks this"})),
);
}
let held = fake
.book()
.accounts
.contains_key(q.get("user").map(String::as_str).unwrap_or(""));
(
StatusCode::OK,
axum::Json(json!({"account": if held { "no_passkey" } else { "none" }})),
)
}
}
};
let app = axum::Router::new()
.route("/-/buy/me", get(me))
.route("/-/buy/account", get(account))
.route(
"/-/buy/ticket",
post(|h: HeaderMap, axum::Json(b): axum::Json<Value>| async move {
if h.get("authorization").and_then(|v| v.to_str().ok()) != Some(PERSON) {
return (StatusCode::UNAUTHORIZED, axum::Json(json!({"error": "sign in to buy"})));
}
// A fresh nonce per ticket, as holger main's: the ONE box spends each once.
static NONCE: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
let nonce = NONCE.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
let t = json!({"subject": "x14", "purpose": b["purpose"], "caps": b["caps"], "nonce": nonce, "by": "holger-fleet-key"});
(StatusCode::OK, axum::Json(json!({"ticket": hex(t.to_string().as_bytes())})))
}),
);
let l = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap();
let at = l.local_addr().unwrap();
tokio::spawn(async move { axum::serve(l, app).await });
at.to_string()
}
/// The site under test: the front's relay from its feed, the fake ONE box it is fed, and every
/// answer body the site gave (scanned at the end for the real ONE box's name).
struct Site {
app: axum::Router,
fake: FakeOneBox,
said: Arc<Mutex<Vec<String>>>,
}
impl Site {
async fn up() -> Site {
let fake = FakeOneBox::spawn("holger", BEARER).await;
// A ONE box that checks Holger's tickets: its grow doors need them (owner 2026-10-26).
fake.verify_tickets();
let door = primary(fake.clone()).await;
let feed: BTreeMap<String, String> = [
(
holger_estate_front::buy::FEED_MONETIZE_BEARER,
BEARER.to_string(),
),
(
holger_estate_front::buy::FEED_CONSOLE_PRODUCT,
"holger".into(),
),
(holger_estate_front::buy::FEED_FLEET, fake.url()),
(
holger_estate_front::buy::FEED_PASSKEY_RP,
"holger.mock.invalid".into(),
),
]
.into_iter()
.map(|(k, v)| (k.to_string(), v))
.collect();
assert!(
!fake.url().contains(THE_ONE_BOX),
"the site is fed the fake, on loopback: {}",
fake.url()
);
let shop = holger_estate_front::buy::shop_feed_of(&feed)
.expect("the feed sells here")
.expect("a usable feed");
let app = holger_estate_front::buy::relay_router(&shop, &door, Some(CONSOLE.into()))
.expect("the relay");
Site {
app,
fake,
said: Arc::new(Mutex::new(Vec::new())),
}
}
async fn ask(
&self,
method: &str,
uri: &str,
auth: Option<&str>,
body: Option<Value>,
) -> (StatusCode, Value) {
let mut req = axum::http::Request::builder()
.method(method)
.uri(uri)
.header("x-forwarded-for", "203.0.113.9");
if let Some(a) = auth {
req = req.header("authorization", a);
}
let req = match body {
Some(b) => req
.header("content-type", "application/json")
.body(axum::body::Body::from(b.to_string()))
.unwrap(),
None => req.body(axum::body::Body::empty()).unwrap(),
};
let res = self.app.clone().oneshot(req).await.unwrap();
let status = res.status();
let bytes = axum::body::to_bytes(res.into_body(), 1 << 20)
.await
.unwrap();
self.said
.lock()
.unwrap()
.push(String::from_utf8_lossy(&bytes).into_owned());
(
status,
serde_json::from_slice(&bytes).unwrap_or(Value::Null),
)
}
/// A visitor signs up for `plan`, pays on the fake Stripe, and is welcomed on Holger's own
/// origin; the account is made only then. Returns the sign-up session.
async fn sign_up_pay_and_be_welcomed(
&self,
user: &str,
plan: &str,
mails_before: usize,
) -> String {
let plan = format!("holger/{plan}");
let (st, started) = self.ask("POST", "/auth/signup/start", None, Some(json!({"username": user, "email": format!("{user}@mock.invalid"), "plan": plan, "next": "/"}))).await;
assert_eq!(st, StatusCode::OK, "{started}");
let url = started["url"].as_str().unwrap().to_owned();
let session = url.rsplit('/').next().unwrap().to_owned();
let (_, pending) = self
.ask(
"GET",
&format!("/auth/signup/status?session={session}"),
None,
None,
)
.await;
assert_eq!(
pending["state"], "pending",
"nothing is made before the payment clears: {pending}"
);
assert!(
!self.fake.book().accounts.contains_key(user),
"no account before the payment"
);
assert!(self.fake.pay(&url), "the fake Stripe page is paid");
let welcome = self
.fake
.book()
.checkout(&url)
.expect("the checkout")
.return_url();
assert!(
welcome.starts_with(&format!("{ORIGIN}/welcome?session={session}")),
"the way back from Stripe is Holger's own welcome: {welcome}"
);
let (st, made) = self
.ask(
"GET",
&format!("/auth/signup/status?session={session}"),
None,
None,
)
.await;
assert_eq!(st, StatusCode::OK, "{made}");
assert_eq!(made["state"], "created", "{made}");
assert_eq!(
made["invite_url"],
format!("/login?signup={session}&user={user}"),
"the primary holds the account, no passkey yet: {made}"
);
assert_eq!(
self.fake.book().mails.len(),
mails_before + 1,
"one sign-in mail, at account creation"
);
session
}
/// Nothing in the flow named the real ONE box, and the ONE box that WAS called is the fake.
fn assert_nothing_went_to_the_one_box_by_name(&self) {
let b = self.fake.book();
assert!(!b.calls.is_empty(), "the flow called a ONE box");
assert!(b.bearers.iter().all(|x| x == &format!("Bearer {BEARER}")), "every call carried the site's own bearer, so every call was the site's to the fake: {:?}", b.bearers);
let mut seen: Vec<String> = b
.urls
.iter()
.map(|(call, url)| format!("{call}: {url}"))
.collect();
seen.extend(b.checkouts.iter().flat_map(|c| {
[
format!("success: {}", c.success_url),
format!("cancel: {}", c.cancel_url),
format!("page: {}", c.url()),
]
}));
for s in &seen {
assert!(
!s.contains(THE_ONE_BOX),
"a way back or a page named the real ONE box: {s}"
);
if let Some(url) = s.split_once(": ").map(|(_, u)| u) {
if url.starts_with("https://holger.") || url.starts_with("https://stripe.") {
assert!(
url.starts_with(ORIGIN)
|| url.starts_with(monetize_site_buy::testkit::STRIPE),
"a page off Holger's origin and off the fake Stripe: {url}"
);
}
}
}
for said in self.said.lock().unwrap().iter() {
assert!(
!said.contains(THE_ONE_BOX),
"the site named the real ONE box in an answer: {said}"
);
}
}
}
#[tokio::test(flavor = "multi_thread", worker_threads = 4)]
async fn sweep_free_and_paid_sign_ups_pay_and_are_welcomed_on_holgers_own_origin() {
let site = Site::up().await;
let (st, plans) = site.ask("GET", "/auth/signup/ladder", None, None).await;
assert_eq!(st, StatusCode::OK, "{plans}");
assert_eq!(plans["plans"][0]["id"], format!("holger/{FREE_ROW}"));
assert_eq!(plans["plans"][1]["id"], format!("holger/{PAID_ROW}"));
let (st, name) = site
.ask("GET", "/auth/signup/name?u=freya", None, None)
.await;
assert_eq!(
(st, name["free"].as_bool()),
(StatusCode::OK, Some(true)),
"{name}"
);
site.sign_up_pay_and_be_welcomed("freya", FREE_ROW, 0).await;
{
let b = site.fake.book();
let c = &b.checkouts[0];
assert!(
c.setup && c.amount_minor == 0,
"the free account is Stripe's 0 kr card check: {c:?}"
);
assert_eq!(b.accounts["freya"].caps["disk_bytes"], FREE_BYTES);
}
site.sign_up_pay_and_be_welcomed("paula", PAID_ROW, 1).await;
{
let b = site.fake.book();
let c = &b.checkouts[1];
assert!(
!c.setup && c.amount_minor == monetize_site_buy::testkit::PAID_MINOR,
"the paid plan is one Stripe page for its amount: {c:?}"
);
assert_eq!(
b.accounts["paula"].caps["disk_bytes"],
monetize_site_buy::testkit::PAID_BYTES
);
assert_eq!(b.checkouts.len(), 2, "two sign-ups, two Stripe pages");
}
site.assert_nothing_went_to_the_one_box_by_name();
}
#[tokio::test(flavor = "multi_thread", worker_threads = 4)]
async fn sweep_a_signed_in_person_grows_pays_and_cancels_on_holgers_site() {
let site = Site::up().await;
site.fake
.add_account("x14", "x14@mock.invalid", &[("disk_bytes", 5 << 30)]);
// Grow: the bundles window, one bought, paid, done.
let (st, window) = site
.ask(
"GET",
"/api/account/subscription/bundles",
Some(PERSON),
None,
)
.await;
assert_eq!(st, StatusCode::OK, "{window}");
let (st, buy) = site
.ask(
"POST",
"/api/account/subscription/buy-bundle",
Some(PERSON),
Some(json!({"bundle": BUNDLE})),
)
.await;
assert_eq!(st, StatusCode::OK, "{buy}");
assert_eq!(
buy["after"]["disk_bytes"].as_u64(),
Some((5 << 30) + BUNDLE_BYTES)
);
assert!(site.fake.pay(buy["url"].as_str().unwrap()));
let (_, done) = site
.ask(
"GET",
&format!(
"/api/account/subscription/status?reference={}",
buy["reference"].as_str().unwrap()
),
Some(PERSON),
None,
)
.await;
assert_eq!(
(done["state"].as_str(), done["phase"].as_str()),
(Some("paid"), Some("done")),
"{done}"
);
// Cancel: a second order, not paid, cancelled by its buyer with the `cancel` ticket: closed,
// its reason the customer's; the paid order cannot be cancelled here; a visitor cancels nothing.
let (st, again) = site
.ask(
"POST",
"/api/account/subscription/buy-bundle",
Some(PERSON),
Some(json!({"bundle": BUNDLE})),
)
.await;
assert_eq!(st, StatusCode::OK, "{again}");
let reference = again["reference"].as_str().unwrap().to_owned();
let (st, cancelled) = site
.ask(
"POST",
"/api/account/subscription/cancel",
Some(PERSON),
Some(json!({"reference": reference})),
)
.await;
assert_eq!(st, StatusCode::OK, "{cancelled}");
assert_eq!(
(
cancelled["phase"].as_str(),
cancelled["cancellable"].as_bool()
),
(Some("cancelled"), Some(false)),
"{cancelled}"
);
assert_eq!(
cancelled["reason"],
monetize_site_buy::relay::CANCELLED_BY_CUSTOMER,
"{cancelled}"
);
{
let b = site.fake.book();
assert!(
b.calls.iter().any(|c| c == "Purchase.Cancel"),
"the shop heard the cancel: {:?}",
b.calls
);
let t = &b
.tickets
.iter()
.rev()
.find(|(c, _)| c == "Purchase.Cancel")
.expect("a cancel ticket")
.1;
assert_eq!(
serde_json::from_slice::<Value>(t).unwrap()["purpose"],
"cancel",
"the primary's cancel ticket vouches for it"
);
}
let (st, refused) = site
.ask(
"POST",
"/api/account/subscription/cancel",
Some(PERSON),
Some(json!({"reference": buy["reference"].as_str().unwrap()})),
)
.await;
assert_eq!(
st,
StatusCode::CONFLICT,
"a paid order is not cancelled here: {refused}"
);
let (st, _) = site
.ask(
"POST",
"/api/account/subscription/cancel",
None,
Some(json!({"reference": "p-1"})),
)
.await;
assert_eq!(st, StatusCode::UNAUTHORIZED, "a visitor cancels nothing");
// A private instance's renewal stopped: the estate door; the fake's shop does not implement
// it, and the site answers the refusal in words, never a 200 and never a panic.
let (st, private) = site.ask("POST", "/auth/private/start", Some(PERSON), Some(json!({"company": "acme", "email": "other@mock.invalid", "front_plan": "f-mini", "main_plan": "m-mini", "main_data_gib": 40}))).await;
assert_eq!(st, StatusCode::OK, "{private}");
let (st, stopped) = site
.ask(
"POST",
"/auth/private/cancel",
Some(PERSON),
Some(json!({"company": "acme"})),
)
.await;
assert_eq!(st, StatusCode::BAD_GATEWAY, "{stopped}");
assert!(
stopped
.get("error")
.and_then(Value::as_str)
.is_some_and(|w| !w.is_empty()),
"{stopped}"
);
assert_eq!(
site.fake.book().checkouts.len(),
3,
"two bundles and one estate: three Stripe pages, all on the fake"
);
site.assert_nothing_went_to_the_one_box_by_name();
}