tests/metro_feed.rs
//! **S5b — nornir feeds real `MetroMap`s into facett's `MetroView`.**
//!
//! This is the inject-assert integration proof for the pure producer
//! [`nornir::viz::metro_feed::build_metro_map`]: a small but REALISTIC slice of
//! nornir's own facts (a button's click-handler → an emitter → a core fn → the
//! gRPC handler) + a `surface_coverage` lit overlay + a `fn → table`
//! warehouse-access edge goes IN; a real [`facett_graphview::MetroMap`] comes OUT,
//! and we assert the line lit up exactly as the coverage says (real data in, real
//! map out — never a "didn't panic" smoke test).
//!
//! The producer reuses nornir's own `arch::metro` chain resolution, so this also
//! pins the bridge: nornir `Boundary::Emitter` → facett `StationKind::Emitter`
//! (a gating stop), every other interior fn → `PassThrough` (ridden through), the
//! gRPC handler → `Grpc`, the warehouse table → `Terminus`, and `is_green()`
//! reflects whether every GATING stop's emit fired in the latest run.
#![cfg(feature = "viz")]
use facett_graphview::{MetroView, StationKind};
use facett_jobview::Facet; // == facett_core::Facet (both crates re-export the 0.1 trait)
use nornir::knowledge::symbols::{CallEdgeRow, SymbolRow};
use nornir::viz::metro_feed::build_metro_map;
use nornir_testmatrix::coverage::CoverageRow;
fn sym(module: &str, name: &str, kind: &str, file: &str, line: u32) -> SymbolRow {
SymbolRow {
crate_name: "nornir".into(),
module_path: module.into(),
item_kind: kind.into(),
item_name: name.into(),
visibility: "pub".into(),
file: file.into(),
line,
doc_lines: 0,
signature: None,
}
}
fn call(caller: &str, callee: &str) -> CallEdgeRow {
call_in(caller, callee, "src/x.rs")
}
/// A call edge with an explicit CALLER FILE — the caller-side FORK derivation
/// classifies a verb's callers by file into UI (`src/viz/…`) vs CLI (`src/bin/…`).
fn call_in(caller: &str, callee: &str, file: &str) -> CallEdgeRow {
CallEdgeRow {
crate_name: "nornir".into(),
caller_path: caller.into(),
callee_ident: callee.into(),
call_kind: "call".into(),
file: file.into(),
line: 1,
}
}
fn cov(id: &str, verdict: &str) -> CoverageRow {
CoverageRow {
run_id: "run-1".into(),
workspace: "ws".into(),
surface_key: format!("function:{id}@fat"),
kind: "function".into(),
id: id.into(),
mode: "fat".into(),
verdict: verdict.into(),
reason: String::new(),
ts_micros: 1,
utfallsrum_covered: 0.0,
}
}
/// A realistic `run_release_gate → Ops.RunRelease` slice: the `draw_release_op` UI
/// click-handler fires the RPC client, which reaches the server's
/// `OpsSvc::run_release` gRPC handler, passing through one emitter (`emit_in`)
/// and one plain core fn (`run_release_rpc`) on the way.
fn fixture() -> (Vec<SymbolRow>, Vec<CallEdgeRow>) {
let symbols = vec![
sym(
"nornir::viz::release_tab::ReleaseTabState",
"draw_release_op",
"fn",
"src/viz/release_tab.rs",
207,
),
sym(
"nornir::viz::trace",
"emit_in",
"fn",
"src/viz/trace.rs",
90,
),
sym(
"nornir::viz::remote",
"run_release_rpc",
"fn",
"src/viz/remote.rs",
300,
),
sym(
"nornir_server",
"impl OpsSvcTrait for OpsSvc",
"impl",
"src/bin/nornir-server.rs",
3243,
),
sym(
"nornir_server::OpsSvc",
"run_release",
"fn",
"src/bin/nornir-server.rs",
3244,
),
];
let calls = vec![
call(
"nornir::viz::release_tab::ReleaseTabState::draw_release_op",
"emit_in",
),
call("nornir::viz::trace::emit_in", "run_release_rpc"),
call(
"nornir::viz::remote::run_release_rpc",
"OpsSvc::run_release",
),
];
(symbols, calls)
}
/// THE keystone: real facts + a coverage run lighting every gating stop + a real
/// terminus access edge → a facett `MetroMap` whose `run_release_gate` line is
/// Start + Emitter(lit) + PassThrough + Grpc + Terminus, and is GREEN.
#[test]
fn nornir_feeds_a_green_metro_line_into_facett() {
let (symbols, calls) = fixture();
// The latest surface_coverage run marks the button handler, the emitter, the
// gRPC handler, and the terminus table all COVERED → every gating stop lit.
let coverage = vec![
cov("draw_release_op", "covered"),
cov("nornir::viz::trace::emit_in", "covered"),
cov("run_release", "covered"),
cov("test_matrix_runs", "covered"),
];
// The fn → table warehouse-access edge that resolves the TERMINUS.
let access = vec![(
"OpsSvc::run_release".to_string(),
"test_matrix_runs".to_string(),
)];
let map = build_metro_map(&symbols, &calls, &coverage, &access);
// One line per registered button.
assert_eq!(
map.lines.len(),
nornir::arch::metro::button_registry().len()
);
let line = map
.lines
.iter()
.find(|l| l.id == "run_release_gate→Ops.RunRelease")
.expect("the run_release_gate metro line is present");
// Station kinds, in chain order: Start, Emitter, PassThrough, Grpc, Terminus.
let kinds: Vec<StationKind> = line.stations.iter().map(|s| s.kind).collect();
assert_eq!(
kinds.first(),
Some(&StationKind::Start),
"head station is the button"
);
assert_eq!(
kinds.last(),
Some(&StationKind::Terminus),
"tail station is the warehouse table"
);
assert!(
kinds.contains(&StationKind::Emitter),
"the emit_in emitter is a gating station"
);
assert!(
kinds.contains(&StationKind::PassThrough),
"the core fn is ridden through"
);
assert!(
kinds.contains(&StationKind::Grpc),
"the gRPC handler is the boundary stop"
);
// The emitter is LIT (it was covered) and labelled from the real fn.
let emitter = line
.stations
.iter()
.find(|s| s.kind == StationKind::Emitter)
.unwrap();
assert_eq!(emitter.label, "emit_in");
assert!(emitter.lit, "the covered emitter lit up");
// The terminus resolved to the REAL table from the access edge (not a placeholder).
let terminus = line.stations.last().unwrap();
assert_eq!(
terminus.label, "test_matrix_runs",
"terminus from the fn→table access edge"
);
assert!(
!terminus.id.starts_with("table?::"),
"a resolved, not placeholder, terminus"
);
// Every gating stop lit ⇒ the line is GREEN, and the overall map green-count
// includes it.
assert!(
line.is_green(),
"fully-covered resolved chain is green: {line:?}"
);
assert!(
map.green_count() >= 1,
"at least the run_release_gate line is green"
);
}
/// SENSITIVITY (real coverage gap → real red): drop the emitter's coverage and the
/// SAME line goes red, with `emit_in` named as the unlit gating reason.
#[test]
fn an_uncovered_emitter_turns_the_line_red() {
let (symbols, calls) = fixture();
let coverage = vec![
cov("draw_release_op", "covered"),
// emit_in deliberately NOT covered.
cov("run_release", "covered"),
cov("test_matrix_runs", "covered"),
];
let access = vec![(
"OpsSvc::run_release".to_string(),
"test_matrix_runs".to_string(),
)];
let map = build_metro_map(&symbols, &calls, &coverage, &access);
let line = map
.lines
.iter()
.find(|l| l.id == "run_release_gate→Ops.RunRelease")
.unwrap();
assert!(!line.is_green(), "an unlit emitter keeps the line red");
let unlit: Vec<&str> = line.unlit().iter().map(|s| s.label.as_str()).collect();
assert!(
unlit.contains(&"emit_in"),
"emit_in is the unlit gating reason: {unlit:?}"
);
}
/// The cross-crate (bin→lib) gap: with no call edges the chain can't resolve to its
/// gRPC handler, so nornir emits the honest Start → (unresolved) → Grpc → Terminus
/// skeleton — never a fabricated interior, never a false green.
#[test]
fn unresolved_chain_yields_an_honest_skeleton() {
let (symbols, _) = fixture();
let map = build_metro_map(&symbols, &[], &[], &[]);
let line = map
.lines
.iter()
.find(|l| l.id == "run_release_gate→Ops.RunRelease")
.unwrap();
assert!(
line.stations
.iter()
.any(|s| s.id.starts_with("unresolved::")),
"honest gap marker"
);
assert_eq!(line.stations.first().unwrap().kind, StationKind::Start);
assert!(line.stations.iter().any(|s| s.kind == StationKind::Grpc));
assert_eq!(line.stations.last().unwrap().kind, StationKind::Terminus);
assert!(!line.is_green(), "an unproven skeleton is never green");
}
/// **Caller-side FORKS — through the builder, asserted via `state_json` (LAW 6).**
/// A gRPC verb with KNOWN UI (`src/viz`) + CLI (`src/bin/nornir.rs`) callers builds
/// a forked `MetroMap`; fed into the reusable `MetroView`, its `state_json` carries
/// the branch topology + per-arm UI/CLI markers off the gRPC station. The verb is
/// covered so both arms light. Registers the fork surface in the test matrix.
#[test]
fn nornir_builder_forks_the_grpc_verb_to_ui_and_cli_arms() {
let (symbols, mut calls) = fixture();
// A UI viz caller and a CLI binary caller both fire the verb's stub method.
calls.push(call_in(
"nornir::viz::remote::run_release",
"run_release",
"src/viz/remote.rs",
));
calls.push(call_in(
"nornir::run_release_remote",
"run_release",
"src/bin/nornir.rs",
));
let coverage = vec![cov("run_release", "covered")];
let map = build_metro_map(&symbols, &calls, &coverage, &[]);
// Feed the reusable MetroView and assert the FORK on its state_json DATA.
let mut view = MetroView::new("🚇 Metro");
view.set_map(map);
let sj = view.state_json();
let lines = sj["line"].as_array().expect("line array");
let line = lines
.iter()
.find(|l| l["id"] == "run_release_gate→Ops.RunRelease")
.expect("the run_release_gate line is in state_json");
let grpc = line["stations"]
.as_array()
.unwrap()
.iter()
.find(|s| s["kind"] == "grpc")
.expect("a grpc station");
let arms = grpc["branches"]
.as_array()
.expect("the gRPC stop carries caller arms");
let two_marked = arms.len() == 2;
let markers: Vec<&str> = arms.iter().map(|b| b["marker"].as_str().unwrap()).collect();
let both_clients = markers.contains(&"UI") && markers.contains(&"CLI");
let both_lit = arms.iter().all(|b| b["lit"].as_bool().unwrap());
nornir_testmatrix::functional_status(
"viz-metro-forks",
"grpc_verb_forks_to_ui_and_cli",
two_marked && both_clients && both_lit,
&format!(
"arms={} markers={markers:?} both_lit={both_lit}",
arms.len()
),
);
assert!(two_marked, "called by BOTH ui+cli → two arms: {arms:?}");
assert!(both_clients, "UI + CLI markers present: {markers:?}");
assert!(
both_lit,
"the covered verb lights both client arms: {arms:?}"
);
assert_eq!(
arms.iter().find(|b| b["marker"] == "UI").unwrap()["kind"],
"ui_client",
"the UI arm is a ui_client kind"
);
assert_eq!(
arms.iter().find(|b| b["marker"] == "CLI").unwrap()["kind"],
"cli_client",
"the CLI arm is a cli_client kind"
);
}
/// SENSITIVITY: a verb called by ONLY the CLI renders exactly ONE CLI arm in
/// `state_json` (no UI arm), and with no coverage it is present-but-unlit.
#[test]
fn nornir_builder_renders_a_single_cli_arm_when_only_cli_calls() {
let (symbols, mut calls) = fixture();
calls.push(call_in(
"nornir::run_release_remote",
"run_release",
"src/bin/nornir.rs",
));
let map = build_metro_map(&symbols, &calls, &[], &[]); // no coverage
let mut view = MetroView::new("🚇 Metro");
view.set_map(map);
let sj = view.state_json();
let line = sj["line"]
.as_array()
.unwrap()
.iter()
.find(|l| l["id"] == "run_release_gate→Ops.RunRelease")
.unwrap()
.clone();
let grpc = line["stations"]
.as_array()
.unwrap()
.iter()
.find(|s| s["kind"] == "grpc")
.unwrap()
.clone();
let arms = grpc["branches"].as_array().unwrap();
let one_cli = arms.len() == 1 && arms[0]["marker"] == "CLI";
nornir_testmatrix::functional_status(
"viz-metro-forks",
"cli_only_verb_renders_one_arm",
one_cli && !arms[0]["lit"].as_bool().unwrap(),
&format!("arms={} marker={}", arms.len(), arms[0]["marker"]),
);
assert!(
one_cli,
"only the CLI calls it → a single CLI arm: {arms:?}"
);
assert_eq!(arms[0]["kind"], "cli_client");
assert!(
!arms[0]["lit"].as_bool().unwrap(),
"no coverage → the CLI arm is unlit"
);
}