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

nordisk/holger

server/dev-narrate/src/udp_tests.rs

//! **A DEV Holger box narrates over UDP, to the installer's ear** (owner 2026-10-19: Holger's
//! test media are DEV builds, debug logs visible, exactly like Gunnar's).
//!
//! Holger's own start (this crate's [`crate::start_at`], as it runs in the box) over a real UDP
//! socket on loopback, and the installer's side as the installer runs it: Skidbladnir
//! `nordisk_narrate::receiver`, holding the private key whose public half the seed names. The
//! box's medium is a ONE-box medium: its seed starts as the metadata marker and becomes the
//! shop's seed a moment later, which is the case `boxside` alone stays OFF for.
//!
//! The release half (no sender in a release build) is read off the symbol table in
//! holger-recipe `tests/dev_narrate_symbols.rs`.

use crate as dev_narrate;
use nordisk_narrate::receiver::{self, Target};
use nordisk_narrate::{seedkey, wire};
use nordisk_pairing::bootlog::BootLog;
use std::sync::{Arc, Mutex};
use std::time::{Duration, Instant};

static LOG: BootLog = BootLog::new(1000);

fn wait_for(what: &str, budget: Duration, mut ok: impl FnMut() -> bool) {
    let t0 = Instant::now();
    while !ok() {
        assert!(t0.elapsed() < budget, "timed out waiting for {what}");
        std::thread::sleep(Duration::from_millis(50));
    }
}

#[test]
fn a_dev_box_streams_its_boot_log_sealed_to_the_installer_once_its_metadata_seed_lands() {
    let installer = wire::generate();
    let root = std::env::temp_dir().join(format!("holger-dev-narrate-udp-{}", std::process::id()));
    let _ = std::fs::remove_dir_all(&root);
    std::fs::create_dir_all(root.join("pairing")).unwrap();
    let seed = root.join(seedkey::SEED_REL);
    // A ONE-box medium: the marker first, the shop's seed (off the metadata) a moment later.
    std::fs::write(&seed, "nordisk-pairing-seed-from = \"upcloud-metadata\"\n").unwrap();
    let real = format!("estate = \"test3.holger.rs\"\nkind = \"holger\"\n[installer_link]\ninstaller_pubkey = \"{}\"\nvm_private = \"broken\"\n", seedkey::b64_of_key(installer.public_key().as_bytes()));
    let writer = {
        let seed = seed.clone();
        std::thread::spawn(move || {
            std::thread::sleep(Duration::from_millis(600));
            std::fs::write(&seed, real).unwrap();
        })
    };
    LOG.push("korp-start: STAGE exec holger-mvp-metered");
    LOG.push(&dev_narrate::stage_line(
        "pairing",
        "the seed is read and the installer's listener serves",
    ));
    let at = dev_narrate::start_at(
        &LOG,
        &root,
        "holger-server",
        "127.0.0.1:0".parse().unwrap(),
        Duration::from_secs(10),
    )
    .expect("the sender starts once the marker is the shop's seed");
    writer.join().unwrap();

    let out = root.join("main.narrate.log");
    let heard = Arc::new(Mutex::new(Vec::<String>::new()));
    let h = heard.clone();
    let rx = receiver::start(
        installer.to_bytes(),
        vec![Target {
            name: "main".into(),
            addr: at,
            out: out.clone(),
        }],
        Box::new(move |vm, line| h.lock().unwrap().push(format!("{vm}|{line}"))),
    )
    .unwrap();
    wait_for("the buffered lines", Duration::from_secs(10), || {
        heard
            .lock()
            .unwrap()
            .iter()
            .any(|l| l.contains("STAGE pairing"))
    });
    // Live: a certify step said after the hello arrives too.
    LOG.push("front: certifying the twin — STAGE certify asked");
    wait_for("the live line", Duration::from_secs(10), || {
        heard
            .lock()
            .unwrap()
            .iter()
            .any(|l| l.contains("STAGE certify"))
    });
    let seen = rx.stop();
    let text = std::fs::read_to_string(&out).unwrap();
    assert!(
        text.contains("korp-start: STAGE exec")
            && text.contains("STAGE pairing")
            && text.contains("STAGE certify"),
        "{text}"
    );
    assert!(
        text.lines().next().unwrap().contains("holger-server"),
        "the stream says whose it is:\n{text}"
    );
    assert_eq!(seen["main"].forged, 0);
    let _ = std::fs::remove_dir_all(&root);
}

#[test]
fn a_marker_that_never_becomes_a_seed_narrates_nothing_and_says_why() {
    let root =
        std::env::temp_dir().join(format!("holger-dev-narrate-marker-{}", std::process::id()));
    let _ = std::fs::remove_dir_all(&root);
    std::fs::create_dir_all(root.join("pairing")).unwrap();
    std::fs::write(
        root.join(seedkey::SEED_REL),
        "nordisk-pairing-seed-from = \"upcloud-metadata\"\n",
    )
    .unwrap();
    let e = dev_narrate::start_at(
        &LOG,
        &root,
        "holger-estate-front",
        "127.0.0.1:0".parse().unwrap(),
        Duration::from_millis(300),
    )
    .unwrap_err();
    assert!(e.contains("still the metadata marker"), "{e}");
    let _ = std::fs::remove_dir_all(&root);
}