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/medium_kernel.rs

//! **Every holger medium asks its kernel for what pairing needs.**
//!
//! MEASURED on the mock 2026-09-28: a donor kernel built for the appliance-boot
//! contract alone carried `# CONFIG_TUN is not set`, and the installed box answered
//! `wg-installer: open /dev/net/tun … No such device (os error 19)` — it waited for
//! an installer it could never hear. The requirement is declared on the installer
//! row (`[[build.installer.requires]]`, edge `kernel`), so the donor is built with it
//! and the why-index names holger as the one who asked.

use holger_recipe::packaging::{front_installer_metered, installer, metered_installer};
use nornir_build_thing::requires::Requirement;

#[test]
fn every_holger_installer_requires_tun_and_inet_of_its_kernel() {
    for m in [installer(), metered_installer(), front_installer_metered()] {
        assert!(
            m.kernel_donor.is_some(),
            "{} names its kernel donor",
            m.name
        );
        for want in ["CONFIG_NET", "CONFIG_INET", "CONFIG_TUN"] {
            let found = m.requires.iter().any(|r| {
                r.edge == "kernel" && matches!(&r.what, Requirement::Kconfig(k) if k.symbol == want)
            });
            assert!(
                found,
                "{} does not require {want} of its kernel: {:?}",
                m.name, m.requires
            );
        }
    }
}

#[test]
fn the_emitted_toml_carries_the_requirement() {
    let toml = holger_recipe::emitted_toml().expect("the recipe emits");
    assert!(
        toml.matches("symbol = \"CONFIG_TUN\"").count() >= 3,
        "every installer row asks for CONFIG_TUN"
    );
}

/// The holger boxes keep their data on the estate's data volume as xfs, with
/// holger's data root there. The front lays xfs too: one donor kernel, one
/// requirement fragment for every holger medium.
#[test]
fn the_holger_boxes_lay_data_as_xfs_with_holger_data_on_it() {
    use nornir_build_thing::data::DataFs;
    for m in [installer(), metered_installer()] {
        assert_eq!(m.data.fs, DataFs::Xfs, "{}", m.name);
        assert_eq!(
            m.env.get("HOLGER_DATA").map(String::as_str),
            Some("/data/holger"),
            "{}",
            m.name
        );
    }
    assert_eq!(
        front_installer_metered().data,
        installer().data,
        "one donor kernel: every medium asks it the same"
    );
    assert_eq!(front_installer_metered().requires, installer().requires);
}

/// ★ Gunnar 35290f29 / b247bf64 (2026-09-15), shared by lane G10: **every installed holger
/// medium demands PCI hot-plug of its kernel.** UpCloud resizes only DETACHED volumes, so a
/// runtime grow is detach → resize → re-attach, and a kernel with `# CONFIG_HOTPLUG_PCI is
/// not set` answers 511 HOTPLUG_FAILED. The rows are edda's `kernel_requires::hotplug_requires`
/// (moved out of gunnar-recipe), one list for both products. Not on the live medium: its
/// `/data` is RAM.
#[test]
fn every_installed_holger_medium_requires_pci_hotplug_of_its_kernel() {
    let want: Vec<String> = nornir_build_thing::kernel_requires::hotplug_requires()
        .iter()
        .filter_map(|r| match &r.what {
            Requirement::Kconfig(k) => Some(k.symbol.clone()),
            _ => None,
        })
        .collect();
    assert!(want.iter().any(|s| s == "CONFIG_HOTPLUG_PCI"));
    for m in [installer(), metered_installer(), front_installer_metered()] {
        for s in &want {
            let found = m.requires.iter().any(|r| {
                r.edge == "kernel" && matches!(&r.what, Requirement::Kconfig(k) if &k.symbol == s)
            });
            assert!(found, "{} does not require {s} of its kernel", m.name);
        }
    }
    let toml = holger_recipe::emitted_toml().expect("the recipe emits");
    assert!(
        toml.matches("symbol = \"CONFIG_HOTPLUG_PCI\"").count() >= 3,
        "every installer row asks for CONFIG_HOTPLUG_PCI"
    );
}