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

nordisk/nornir

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"
    );
}