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

nordisk/edda

crates/nornir-testmatrix/tests/appliance_boot.rs

//! **The `appliance-boot/<preset>` roster, against the REAL declarations.**
//!
//! `src/appliance.rs` owns the grid; this file is the binding to
//! `nornir-build-thing` (a dev-dependency, for the cycle reason
//! `tests/chain_matrix.rs` records) and proves that the matrix is EMITTED from
//! the one preset roster — `target::presets::PRESETS` — rather than typed out
//! anywhere in this crate.

use nornir_build_thing::target::presets::{Mimic, PresetStatus, PRESETS};
use nornir_testmatrix::appliance::{
    ApplianceBootGrid, BootPreset, BootReach, BootSubstitution, ProofVerdict, APPLIANCE_BOOT_PROOFS,
};
use nornir_testmatrix::functional::functional_row;

/// The ~10-line adapter every caller writes: the roster FROM the code. The
/// library's own `presets::boot_roster()` (behind `--features testmatrix`) is
/// the same lines; this copy keeps the test independent of that feature.
fn roster_from_code() -> Vec<BootPreset> {
    PRESETS
        .iter()
        .map(|p| BootPreset {
            name: p.name.to_string(),
            reach: match p.mimic {
                Mimic::Qemu => BootReach::Kvm,
                Mimic::NeedsRealCloud(why) => BootReach::RealCloud(why.to_string()),
            },
            measured: p.measured.map(|e| e.label()),
            substitutions: p
                .axes()
                .substitutions()
                .into_iter()
                .map(|(facet, missing, with)| BootSubstitution {
                    facet: facet.to_string(),
                    missing: missing.to_string(),
                    with: with.to_string(),
                })
                .collect(),
        })
        .collect()
}

/// One row per preset, reach derived from `Mimic`, and the named gaps are
/// visible holes — never green, never missing.
#[test]
fn every_declared_preset_is_a_row_and_its_reach_follows_mimic() {
    let grid = ApplianceBootGrid::from_rows(roster_from_code(), &[]);
    assert_eq!(grid.presets.len(), PRESETS.len());
    for (row, p) in grid.presets.iter().zip(PRESETS) {
        assert_eq!(row.name, p.name, "roster order is the code's order");
        match (p.status(), &row.reach) {
            (PresetStatus::NeedsRealCloud, BootReach::RealCloud(why)) => {
                assert_eq!(Some(why.as_str()), p.gap());
                assert!(grid.detail(p.name, "install_ok").starts_with("needs real cloud: "), "{}", p.name);
            }
            (PresetStatus::MimicMeasured | PresetStatus::CloudMeasured | PresetStatus::Stub, BootReach::Kvm) => {
                assert!(p.gap().is_none());
            }
            (s, r) => panic!("{}: status {s:?} vs reach {r:?} disagree", p.name),
        }
        for proof in APPLIANCE_BOOT_PROOFS {
            assert_eq!(grid.verdict(p.name, proof), ProofVerdict::Absent, "{}: nothing ran", p.name);
        }
    }
    let rendered = grid.render();
    for p in PRESETS {
        assert!(rendered.contains(p.name), "{}: missing from the wall:\n{rendered}", p.name);
    }
    assert!(rendered.contains("needs real cloud: ENA"), "{rendered}");
    assert!(!grid.kvm_all_green());
}

/// The door's rows land on the code's names: a measured UpCloud B1/B2/B3 turns
/// exactly its row green and no other.
#[test]
fn the_installtest_rows_fold_onto_the_code_roster() {
    let rows: Vec<_> = APPLIANCE_BOOT_PROOFS
        .iter()
        .map(|proof| functional_row("appliance-boot/upcloud", proof, true, "SeaBIOS + -serial none"))
        .collect();
    let grid = ApplianceBootGrid::from_rows(roster_from_code(), &rows);
    for proof in APPLIANCE_BOOT_PROOFS {
        assert_eq!(grid.verdict("upcloud", proof), ProofVerdict::Green);
        assert_eq!(grid.verdict("qemu-local", proof), ProofVerdict::Absent);
    }
    assert_eq!(grid.presets.len(), PRESETS.len(), "no row invented");
    let emitted = grid.rows();
    assert_eq!(emitted.len(), PRESETS.len() * APPLIANCE_BOOT_PROOFS.len());
    assert_eq!(emitted.iter().filter(|r| r.status == "pass").count(), 3);
}

