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

nordisk/holger

estate-tests/tests/mirror_of_monetizes_pull_holger.rs

//! ★ **The mirror image of monetize's `crates/monetize-server/tests/pull_holger.rs`**: there
//! the ONE box records a holger main's report and queues its orders; here a holger box (this
//! crate's Puller) REPORTS into that same server state, PULLS what holger's real plugin
//! queued (`push_entitlement`, `purge_tenant`), runs each and acks it — and holger's own
//! guardian reads the health words the box sent.

use std::cell::RefCell;
use std::collections::BTreeMap;
use std::sync::Arc;

use holger_fleet::exec::{Applied, HolgerBox};
use holger_fleet::{Addressee, BoxKey, Fault, Link, Puller, Signed};
use monetize_embed::fleet::SignedOrder;
use monetize_embed::signing::base64_encode;
use monetize_guardian::{FleetRefusal, Guardian};
use monetize_product::guardian::{role, BoxView, EstateView, Remedy};
use monetize_product::pull::{GrowRoom, ProductReport, PurgeAnswer, PurgeTenant};
use monetize_product::*;
use monetize_server::config::Config;
use monetize_server::registry::{Linked, Registry};
use monetize_server::state::AppState;

const ESTATE: &str = "holger-rs";
const SEED: [u8; 32] = [11u8; 32];

fn now_ms() -> u64 {
    holger_fleet::now_unix_ms()
}

/// monetize-server's `Fleet` service (`admit` + `report`/`orders`/`ask`), minus tonic.
struct OneBox(Arc<Guardian>);

fn refusal(r: FleetRefusal) -> Fault {
    Fault::new(
        if matches!(r, FleetRefusal::Unauthenticated) {
            "unauthenticated"
        } else {
            "refused"
        },
        r.to_string(),
    )
}

impl Link for OneBox {
    fn report(&mut self, s: Signed) -> Result<u64, Fault> {
        if !s.box_key.is_empty() {
            self.0
                .first_call(&s.call, &s.signature, &s.box_key, now_ms())
                .map_err(refusal)?;
        }
        self.0
            .report(&s.call, &s.signature, now_ms())
            .map_err(refusal)?;
        Ok(30_000)
    }
    fn orders(&mut self, s: Signed) -> Result<Vec<SignedOrder>, Fault> {
        self.0
            .orders(&s.call, &s.signature, now_ms())
            .map(|(o, _)| o)
            .map_err(refusal)
    }
    fn ask(&mut self, s: Signed) -> Result<holger_fleet::Asked, Fault> {
        self.0
            .ask(&s.call, &s.signature, now_ms())
            .map(|a| holger_fleet::Asked {
                case_id: a.case_id,
                words: a.words,
                url: String::new(),
            })
            .map_err(refusal)
    }
}

/// A fresh holger main, as its Fleet client reports it.
#[derive(Default)]
struct FreshMain {
    facts: RefCell<BTreeMap<String, EntitlementFact>>,
    purged: RefCell<Vec<String>>,
}

impl HolgerBox for FreshMain {
    fn serving(&self) -> bool {
        true
    }
    fn health(&self) -> BTreeMap<String, String> {
        [
            ("serving", "no"),
            ("data", "fresh"),
            ("serves_at", "10.6.0.10:50051"),
            ("twin", "paired"),
        ]
        .iter()
        .map(|(k, v)| (k.to_string(), v.to_string()))
        .collect()
    }
    fn product_report(&self) -> Option<String> {
        let now = now_ms();
        let pr = ProductReport {
            tenants: vec![
                TenantOwner {
                    tenant: TenantId("crates".into()),
                    person: false,
                    seller: false,
                },
                TenantOwner {
                    tenant: TenantId("bundles".into()),
                    person: false,
                    seller: false,
                },
            ],
            usage: [
                (
                    "crates".to_string(),
                    Usage {
                        meters: [("disk_bytes".to_string(), 4_096)].into(),
                        measured_at_unix_ms: now,
                    },
                ),
                (
                    "bundles".to_string(),
                    Usage {
                        meters: [("disk_bytes".to_string(), 8_192)].into(),
                        measured_at_unix_ms: now,
                    },
                ),
            ]
            .into(),
            metered: Some(MeteredDoor::Enforcing(
                "holger: a metered build, said by the box itself".into(),
            )),
            names: vec!["crates".into(), "bundles".into()],
            measured_unix_ms: now,
            ..Default::default()
        };
        serde_json::to_string(&pr).ok()
    }
    fn entitle(&self, fact: &EntitlementFact) -> Result<Applied, String> {
        self.facts
            .borrow_mut()
            .insert(fact.tenant.0.clone(), fact.clone());
        Ok(Applied::New(format!(
            "{} is {:?}",
            fact.tenant.0, fact.state
        )))
    }
    fn purge(&self, p: &PurgeTenant) -> Result<PurgeAnswer, String> {
        self.purged.borrow_mut().push(p.tenant.clone());
        Ok(PurgeAnswer {
            job: format!("holger-purge:{}", p.tenant),
            bytes_reclaimed: Some(8_192),
            ..Default::default()
        })
    }
    fn want_room(&self, _: &GrowRoom) -> Result<String, String> {
        Ok("kept".into())
    }
}

