crates/nornir-depgraph/src/selftest.rs
//! # Functional-status emit bridge — `nornir-depgraph` → test matrix
//!
//! The single internal call site this crate uses to push a *functional* row into
//! the [`nornir_testmatrix`] matrix, so `nornir test --features testmatrix`
//! records whether `nornir-depgraph`'s real persistence surface (the
//! [`DepGraphSnapshot`] ⇄ [`DepGraphRow`] fold — [`to_rows`] / [`group_snapshots`])
//! ACTUALLY round-trips — without eyeballing.
//!
//! ## Release strips everything
//! The `testmatrix` cargo feature gates the whole bridge: with it OFF (the
//! release default) [`emit`] is an `#[inline]` no-op and `nornir-testmatrix` is
//! not even linked. Lit ONLY under `cargo … --features testmatrix`.
//!
//! [`DepGraphSnapshot`]: crate::DepGraphSnapshot
//! [`DepGraphRow`]: crate::DepGraphRow
//! [`to_rows`]: crate::DepGraphSnapshot::to_rows
//! [`group_snapshots`]: crate::group_snapshots
/// The aspect tag every self-emitted row carries (matches `functional_row`).
pub const ASPECT_FUNCTIONAL: &str = "functional";
/// Push ONE functional-status row for a single real check (feature ON).
///
/// * `component` — the unit under test (becomes the row's `suite`).
/// * `check` — the specific assertion's name (becomes the row's `test_name`).
/// * `ok` — the **real** verdict.
/// * `detail` — the **measured** value.
#[cfg(feature = "testmatrix")]
#[inline]
pub fn emit(component: &str, check: &str, ok: bool, detail: &str) {
nornir_testmatrix::functional_status(component, check, ok, detail);
}
/// No-op stub when the `testmatrix` feature is OFF (release builds). Inlined and
/// empty so the call — and, with the wrap-the-call-site pattern, the detail
/// string-building — is stripped entirely.
#[cfg(not(feature = "testmatrix"))]
#[inline]
pub fn emit(_component: &str, _check: &str, _ok: bool, _detail: &str) {}
/// `assert!`-with-emit: assert on the real return value / object state AND record
/// the verdict as a matrix row. The `assert!` is the test's actual gate; the emit
/// is the matrix observation.
#[macro_export]
macro_rules! depgraph_assert_emit {
($component:expr, $check:expr, $ok:expr, $($detail:tt)+) => {{
let __ok: bool = $ok;
let __detail = ::std::format!($($detail)+);
$crate::selftest::emit($component, $check, __ok, &__detail);
::std::assert!(__ok, "{}::{} — {}", $component, $check, __detail);
}};
}
// ─── inject-and-assert wiring test (feature ON only) ─────────────────────────
#[cfg(all(test, feature = "testmatrix"))]
mod wiring {
use crate::{group_snapshots, CrossRepoEdge, DepGraphSnapshot, DepKind};
use chrono::{DateTime, Utc};
use std::collections::BTreeSet;
use uuid::Uuid;
fn via(cs: &[&str]) -> BTreeSet<String> {
cs.iter().map(|s| s.to_string()).collect()
}
/// Exercise the real `DepGraphSnapshot ⇄ DepGraphRow` fold, emit an honest row
/// per surface, then drain the process-global functional buffer and assert the
/// rows landed — proving the emit bridge is wired end to end.
#[test]
fn emits_honest_rows_for_snapshot_persistence_surfaces() {
let ts: DateTime<Utc> =
DateTime::parse_from_rfc3339("2026-07-14T12:00:00Z").unwrap().with_timezone(&Utc);
let original = DepGraphSnapshot {
snapshot_id: Uuid::new_v4(),
workspace_name: "nordisk".into(),
timestamp: ts,
edges: vec![
CrossRepoEdge {
from: "dwarves".into(),
to: "edda".into(),
via: via(&["nornir-service"]),
kind: DepKind::Dev,
},
CrossRepoEdge {
from: "nornir".into(),
to: "edda".into(),
via: via(&["jera", "nornir-git", "saga"]),
kind: DepKind::Normal,
},
],
};
// Real surface #1: the flat fan-out is one row per (edge, via-crate).
let rows = original.to_rows();
depgraph_assert_emit!(
"nornir-depgraph",
"to_rows_fans_out_per_via_crate",
rows.len() == 4,
"rows={}",
rows.len()
);
// Real surface #2 (RED-when-broken): grouping the rows must reconstruct the
// snapshot EXACTLY — a broken fold makes this false and flips the row red.
let regrouped = group_snapshots(rows);
depgraph_assert_emit!(
"nornir-depgraph",
"group_snapshots_round_trips_exactly",
regrouped.len() == 1 && regrouped[0] == original,
"snapshots={}",
regrouped.len()
);
let drained = nornir_testmatrix::drain_functional_rows();
let has = |t: &str| {
drained
.iter()
.any(|r| r.suite == "nornir-depgraph" && r.test_name == t && r.status == "pass")
};
assert!(has("to_rows_fans_out_per_via_crate"), "rows={drained:?}");
assert!(has("group_snapshots_round_trips_exactly"), "rows={drained:?}");
assert!(
drained
.iter()
.filter(|r| r.suite == "nornir-depgraph")
.all(|r| r.aspect == "functional"),
"rows={drained:?}"
);
}
}