/// **The substitutions reach the grid from the REAL roster** — not a fixture.
///
/// `azure-gen2` presents a Hyper-V synthetic disk and NIC, neither of which
/// QEMU models, so `MimicAxes` says both are stood in for. A `pass` row that
/// does not NAME the swap is refused: the KVM run proved the shape (firmware
/// handoff, boot order, partition scan, root mount) and not the machine, and a
/// row that hides which devices were swapped is the exact silent green this
/// crate exists to refuse.
#[test]
fn a_real_azure_pass_must_name_hv_netvsc_or_it_is_red() {
    let roster = roster_from_code();
    let azure = roster.iter().find(|p| p.name == "azure-gen2").expect("azure-gen2 is on the roster");
    let labels: Vec<String> = azure.substitutions.iter().map(|s| s.label()).collect();
    assert!(
        labels.iter().any(|l| l == "nic: hv-netvsc -> virtio-net-pci"),
        "the roster itself must derive the NIC substitution: {labels:?}"
    );

    // RED: a bare pass.
    let silent = vec![functional_row("appliance-boot/azure-gen2", "install_ok", true, "B1 INSTALL-OK")];
    let grid = ApplianceBootGrid::from_rows(roster_from_code(), &silent);
    assert_eq!(grid.verdict("azure-gen2", "install_ok"), ProofVerdict::Red, "a silent green must not stand");
    assert!(grid.detail("azure-gen2", "install_ok").contains("nic: hv-netvsc -> virtio-net-pci"));

    // GREEN: the same run, reported honestly.
    let honest = vec![functional_row(
        "appliance-boot/azure-gen2",
        "install_ok",
        true,
        &format!("B1 INSTALL-OK (shape only — {})", labels.join("; ")),
    )];
    let grid = ApplianceBootGrid::from_rows(roster_from_code(), &honest);
    assert_eq!(grid.verdict("azure-gen2", "install_ok"), ProofVerdict::Green);
}

/// **The roster's evidence says which KIND it is.** `upcloud` was booted on a
/// real UpCloud instance; `qemu-local-bios` was booted here. Before the split
/// both were the word `measured`, and "3 of 13 measured" read as three clouds.
#[test]
fn the_roster_separates_a_cloud_boot_from_a_rig_run() {
    let cloud: Vec<&str> = PRESETS.iter().filter(|p| p.status() == PresetStatus::CloudMeasured).map(|p| p.name).collect();
    assert_eq!(cloud, vec!["upcloud"]);
    let rig: Vec<&str> = PRESETS.iter().filter(|p| p.status() == PresetStatus::MimicMeasured).map(|p| p.name).collect();
    assert_eq!(rig, vec!["qemu-local", "qemu-local-bios"]);

    // The word travels onto the emitted row, so a warehouse reader never has to
    // guess which kind of evidence a date is.
    let roster = roster_from_code();
    let up = roster.iter().find(|p| p.name == "upcloud").unwrap();
    assert!(up.measured.as_deref().unwrap().starts_with("real cloud: "), "{:?}", up.measured);
    let rig_row = roster.iter().find(|p| p.name == "qemu-local-bios").unwrap();
    assert!(rig_row.measured.as_deref().unwrap().starts_with("qemu rig: "), "{:?}", rig_row.measured);

    // `NeedsRealCloud` keeps its name and meaning — gunnar's installtest gates
    // `--target` on exactly this comparison, and the split must not move it.
    let renderable: Vec<&str> =
        PRESETS.iter().filter(|p| p.status() != PresetStatus::NeedsRealCloud).map(|p| p.name).collect();
    assert_eq!(
        renderable,
        vec!["qemu-local", "qemu-local-bios", "upcloud", "gce-virtio", "hetzner-cloud", "ovh-public-cloud"],
        "the presets gunnar-installtest will still launch"
    );
}