crates/monetize-server/src/estate_order/tests/overview_slot.rs
//! ★ **OVW-CLEAN (owner 2026-10-29): the Overview lists only estates that exist, and one slot
//! makes a new one.** Prod's Overview listed every declared site and every record its store
//! keeps: test2-gunnar-rs and test2-holger-rs (declared, not ordered) and acme2, ignalina, polka,
//! rickardtest and test3-holger-rs (terminated orders and signups, still in the fleet's store),
//! each as "not installed".
//!
//! * `Estates.Overview`: the rows are what is installed or being laid; what ended or was never
//! installed is the quiet line; a declared site with no row is the slot's to start by name.
//! * `Estates.NewEstate`: a declared operator site is ordered as it is; a new name is copied from a
//! declared site of its product into the SITE BOOK, then ordered — the one site order, the
//! same payment page. Refused by name, before anything is kept or held.
use std::sync::OnceLock;
use super::*;
use crate::services::estates::EstatesService;
use crate::site_book::{SiteBook, SiteBookLink, SiteBookRefusal, SitePut, SitePutDone, SiteShown};
use monetize_proto as pb;
use monetize_proto::estates_server::Estates as _;
/// A site book that keeps each put and declares it at once, as the ONE box's config watcher
/// does a look later: the new site copies the orders (the media) of the site it names.
#[derive(Clone, Default)]
struct Book {
state: Arc<OnceLock<Arc<AppState>>>,
puts: Arc<Mutex<Vec<SitePut>>>,
/// A box that takes the put late: it is kept, and declared only by [`Book::take`].
slow: Arc<std::sync::atomic::AtomicBool>,
}
impl Book {
/// Declare `p` as the ONE box's config watcher does once it looks.
fn take(&self, p: &SitePut) {
let state = self.state.get().expect("the rig's state");
let orders = state
.registry
.declared_estates()
.into_iter()
.find(|(l, _)| *l == p.media_from)
.map(|(_, e)| e.orders)
.unwrap_or_default();
let e = crate::config::EstateConfig {
product: p.product.clone(),
vendor: p.vendor.clone(),
owner: p.first_admin.clone(),
site: p.domain.clone(),
operator_site: p.operator_site,
terminable: p.terminable,
orders,
..Default::default()
};
state.registry.declare_estate(&p.estate, e);
}
}
impl SiteBook for Book {
fn show(&self, estate: &str) -> Result<SiteShown, SiteBookRefusal> {
Err(SiteBookRefusal::NotFound(format!(
"{estate} is not in this fake"
)))
}
fn put(&self, p: &SitePut) -> Result<SitePutDone, SiteBookRefusal> {
self.puts.lock().unwrap().push(p.clone());
if !self.slow.load(std::sync::atomic::Ordering::SeqCst) {
self.take(p);
}
Ok(SitePutDone {
words: format!("{} is added", p.estate),
changed: Vec::new(),
})
}
}
/// The ONE box of the rig: `gunnar-rs` (its home, protected), `test2-gunnar-rs` (an operator
/// test site with media of its own, declared and never ordered) and `kunde-se` (a customer's
/// site, under the zone), with a site book when `book` is given.
fn rig(name: &str, book: Option<Book>) -> (Arc<AppState>, HoldPay) {
let dir = tmp(name);
let pay = HoldPay::default();
let site = |vendor: &str, site: &str, operator_site: bool| crate::config::EstateConfig {
product: "gunnar".into(),
vendor: vendor.into(),
site: site.into(),
owner: "ignalina".into(),
operator_site,
..Default::default()
};
let mut test2 = crate::config::EstateConfig {
terminable: true,
..site("holdpay", "test2.gunnar.rs", true)
};
test2.orders.media.insert("dev".into(), "dev-media".into());
test2.orders.term_days = Some(1);
let mut reg = Registry::new()
.sells("gunnar", pay.clone())
.vendor(SitePay("sitepay-kunde"))
.cloud(Arc::new(MockCloud::new()))
.shared_product(shop_product())
.home("gunnar", "gunnar-rs")
.estate("gunnar-rs", site("holdpay", "gunnar.rs", true))
.estate("test2-gunnar-rs", test2)
.estate("kunde-se", site("sitepay-kunde", "kunde.gunnar.rs", false));
if let Some(b) = &book {
reg = reg.with_linked(crate::registry::Linked {
site_book: Some(SiteBookLink(Arc::new(b.clone()))),
..Default::default()
});
}
let (state, ..) = build_in(
reg,
&dir,
EstateOrderConfig {
vendor: String::new(),
apex: String::new(),
..cfg()
},
FakeKit::new("PASS"),
None,
None,
);
if let Some(b) = book {
let _ = b.state.set(state.clone());
}
(state, pay)
}
fn names(lines: &[standing::EstateLine]) -> Vec<(&str, &str)> {
lines
.iter()
.map(|l| (l.name.as_str(), l.standing))
.collect()
}
/// ★ RED: **the rows are the estates that exist**; the leftovers are the quiet line; a declared
/// site that was never ordered is no row and is the slot's to start.
#[test]
fn the_overview_lists_what_exists_and_hides_the_leftovers() {
let (state, _pay) = rig("ovw-standing", None);
let g = state.fleet.guardian().unwrap();
// gunnar.rs runs (kit-installed: a fleet record whose main reports, no run here).
g.store.declare("gunnar-rs", "gunnar").unwrap();
g.store
.record_report("gunnar-rs", "main", state.now(), &running("main"))
.unwrap();
// A signup's leftover: declared in the fleet's store, never installed (polka, ignalina …).
g.store.declare("polka", "gunnar").unwrap();
let o = standing::overview(&state);
assert_eq!(
names(&o.estates),
[("gunnar-rs", "installed")],
"only what exists is a row: {o:#?}"
);
assert!(
o.estates[0].in_fleet && o.estates[0].domain == "gunnar.rs",
"{o:#?}"
);
assert_eq!(names(&o.ended), [("polka", "never_installed")]);
assert_eq!(
o.ended[0].words,
"never installed: no machine of it ever reported in"
);
assert_eq!(
o.declared,
["test2-gunnar-rs"],
"declared, never ordered: no row, startable by name (a customer's site never)"
);
assert_eq!(
o.products,
["gunnar"],
"the slot makes what a declared site with media of its own can be copied from"
);
// Ordered: a row being laid, before the fleet knows it.
site::start_site(
&state,
"test2-gunnar-rs",
"ops@example.invalid",
&EstateSizes::default(),
)
.expect("ordered");
let o = standing::overview(&state);
assert_eq!(
names(&o.estates),
[("gunnar-rs", "installed"), ("test2-gunnar-rs", "laying")]
);
let t2 = &o.estates[1];
assert_eq!(
(
t2.words.as_str(),
t2.in_fleet,
t2.domain.as_str(),
t2.product.as_str()
),
(
"ordered: waiting for its payment",
false,
"test2.gunnar.rs",
"gunnar"
)
);
assert!(
o.declared.is_empty(),
"a site with a row is not offered to the slot: {o:#?}"
);
// Terminated (acme2, rickardtest, test3-holger-rs …): its fleet record stays, its boxes go.
g.store.declare("test2-gunnar-rs", "gunnar").unwrap();
{
let _pen = state.estates.pen("test2gunnarrs");
let mut run = state.estates.get("test2gunnarrs").unwrap();
run.phase = phase::TERMINATED.into();
run.history.push(Transition {
phase: phase::TERMINATED.into(),
at_ms: 1_793_059_200_000,
note: "terminated by the operator".into(),
});
save(&state, &run).unwrap();
}
let o = standing::overview(&state);
assert_eq!(names(&o.estates), [("gunnar-rs", "installed")]);
assert_eq!(
names(&o.ended),
[("polka", "never_installed"), ("test2-gunnar-rs", "ended")]
);
assert_eq!(o.ended[1].words, "terminated on 2026-10-27");
assert_eq!(
o.declared,
["test2-gunnar-rs"],
"an ended site is the slot's to start again"
);
}
/// The operator's marker on a request, as the door's operator bearer carries it.
fn as_operator<T>(r: T) -> tonic::Request<T> {
let mut req = tonic::Request::new(r);
req.extensions_mut().insert(crate::auth::Operator);
req
}
fn ask(name: &str, product: &str) -> pb::NewEstateRequest {
pb::NewEstateRequest {
name: name.into(),
product: product.into(),
email: "ops@example.invalid".into(),
actor: "console:op-1".into(),
..Default::default()
}
}
/// ★ RED: **the slot makes a new estate and hands it to the ONE site order** — copied from the
/// declared test site of its product into the site book, its domain from its name, then the
/// same order and payment page as the Sites page's; and the Overview shows it being laid.
#[test]
fn the_slot_makes_a_new_estate_and_hands_it_to_the_one_site_order() {
let book = Book::default();
let (state, pay) = rig("ovw-new", Some(book.clone()));
let svc = EstatesService(state.clone());
let rt = tokio::runtime::Builder::new_multi_thread()
.enable_all()
.build()
.unwrap();
let made = rt
.block_on(svc.new_estate(as_operator(ask("test4-gunnar-rs", "gunnar"))))
.expect("made and ordered")
.into_inner();
assert!(made.created, "{made:?}");
assert_eq!(
(
made.estate.as_str(),
made.domain.as_str(),
made.reference.as_str(),
made.price_words.as_str()
),
(
"test4-gunnar-rs",
"test4.gunnar.rs",
"estate/test4gunnarrs",
"0.50 EUR"
)
);
assert!(
made.checkout_url.starts_with("https://pay.example/"),
"the one payment page: {made:?}"
);
assert!(
made.words.contains("as test2-gunnar-rs's") && made.words.contains("pay 0.50 EUR"),
"{}",
made.words
);
let puts = book.puts.lock().unwrap().clone();
assert_eq!(puts.len(), 1);
let p = &puts[0];
assert_eq!(
(
p.domain.as_str(),
p.vendor.as_str(),
p.first_admin.as_str(),
p.media_from.as_str(),
p.actor.as_str()
),
(
"test4.gunnar.rs",
"holdpay",
"ignalina",
"test2-gunnar-rs",
"console:op-1"
)
);
assert!(
p.create && p.operator_site && p.terminable && p.terms.term_days == 1,
"{p:?}"
);
assert_eq!(
pay.0.requests.lock().unwrap().len(),
1,
"one hold, through the site's own vendor"
);
let o = standing::overview(&state);
assert!(
o.estates.iter().any(|l| l.name == "test4-gunnar-rs"
&& l.standing == "laying"
&& l.domain == "test4.gunnar.rs"),
"{o:#?}"
);
// The same name again: it exists, nothing more is made or held.
let again = rt
.block_on(svc.new_estate(as_operator(ask("test4-gunnar-rs", "gunnar"))))
.unwrap_err();
assert_eq!(again.code(), tonic::Code::AlreadyExists, "{again:?}");
assert_eq!(
(
book.puts.lock().unwrap().len(),
pay.0.requests.lock().unwrap().len()
),
(1, 1)
);
// A declared site is ordered as it is: nothing is made.
let declared = rt
.block_on(svc.new_estate(as_operator(ask("test2-gunnar-rs", "gunnar"))))
.expect("ordered")
.into_inner();
assert!(
!declared.created
&& declared.domain == "test2.gunnar.rs"
&& declared.checkout_url.starts_with("https://"),
"{declared:?}"
);
assert_eq!(
book.puts.lock().unwrap().len(),
1,
"a declared site is not put again"
);
}
/// ★ **OVW-5: the slot never holds the call for a box that takes the site late** (owner rule:
/// a non-trivial ask is a queued jera job, never one long blocking call). The call waited up to
/// 20 s for the box to take a site it added, then said `[new-estate-not-taken-yet]` and the
/// operator pressed again. Now, past a short look, a queued job owns the order: the call answers
/// at once that the estate is made, nothing is held yet, and once the box takes it the job
/// places the ONE site order (its payment page is on the Sites page).
#[test]
fn a_site_the_box_takes_late_is_ordered_by_a_queued_job_never_by_a_held_call() {
let book = Book::default();
book.slow.store(true, std::sync::atomic::Ordering::SeqCst);
let (state, pay) = rig("ovw-late", Some(book.clone()));
let svc = EstatesService(state.clone());
let rt = tokio::runtime::Builder::new_multi_thread()
.enable_all()
.build()
.unwrap();
let t0 = std::time::Instant::now();
let made = rt
.block_on(svc.new_estate(as_operator(ask("test4-gunnar-rs", "gunnar"))))
.expect("made; the order is the queued job's")
.into_inner();
assert!(
t0.elapsed() < std::time::Duration::from_secs(10),
"the call is not held for the box's take: {:?}",
t0.elapsed()
);
assert!(
made.created
&& made.domain == "test4.gunnar.rs"
&& made.checkout_url.is_empty()
&& made.reference.is_empty(),
"{made:?}"
);
assert!(
made.words.contains("Sites page"),
"where its payment page will be: {}",
made.words
);
assert!(
pay.0.requests.lock().unwrap().is_empty(),
"nothing is held before the box took it"
);
// The box takes it: the queued job places the one site order.
let put = book.puts.lock().unwrap()[0].clone();
book.take(&put);
let ordered = rt.block_on(async {
for _ in 0..100 {
if state.estates.get("test4gunnarrs").is_some() {
return true;
}
tokio::time::sleep(std::time::Duration::from_millis(100)).await;
}
false
});
assert!(ordered, "the job ordered it once the box took it");
assert_eq!(
pay.0.requests.lock().unwrap().len(),
1,
"one hold, through the site's own vendor"
);
let o = standing::overview(&state);
assert!(
o.estates
.iter()
.any(|l| l.name == "test4-gunnar-rs" && l.standing == "laying"),
"{o:#?}"
);
}
/// ★ RED: **refused by name, before anything is kept or held**.
#[test]
fn the_slot_refuses_by_name_before_anything_is_kept_or_held() {
let book = Book::default();
let (state, pay) = rig("ovw-refused", Some(book.clone()));
let svc = EstatesService(state.clone());
let rt = tokio::runtime::Builder::new_multi_thread()
.enable_all()
.build()
.unwrap();
let refused =
|r: tonic::Request<pb::NewEstateRequest>| rt.block_on(svc.new_estate(r)).unwrap_err();
// Not the operator: the service bearer, or a site's own bearer beside the marker.
assert_eq!(
refused(tonic::Request::new(ask("test4-gunnar-rs", "gunnar"))).code(),
tonic::Code::PermissionDenied
);
let mut a_site = as_operator(ask("test4-gunnar-rs", "gunnar"));
a_site
.extensions_mut()
.insert(crate::auth::CallerEstate("gunnar-rs".into()));
assert_eq!(refused(a_site).code(), tonic::Code::PermissionDenied);
for (r, code, named) in [
(
ask("Test4", "gunnar"),
tonic::Code::InvalidArgument,
"[new-estate-name]",
),
(
pb::NewEstateRequest {
email: "nobody".into(),
..ask("test4-gunnar-rs", "gunnar")
},
tonic::Code::InvalidArgument,
"[new-estate-email]",
),
(
ask("test4-holger-rs", "holger"),
tonic::Code::InvalidArgument,
"[new-estate-product]",
),
(
ask("gunnar-rs", "holger"),
tonic::Code::InvalidArgument,
"[new-estate-other-product]",
),
(
ask("kunde-se", "gunnar"),
tonic::Code::FailedPrecondition,
"[new-estate-customer-site]",
),
(
ask("kunde", "gunnar"),
tonic::Code::AlreadyExists,
"[new-estate-domain-taken]",
),
] {
let s = refused(as_operator(r));
assert_eq!(s.code(), code, "{named}: {s:?}");
assert!(s.message().contains(named), "{named}: {}", s.message());
}
// An estate that exists is never laid over: one whose boxes call home (as its site stands).
let g = state.fleet.guardian().unwrap();
g.store.declare("old-one", "gunnar").unwrap();
g.store
.record_report("old-one", "main", state.now(), &running("main"))
.unwrap();
let s = refused(as_operator(ask("old-one", "gunnar")));
assert!(
s.code() == tonic::Code::AlreadyExists && s.message().contains("[new-estate-taken]"),
"{s:?}"
);
assert!(
book.puts.lock().unwrap().is_empty() && pay.0.requests.lock().unwrap().is_empty(),
"nothing kept, nothing held"
);
// A box with no site book makes nothing new (a declared site is still ordered).
let (bare, _) = rig("ovw-no-book", None);
let s = rt
.block_on(EstatesService(bare).new_estate(as_operator(ask("test4-gunnar-rs", "gunnar"))))
.unwrap_err();
assert!(
s.code() == tonic::Code::FailedPrecondition && s.message().contains("[new-estate-no-book]"),
"{s:?}"
);
}
/// ★ The Overview over the wire: rows, the quiet line and the slot, behind the console's bearer.
#[test]
fn the_overview_answers_on_the_wire_behind_the_consoles_bearer() {
let (state, _) = rig("ovw-wire", None);
let g = state.fleet.guardian().unwrap();
g.store.declare("gunnar-rs", "gunnar").unwrap();
g.store
.record_report("gunnar-rs", "main", state.now(), &running("main"))
.unwrap();
g.store.declare("acme2", "gunnar").unwrap();
let rt = tokio::runtime::Builder::new_multi_thread()
.enable_all()
.build()
.unwrap();
let o = rt
.block_on(
EstatesService(state).overview(tonic::Request::new(pb::EstatesOverviewRequest {})),
)
.expect("the console reads it")
.into_inner();
assert_eq!(
o.estates
.iter()
.map(|e| (e.name.as_str(), e.standing.as_str()))
.collect::<Vec<_>>(),
[("gunnar-rs", "installed")]
);
assert_eq!(
o.ended.iter().map(|e| e.name.as_str()).collect::<Vec<_>>(),
["acme2"]
);
let slot = o.slot.expect("the slot");
assert_eq!(
(slot.products, slot.declared),
(
vec!["gunnar".to_string()],
vec!["test2-gunnar-rs".to_string()]
)
);
}