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

nordisk/skade

tests/testmatrix_wiring.rs

//! L4 wiring proof for the published `nornir-testmatrix` crate.
//!
//! The whole file is gated on the `testmatrix` feature: `nornir-testmatrix` is
//! an OPTIONAL dependency (linked only under `--features testmatrix`), so a
//! plain `cargo test` must compile this file down to nothing rather than fail
//! on the unresolved `nornir_testmatrix` import. Run the proof with
//! `cargo test --features testmatrix`.
//!
//! This is an INJECT-AND-ASSERT test (project LAW): it feeds canned
//! `TestResultRow`s — varied status / aspect / metric — through the real
//! `JsonFileSink` round-trip and the `summarize_runs` + `render_matrix`
//! renderers, then asserts on the REAL output (counts, surviving fields, the
//! red marker in the grid). It runs fast and fully offline: NO cargo
//! subprocess, no network. It proves skade can build against the crate AND
//! that the crate's core data path works from this repo.

#![cfg(feature = "testmatrix")]

use nornir_testmatrix::{
    JsonFileSink, TestResultRow, TestSink, render_matrix, status, summarize_runs,
};

/// A fixed run's worth of canned rows spanning several aspects, statuses and
/// metric values. `ts_micros` is shared (one run); the run_id groups them.
fn canned_rows() -> Vec<TestResultRow> {
    let run_id = "run-L4-skade-0001";
    let repo = "skade-katalog";
    let ts = 1_700_000_000_000_000_i64;
    let mk = |suite: &str, name: &str, st: &str, aspect: &str, metric: f64, msg: &str| {
        let mut r = TestResultRow::unit(run_id, repo, suite, name, st, 12.5, ts, msg);
        r.aspect = aspect.to_string();
        r.metric = metric;
        r
    };
    vec![
        mk(
            "catalog",
            "commit_table_roundtrip",
            status::PASS,
            "unit",
            0.0,
            "",
        ),
        mk("build", "build", status::PASS, "build", 0.0, ""),
        // a genuinely red case — this MUST surface as ✗ in the matrix.
        mk(
            "clippy",
            "clippy",
            status::FAIL,
            "clippy",
            7.0,
            "7 warnings denied",
        ),
        mk(
            "time_travel",
            "snapshot_skip",
            status::IGNORED,
            "unit",
            0.0,
            "needs fixture",
        ),
        mk("coverage", "coverage", status::PASS, "coverage", 84.3, ""),
    ]
}

#[test]
fn testmatrix_roundtrip_and_render_inject_assert() {
    let rows = canned_rows();

    // ── 1. JsonFileSink round-trip: append then read_all must return the SAME
    //       rows, with aspect + metric surviving serde. ──────────────────────
    let dir = tempfile::tempdir().expect("tempdir");
    let path = dir.path().join("quality-matrix.jsonl");
    let sink = JsonFileSink::new(&path);
    sink.append(&rows).expect("append rows");

    let read_back = sink.read_all().expect("read_all");
    assert_eq!(read_back.len(), rows.len(), "row count must round-trip");
    assert_eq!(
        read_back, rows,
        "rows must round-trip byte-for-byte (incl. aspect+metric)"
    );

    // The clippy row's metric (7 warnings) and aspect must have survived.
    let clippy = read_back
        .iter()
        .find(|r| r.test_name == "clippy")
        .expect("clippy row survives");
    assert_eq!(clippy.aspect, "clippy");
    assert_eq!(clippy.metric, 7.0);
    assert!(status::is_red(&clippy.status), "fail must classify as red");

    let coverage = read_back
        .iter()
        .find(|r| r.aspect == "coverage")
        .expect("coverage row survives");
    assert_eq!(coverage.metric, 84.3, "coverage metric must survive");
    assert!(status::is_green(&coverage.status));

    // ── 2. summarize_runs: exact tallies for the single run. ────────────────
    let summaries = summarize_runs(&read_back);
    assert_eq!(summaries.len(), 1, "exactly one run id");
    let s = &summaries[0];
    assert_eq!(s.passed, 3, "3 pass (unit + build + coverage)");
    assert_eq!(s.failed, 1, "1 fail (clippy)");
    assert_eq!(s.ignored, 1, "1 ignored (snapshot_skip)");
    assert_eq!(s.total(), 5);
    assert!(!s.green(), "a failed run is not green");

    // ── 3. render_matrix: the human grid must contain the red marker AND the
    //       failing aspect/case, plus the repo name. ─────────────────────────
    let grid = render_matrix(&read_back);
    assert!(
        grid.contains('✗'),
        "rendered grid must show a red marker:\n{grid}"
    );
    assert!(
        grid.contains("skade-katalog"),
        "grid names the repo:\n{grid}"
    );
    assert!(
        grid.contains("[clippy]") && grid.contains("clippy::clippy"),
        "grid surfaces the failing clippy case with its aspect:\n{grid}"
    );
    assert!(
        grid.contains("7 warnings denied"),
        "grid carries the failure message:\n{grid}"
    );

    // Feed this wiring test's own real result into the matrix (the engine's
    // functional emitter), gated so release strips it.
    #[cfg(feature = "testmatrix")]
    nornir_testmatrix::functional_status(
        "testmatrix",
        "testmatrix_roundtrip_and_render_inject_assert",
        read_back == rows && s.passed == 3 && s.failed == 1 && grid.contains('✗'),
        &format!(
            "roundtrip {} rows; summary {}p/{}f/{}i; grid shows red marker={}",
            read_back.len(),
            s.passed,
            s.failed,
            s.ignored,
            grid.contains('✗')
        ),
    );
}