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

nordisk/holger

holger-recipe/tests/open_declaration_without_monetize_impl.rs

//! **Holger's open declaration loads and lists without the commercial checkout.**
//!
//! Holger is open source: its open build must never NEED a monetize-impl checkout.
//! The sold payload's edge `plugin → monetize-impl/holger-guest : wasm` made the
//! shared load refuse the WHOLE declaration in a tree without monetize-impl, so
//! `cargo xtask build --list` died there (L15, 2026-10-18).
//!
//! Each test lays out a sibling tree in a temp dir: `holger` and every sibling of
//! this checkout as symlinks — except `monetize-impl`, which is absent, or a stub
//! donor the test writes itself.

use std::path::{Path, PathBuf};

use holger_recipe::load::{list, load_declaration, refuse_absent_commercial_donor};
use holger_recipe::packaging::{METERED_PAYLOAD_VARIANT, OWN_PLUGIN_REPO, OWN_PLUGIN_ROW};
use nornir_build_thing::suite_cli;

fn holger_root() -> PathBuf {
    Path::new(env!("CARGO_MANIFEST_DIR"))
        .parent()
        .unwrap()
        .to_path_buf()
}

/// A temp sibling tree; `holger` resolved through it. Removed on drop.
struct Tree(PathBuf);

impl Tree {
    fn without_commercial(tag: &str) -> Self {
        let dir =
            std::env::temp_dir().join(format!("holger-open-decl-{tag}-{}", std::process::id()));
        let _ = std::fs::remove_dir_all(&dir);
        std::fs::create_dir_all(&dir).unwrap();
        let parent = holger_root().parent().unwrap().to_path_buf();
        for entry in std::fs::read_dir(&parent).unwrap() {
            let entry = entry.unwrap();
            let name = entry.file_name();
            if name == OWN_PLUGIN_REPO || !entry.path().is_dir() {
                continue;
            }
            std::os::unix::fs::symlink(entry.path(), dir.join(&name)).unwrap();
        }
        assert!(dir.join("holger").is_dir());
        assert!(!dir.join(OWN_PLUGIN_REPO).exists());
        Tree(dir)
    }

    fn holger(&self) -> PathBuf {
        self.0.join("holger")
    }

    /// A stub commercial donor declaring `holger-guest` as the given kind.
    fn with_stub_donor(self, kind: &str) -> Self {
        let nornir = self.0.join(OWN_PLUGIN_REPO).join(".nornir");
        std::fs::create_dir_all(&nornir).unwrap();
        std::fs::write(
            nornir.join("build-variants.toml"),
            format!(
                "[[build.variant]]\nname = \"{OWN_PLUGIN_ROW}\"\nkind = \"{kind}\"\n\
                 target = \"wasm32-unknown-unknown\"\n"
            ),
        )
        .unwrap();
        self
    }
}

impl Drop for Tree {
    fn drop(&mut self) {
        let _ = std::fs::remove_dir_all(&self.0);
    }
}

fn args(argv: &[&str]) -> suite_cli::BuildArgs {
    suite_cli::parse(argv).unwrap()
}

#[test]
fn the_open_declaration_loads_without_monetize_impl() {
    let tree = Tree::without_commercial("load");
    let set = load_declaration(&tree.holger()).unwrap_or_else(|e| panic!("{e:#}"));
    // The sold row and its edge stay in the declaration: lazy, not deleted.
    let edges = set
        .edges_of(METERED_PAYLOAD_VARIANT)
        .expect("the sold row is declared");
    assert!(
        edges.iter().any(|(_, e)| e.repo == OWN_PLUGIN_REPO),
        "{edges:?}"
    );
}

#[test]
fn build_list_runs_without_monetize_impl() {
    let tree = Tree::without_commercial("list");
    // The one delivery lists; it names the sold row beside the open ones.
    let (lines, names) = list(&tree.holger(), &args(&["--list", "--suite", "MVP"]))
        .unwrap_or_else(|e| panic!("{e:#}"));
    assert!(!lines.is_empty());
    assert!(names.iter().any(|n| n == "mvp-server-musl"), "{names:?}");
    assert!(
        names.iter().any(|n| n == METERED_PAYLOAD_VARIANT),
        "{names:?}"
    );
    for p in holger_recipe::variants::PRODUCTS {
        assert!(
            names.iter().any(|n| n == p),
            "the product {p} is listed: {names:?}"
        );
    }
}

#[test]
fn building_the_sold_variant_without_monetize_impl_is_refused_by_name() {
    let tree = Tree::without_commercial("refuse");
    let set = load_declaration(&tree.holger()).unwrap_or_else(|e| panic!("{e:#}"));
    let e = format!(
        "{:#}",
        refuse_absent_commercial_donor(&set, METERED_PAYLOAD_VARIANT, &tree.holger()).unwrap_err()
    );
    assert!(
        e.contains(METERED_PAYLOAD_VARIANT) && e.contains(OWN_PLUGIN_REPO) && e.contains("SOLD"),
        "{e}"
    );
    // Every open variant builds without it.
    for open in [
        "mvp-server-musl",
        "holger",
        "holger-downstream",
        "holger-cli",
    ] {
        refuse_absent_commercial_donor(&set, open, &tree.holger())
            .unwrap_or_else(|e| panic!("{open}: {e:#}"));
    }
}

#[test]
fn with_monetize_impl_present_the_edge_is_type_checked_and_the_sold_variant_builds() {
    let ok = Tree::without_commercial("donor-ok").with_stub_donor("wasm");
    let set = load_declaration(&ok.holger()).unwrap_or_else(|e| panic!("{e:#}"));
    refuse_absent_commercial_donor(&set, METERED_PAYLOAD_VARIANT, &ok.holger()).unwrap();
    // A donor whose row is the wrong typ is still refused at load.
    let bad = Tree::without_commercial("donor-bad").with_stub_donor("exe");
    let e = format!("{:#}", load_declaration(&bad.holger()).unwrap_err());
    assert!(e.contains(OWN_PLUGIN_REPO), "{e}");
}

/// **No server row's container build needs holger-ui** (another checkout): only the estate
/// front's row and the console's own row reach it, so only those rows name it.
#[test]
fn open_rows_mount_no_holger_ui_and_only_the_front_row_names_it() {
    let tree = Tree::without_commercial("siblings");
    let root = tree.holger();
    let set = load_declaration(&root).unwrap_or_else(|e| panic!("{e:#}"));
    let tc = set
        .toolchain
        .clone()
        .expect("holger declares its toolchain");
    assert!(
        !tc.siblings.iter().any(|s| s == "holger-ui"),
        "{:?}",
        tc.siblings
    );
    for open in [
        "plugin-allocation",
        "plugin-skidbladnir",
        "plugin-rust-toolchain",
        "mvp-server-musl",
    ] {
        let v = set.get(open).unwrap();
        assert!(
            !tc.for_variant(v).siblings.iter().any(|s| s == "holger-ui"),
            "{open}"
        );
    }
    let front = set
        .get(holger_recipe::packaging::FRONT_PAYLOAD_VARIANT)
        .unwrap();
    assert!(tc
        .for_variant(front)
        .siblings
        .iter()
        .any(|s| s == "holger-ui"));
    let console = set.get(holger_recipe::variants::HOLGER_UI).unwrap();
    assert!(tc
        .for_variant(console)
        .siblings
        .iter()
        .any(|s| s == "holger-ui"));
}