Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/monetize

crates/monetize-shop-pairing/src/l18_tests.rs

//! ★ **A shop that sells Gunnar pairs a Holger site as Holger** (lane L18, 2026-10-18): the ONE
//! box's one pairing was built from `[estate_orders] product = "gunnar"` and spoke Gunnar's
//! contract for every run — a Holger site (test3.holger.rs) would have been minted Gunnar's
//! seeds, recorded as Gunnar's variant, sale-checked at Gunnar's doors and its front fed
//! `console_admin_token`, which Holger's front does not read (private-holger-ops 6b2a0f7 feeds
//! `holger_console_token` only). The core hands each run its product's facts (v2.0 P3), and the
//! pairing speaks the contract THEY declare; a request whose product declares none is refused.

use super::*;
#[allow(unused_imports)]
use crate::test_fixtures::*;

fn shop() -> ShopPairing {
    ShopPairing { sale_feed: BTreeMap::new(), budget_s: 600, fleet_late_s: 0, installer_link_psk: true }
}

fn order(apex: &str) -> LaidOrder {
    serde_json::from_value(serde_json::json!({
        "company": "acme", "apex": apex, "domain": "", "names": [format!("acme.{apex}")],
        "estate": {"reference": "estate/acme", "company": "acme", "zone": "se-sto1", "machines": []},
        "first_login_ttl_secs": 604800
    }))
    .unwrap()
}

fn handoff() -> tempfile::TempDir {
    let dir = tempfile::tempdir().unwrap();
    for (n, v) in [("console-admin-token", "aa"), ("estate-client.key", "cc")] {
        std::fs::write(dir.path().join(n), v).unwrap();
    }
    dir
}

#[test]
fn the_estates_own_facts_pick_the_contract() {
    use monetize_server::estate_order::Installer as _;
    use monetize_server::testing::lifecycles::{gunnar_facts, holger_facts};
    let s = shop();
    let names = |f: &[(String, String)]| f.iter().map(|(n, _)| n.clone()).collect::<Vec<_>>();
    let h = s.mint_for(&holger_facts(), "test3holgerrs", "test3.holger.rs").unwrap();
    assert!(names(&h).contains(&"seed.holger.toml".to_string()) && !names(&h).contains(&"seed.gunnar.toml".to_string()), "{:?}", names(&h));
    let g = s.mint_for(&gunnar_facts(), "acme", "acme.gunnar.rs").unwrap();
    assert!(names(&g).contains(&"seed.gunnar.toml".to_string()));
    assert!(s.mint("acme", "acme.gunnar.rs").unwrap_err().contains("[contract-no-kind]"), "no product named: nothing is guessed");
}

#[test]
fn a_holger_front_is_fed_holgers_console_token_key_and_gunnars_keeps_its_own() {
    let dir = handoff();
    let sale = shop().sale_feed;
    let h = front_feed_for(&holger(), &sale, &order("test3.holger.rs"), dir.path()).unwrap();
    assert_eq!(h.get("holger_console_token").map(String::as_str), Some("aa"), "the key Holger's front reads");
    assert!(!h.contains_key("console_admin_token"), "never Gunnar's key on a Holger front");
    assert_eq!(h.get(&holger().free_feed).map(String::as_str), Some("true"));
    assert!(!h.contains_key(&gunnar().free_feed));
    let g = front_feed_for(&gunnar(), &sale, &order("gunnar.rs"), dir.path()).unwrap();
    assert_eq!(g.get("console_admin_token").map(String::as_str), Some("aa"), "Gunnar's unchanged");
    assert!(!g.contains_key("holger_console_token"));
    assert_eq!((gunnar().console_token_feed.as_str(), holger().console_token_feed.as_str()), ("console_admin_token", "holger_console_token"));
}

