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

//! **Step-0 proof — functional-row landing across the test subprocess.**
//!
//! A leaf repo's [`functional_status`](nornir_testmatrix::functional_status) emit
//! happens INSIDE its `cargo test --features testmatrix` child process, whose
//! process-global buffer dies on exit. This test proves the fix: the matrix
//! runner points that child at a `NORNIR_TESTMATRIX_OUT` JSONL sink, reads the
//! rows back ([`MatrixRun::functional_rows`]), and the aspect engine folds them
//! into the `Aspect::Functional` drain — so the leaf's RED self-report lands as a
//! RED matrix row in the PARENT.
//!
//! RED-when-broken / GREEN-when-fixed: before the runner.rs + aspect.rs fix the
//! parent collected NOTHING from the subprocess and both assertions below fail.
//!
//! Gated on `testmatrix` (run with `--features testmatrix`) because it drives the
//! real recorder + the feature-ON aspect drain.
#![cfg(feature = "testmatrix")]

use std::path::PathBuf;

use nornir_testmatrix::{
    detect_runner, drain_functional_rows, run_full_matrix, run_matrix, status, Aspect,
};

/// The standalone leaf fixture crate (its own `[workspace]` + target dir).
fn fixture_dir() -> PathBuf {
    PathBuf::from(env!("CARGO_MANIFEST_DIR"))
        .join("tests")
        .join("fixtures")
        .join("leaf_emitter")
}

#[test]
fn leaf_functional_status_lands_as_red_matrix_row_through_the_subprocess() {
    let dir = fixture_dir();

    // Build the fixture into a roomy tmpfs target dir, NOT the parent's
    // CARGO_TARGET_DIR — sharing it would contend on the build lock with the
    // outer `cargo test` and pile artifacts onto a possibly near-full project
    // disk. `CARGO_TARGET_DIR` (env) takes precedence over any `.cargo/config`,
    // and the child inherits this process's env. This is the only test in this
    // binary, so the env write is single-threaded.
    let tmp_target = std::env::temp_dir().join("nornir-testmatrix-fixture-target");
    let saved = std::env::var_os("CARGO_TARGET_DIR");
    // SAFETY: single test in this binary ⇒ no concurrent env access.
    unsafe { std::env::set_var("CARGO_TARGET_DIR", &tmp_target) };

    // ── 1. runner.rs: the child's emit is read back into MatrixRun ──────────
    let run = run_matrix(&dir, detect_runner()).expect("the fixture matrix runs");
    let frows: Vec<_> = run
        .functional_rows
        .iter()
        .filter(|r| r.test_name == "subprocess_render")
        .collect();
    assert_eq!(
        frows.len(),
        1,
        "run_matrix reads the subprocess functional sink back (got cases={:?}, functional_rows={:?})",
        run.cases,
        run.functional_rows,
    );
    assert_eq!(frows[0].status, status::FAIL, "the leaf reported ok=false → RED");
    assert!(status::is_red(&frows[0].status));
    assert_eq!(frows[0].suite, "leaf-emitter", "component → suite");
    assert_eq!(
        frows[0].repo, "leaf_emitter",
        "stamped with NORNIR_TESTMATRIX_REPO (the repo dir name)"
    );
    assert_eq!(frows[0].message, "blank framebuffer from a leaf subprocess");

    // ── 2. aspect.rs end-to-end: run_full_matrix([Unit, Functional]) ────────
    // Unit spawns the child + folds its functional rows into the buffer;
    // Functional drains them into the matrix. Clear the buffer first so the only
    // functional rows are the fixture's.
    let _ = drain_functional_rows();
    let rows = run_full_matrix(&dir, &[Aspect::Unit, Aspect::Functional]);
    let red: Vec<_> = rows
        .iter()
        .filter(|r| r.aspect == "functional" && r.test_name == "subprocess_render")
        .collect();
    assert_eq!(
        red.len(),
        1,
        "the leaf's functional self-report is one RED functional matrix row (rows={rows:?})",
    );
    assert_eq!(red[0].status, status::FAIL);
    assert!(status::is_red(&red[0].status), "matrix reads it as RED");
    assert_eq!(red[0].suite, "leaf-emitter");
    assert_eq!(red[0].message, "blank framebuffer from a leaf subprocess");

    // Restore the parent's CARGO_TARGET_DIR.
    // SAFETY: single test in this binary ⇒ no concurrent env access.
    unsafe {
        match saved {
            Some(v) => std::env::set_var("CARGO_TARGET_DIR", v),
            None => std::env::remove_var("CARGO_TARGET_DIR"),
        }
    }
}