#[test]
fn a_holger_main_reports_into_the_one_box_pulls_its_plugins_orders_and_its_guardian_reads_it() {
    let key = base64_encode(
        ed25519_dalek::SigningKey::from_bytes(&SEED)
            .verifying_key()
            .as_bytes(),
    );
    let cfg = Config::from_toml(&format!("[products.holger]\nfree = true\ninstance = \"{ESTATE}\"\nfleet_keys = {{ main = \"{key}\" }}\n")).unwrap();
    let mut linked = Linked::open();
    linked.product(monetize_server::testing::products::HOLGER_FACTORY);
    let reg = Registry::from_config_with(&cfg, &linked).unwrap();
    let state = AppState::in_memory(reg);
    monetize_server::fleet::declare_pulled(&state, &cfg).unwrap();
    let g = Arc::new(
        state
            .fleet
            .guardian()
            .expect("the in-memory guardian")
            .clone(),
    );
    let order_key = state.keys.product("holger").public_key();

    let me = Addressee {
        product: "holger".into(),
        instance: ESTATE.into(),
        role: role::MAIN.into(),
    };
    let mut puller = Puller::new(me, BoxKey::from_seed(SEED), "holger-test");
    let mut link = OneBox(Arc::clone(&g));
    let b = FreshMain::default();

    // The box reports: the ONE box answers holger's product from it, never dialling.
    puller
        .report(&mut link, b.health(), b.product_report(), None, now_ms())
        .expect("the registered key is heard");
    let p = state
        .registry
        .products()
        .find(|p| p.id() == "holger")
        .expect("served");
    assert_eq!(
        p.list_tenants().unwrap(),
        vec![TenantId("crates".into()), TenantId("bundles".into())]
    );
    assert_eq!(
        p.read_usage(&TenantId("crates".into())).unwrap().meters["disk_bytes"],
        4_096
    );
    assert_eq!(p.metered_door().name(), "enforcing");

    // Holger's plugin queues an entitlement and a purge; the box pulls, verifies, runs, acks.
    let fact = state.keys.product("holger").sign_fact(EntitlementFact {
        tenant: TenantId("crates".into()),
        plan: "holger/crates/10gb-1m".into(),
        state: State::Paid,
        paid_until_unix_ms: None,
        caps: [("disk_bytes".to_string(), 10 << 30)].into(),
        source: "test".into(),
        signature: Vec::new(),
        issued_unix_ms: Some(now_ms()),
        issued_signature: Vec::new(),
    });
    p.push_entitlement(&fact).expect("queued, not dialled");
    p.purge_tenant(&TenantId("bundles".into()), "nonpay day 30")
        .expect("queued, not dialled");
    let pulled = puller
        .pull(
            &mut link,
            &holger_fleet::Pumped(&b),
            Some(&order_key),
            0,
            now_ms(),
        )
        .expect("orders");
    assert!(
        pulled.forged.is_empty(),
        "the orders verify under holger's product key: {pulled:?}"
    );
    assert_eq!(
        pulled.acks.iter().map(|a| a.ok).collect::<Vec<_>>(),
        [true, true],
        "{pulled:?}"
    );
    assert!(b.facts.borrow().contains_key("crates"));
    assert_eq!(b.purged.borrow().as_slice(), ["bundles"]);
    puller
        .report(&mut link, b.health(), b.product_report(), None, now_ms())
        .unwrap();
    assert!(
        g.store.orders_for(ESTATE, role::MAIN, 0).is_empty(),
        "the acks took the orders off the queue"
    );

    // Holger's guardian reads the words the box reported: a fresh (held) main with a whole twin
    // is no case of its own (Gunnar's rule, W3 parity) — a person may press Recharge from twin,
    // and the plan recharges the held main with no fence first.
    let rec = g
        .store
        .box_record(ESTATE, role::MAIN)
        .expect("the main's report is kept");
    let twin = BoxView {
        role: "twin".into(),
        heard_unix_ms: now_ms(),
        health: [("primary", "live"), ("complete", "yes")]
            .iter()
            .map(|(k, v)| (k.to_string(), v.to_string()))
            .collect(),
        ..Default::default()
    };
    let main = BoxView {
        role: "main".into(),
        heard_unix_ms: rec.heard_unix_ms,
        health: rec.report.health.clone(),
        ..Default::default()
    };
    let v = EstateView {
        product: "holger".into(),
        instance: ESTATE.into(),
        now_unix_ms: now_ms(),
        silent_after_ms: 90_000,
        boxes: [("main".to_string(), main), ("twin".to_string(), twin)]
            .into_iter()
            .collect(),
    };
    let guardian = p.guardian().expect("holger's guardian");
    assert!(
        guardian.diagnose(&v).is_empty(),
        "a held main is the rebuild plan's box, no finding of its own"
    );
    let steps = guardian
        .plan(Remedy::RechargeFromTwin, &v)
        .expect("a pressed recharge is planned");
    assert!(
        matches!(&steps[0], monetize_product::guardian::Step::Order { kind, .. } if kind == "recharge_from_twin"),
        "{steps:?}"
    );
}