/// ★ **A request whose product declares no contract is refused by name** (v2.0 P3): the shop
/// guesses no product's contract (it spoke Gunnar's for an empty one once). Nothing is minted,
/// installed or proven for it, and each refusal names the missing fact.
#[test]
fn a_request_whose_product_declares_no_contract_is_refused_by_name() {
    use monetize_server::estate_order::Installer as _;
    let s = shop();
    let bare = monetize_server::facts::Facts { kind: "idun".into(), ..Default::default() };
    let why = s.mint_for(&bare, "acme", "acme.idun.example").unwrap_err();
    assert!(why.contains("idun") && why.contains("[contract-box-kind]"), "{why}");
    let dir = tempfile::tempdir().unwrap();
    let at = monetize_server::estate_order::SaleCheckAt { facts: &bare, company: "acme", host: "acme.idun.example", account: "a", front: None, run_dir: dir.path(), console_token: "t", first_login: "i" };
    assert!(s.sale_check(&at).unwrap_err().contains("REFUSED [contract-"), "no sale is proven by a proof nobody declared");
}

/// ★ The bench's `fleet-feed-late` (`[estate_orders] bench_fleet_late_s`): the plan's shared
/// feed names the pull channel's three keys and the hold; 0 leaves the plan as it was.
#[test]
fn the_bench_fleet_late_knob_names_the_pull_channel_keys_on_the_plan() {
    let vm = |name: &str, last: u8, kind: Kind| nordisk_pairing::installer::PlanVm { name: name.into(), public: std::net::Ipv4Addr::new(127, 0, 0, last), utility: std::net::Ipv4Addr::new(10, 13, 8, last), overlay: nordisk_pairing::OVERLAY_FRONT, kind, feed: BTreeMap::new() };
    let mut plan = Plan { estate: "test3.holger.rs".into(), tunnel: TunnelKind::Wireguard, vms: vec![vm("front", 1, Kind::Front)], feed: BTreeMap::new(), front: None, port: 0, link_port: 0, budget_s: 600, close_when: nordisk_pairing::installer::CloseWhen::Paired, box_cert_valid_s: None, front_waits_for: Vec::new() };
    fleet_late(&mut plan, 0);
    assert!(plan.feed.is_empty(), "off: nothing held");
    fleet_late(&mut plan, 75);
    assert_eq!(plan.feed[nordisk_pairing::installer::LATE_FEED], "fleet,fleet_instance,fleet_at");
    assert_eq!(plan.feed[nordisk_pairing::installer::LATE_FEED_S], "75");
}

/// ★ **Auto-repair is ON for every shop-laid estate unless the site turns it off** (owner
/// 2026-10-12: "a dead main is rebuilt from the twin by autorepair"; lane G11 follow-up). Both
/// fronts fill a re-laid main from its twin only when fed `repair_auto = true` (nordisk-pairing
/// `autofill::FEED_REPAIR_AUTO`), and Gunnar's boxes read the same word: the shop feeds it to the
/// front and to main and twin, Gunnar and Holger alike. A site's `[estate_orders.sale_feed]
/// repair_auto = "false"` keeps it off, everywhere.
#[test]
fn every_shop_laid_estate_is_fed_repair_auto_on_unless_the_site_turns_it_off() {
    let dir = handoff();
    for c in [&gunnar(), &holger()] {
        let front = front_feed_for(c, &shop().sale_feed, &order("acme.example"), dir.path()).unwrap();
        assert_eq!(front.get(REPAIR_AUTO).map(String::as_str), Some("true"), "{}: the front is fed auto-repair on", c.product);
        let boxes = box_feed_for(c, &BTreeMap::new(), BTreeMap::new(), &front);
        assert_eq!(boxes.get(REPAIR_AUTO).map(String::as_str), Some("true"), "{}: main and twin too", c.product);
        let mut off = shop().sale_feed;
        off.insert(REPAIR_AUTO.into(), "false".into());
        let front = front_feed_for(c, &off, &order("acme.example"), dir.path()).unwrap();
        assert_eq!(front.get(REPAIR_AUTO).map(String::as_str), Some("false"), "{}: the site turned it off", c.product);
        let boxes = box_feed_for(c, &BTreeMap::new(), BTreeMap::new(), &front);
        assert_eq!(boxes.get(REPAIR_AUTO).map(String::as_str), Some("false"), "{}: off on the boxes as well", c.product);
    }
    assert_eq!(REPAIR_AUTO, "repair_auto", "the word both fronts and Gunnar's boxes read");
}