dwarves-gui/tests/robot_error_codes.rs
//! **ROBOT-UI (LAW): dwarves' non-UI errors carry a STABLE CODE on every channel.**
//!
//! The companion to the registry's own unit guards (`dwarves::errcode::tests` — uniqueness,
//! well-formedness, and the WIRING guard that fails if a `wired` row is not actually
//! raised in its declared file). Those prove the CATALOG is honest. This file proves the
//! codes actually reach the surfaces a consumer reads, driven through the SHIPPED
//! host-only shell (`build_native_app`) and the REAL warehouse proxy:
//!
//! 1. [`the_build_thing_scene_refuses_by_name_through_the_shipped_shell`] — an EMPTY
//! constellation through the shell makes the ⚒ scene REFUSE by name (what was asked
//! for, and the root it searched), with no half-built matrix left behind. A populated
//! constellation resolves — so the refusal is a real signal, not a constant.
//! 2. [`a_dead_upstream_puts_the_proxy_code_on_the_grpc_status_and_the_wire`] — the REAL
//! dwarves warehouse proxy fronting a DEAD upstream answers a `Warehouse.Scan` with a
//! gRPC `Status` whose message carries `dwarves-proxy-2` AND whose `x-dwarves-code`
//! metadata header carries it structurally — the code reaches a client that never
//! parses prose.
//! 3. [`every_wired_registry_code_is_reachable_and_the_split_is_honest`] — the registry's
//! wired/reserved split is re-asserted from the test side (a wired code is raised in
//! its file; a reserved one is not raised anywhere), and every code is well-formed +
//! unique. This is the anti-fiction net: a catalog that claims coverage it does not
//! have fails HERE too, not only in the crate's own unit tests.
//!
//! Each emits a `nornir-testmatrix` cell under `--features testmatrix`.
use dwarves::errcode;
use dwarves_gui::build_native_app;
use facett_core::Facet;
use serde_json::json;
const NORNIR_POISON: &str = "http://nornir-poison.example:7878";
const DEAD_DWARVES_HOST: &str = "http://127.0.0.1:9";
/// A dead upstream the proxy fronts — nothing listens, so every forwarded read fails.
const DEAD_UPSTREAM: &str = "http://127.0.0.1:9";
#[allow(unused_variables)]
fn matrix(check: &str, ok: bool, detail: &str) {
#[cfg(feature = "testmatrix")]
nornir_testmatrix::functional_status("dwarves-gui", check, ok, detail);
}
/// Build the shipped shell host-only over `root` as the constellation.
fn shell_over(root: &std::path::Path) -> dwarves_gui::tabbed::TabbedView {
// SAFETY: single-purpose test binary; construction reads the env synchronously.
unsafe {
std::env::set_var("NORNIR_SERVER", NORNIR_POISON);
std::env::set_var("DWARVES_SERVER", DEAD_DWARVES_HOST);
std::env::set_var("DWARVES_CONSTELLATION", root);
std::env::set_var("DWARVES_WAREHOUSES", "demo");
}
build_native_app(
DEAD_DWARVES_HOST.to_string(),
std::path::PathBuf::from("/nonexistent/dwarves-gui/errcodes"),
)
}
/// ROBOT — **the ⚒ Build Thing scene refuses honestly through the SHIPPED shell.**
///
/// The pane that folded `dwarves-buildthing-1` out of a roster is retired; the scene
/// that replaced it has no roster to be empty. What it owes instead is a refusal that
/// NAMES what it looked for and where — so this drives the shipped shell over an empty
/// constellation, asks it to resolve a name, and asserts the refusal is present and
/// specific. A populated constellation resolves, so the refusal is a real signal and
/// not a constant.
#[test]
fn the_build_thing_scene_refuses_by_name_through_the_shipped_shell() {
// ── EMPTY constellation: nothing declares anything. ─────────────────────────────
let empty = std::env::temp_dir().join(format!("dwarves-errcode-empty-{}", std::process::id()));
let _ = std::fs::remove_dir_all(&empty);
std::fs::create_dir_all(&empty).expect("mkdir empty root");
let mut app = shell_over(&empty);
Facet::update_json(&mut app, &json!({ "set_tab": "Build Thing" }).to_string());
Facet::update_json(&mut app, &json!({ "artifact": "app" }).to_string());
Facet::update_json(&mut app, &json!({ "resolve": true }).to_string());
let bt = Facet::state_json(&app)["build-thing"].clone();
let refusal = bt["error"].as_str().unwrap_or_default().to_string();
// An EMPTY root owes the ROOT it searched and the VARIABLE that fixes it — NOT the
// artifact name. `1859b82` ("an empty constellation root says so, instead of saying
// 'not found'") split that case out on purpose: "ingen deklaration nämner app" is
// equally true of a root holding 40 checkouts and one holding none, and only one of
// those is the operator's fault. This assertion still demanded `"app"` and had been
// red ever since, while the guard written FOR the new wording
// (`robot_build_scene_empty_root.rs:116`) was green throughout.
let named = refusal.contains(&empty.display().to_string())
&& refusal.contains("DWARVES_CONSTELLATION")
&& !refusal.contains("app");
assert!(
named,
"the empty-root refusal must name the root and the variable that fixes it, and must \
NOT blame the artifact (that misdiagnosis is what 1859b82 removed): {bt}"
);
let no_matrix = bt["rows"].as_array().map(|a| a.is_empty()).unwrap_or(false)
&& bt["recipe"].is_null()
&& bt["can_build"] == json!(false);
assert!(
no_matrix,
"a refused resolve left a half-built matrix behind: {bt}"
);
// ── POPULATED constellation: it resolves (the refusal is not a constant). ───────
let full = std::env::temp_dir().join(format!("dwarves-errcode-full-{}", std::process::id()));
let _ = std::fs::remove_dir_all(&full);
let dir = full.join("demorepo").join(".nornir");
std::fs::create_dir_all(&dir).expect("mkdir staged");
std::fs::write(
dir.join("build-variants.toml"),
"[[build.variant]]\nname = \"app\"\npackage = \"demo\"\nbin = \"demo\"\ndefault = true\n",
)
.expect("write staged declaration");
let mut app2 = shell_over(&full);
Facet::update_json(&mut app2, &json!({ "set_tab": "Build Thing" }).to_string());
Facet::update_json(&mut app2, &json!({ "artifact": "app" }).to_string());
Facet::update_json(&mut app2, &json!({ "resolve": true }).to_string());
let bt2 = Facet::state_json(&app2)["build-thing"].clone();
let resolved = bt2["error"].is_null()
&& bt2["recipe"]
.as_str()
.unwrap_or_default()
.starts_with("demorepo-build-thing")
&& bt2["row"] == json!("app");
assert!(resolved, "a staged declaration did not resolve: {bt2}");
// ── AND THE NAME MISS, which is where "refuses BY NAME" means anything. Same
// POPULATED root, same shell, a name nobody declares: the refusal owes the NAME
// and the ROOT. Asserting it here rather than on the empty root is what keeps the
// two refusals distinguishable instead of collapsing them into one string.
Facet::update_json(
&mut app2,
&json!({ "artifact": "no-such-artifact-anywhere" }).to_string(),
);
Facet::update_json(&mut app2, &json!({ "resolve": true }).to_string());
let bt3 = Facet::state_json(&app2)["build-thing"].clone();
let miss = bt3["error"].as_str().unwrap_or_default().to_string();
let named_miss =
miss.contains("no-such-artifact-anywhere") && miss.contains(&full.display().to_string());
assert!(
named_miss,
"a POPULATED root refused without naming what was asked and where it looked: {bt3}"
);
let ok = named && no_matrix && resolved && named_miss;
matrix(
"build_scene_refuses_by_name_through_the_shipped_shell",
ok,
"the \u{2692} Build Thing SCENE, driven through the SHIPPED host-only shell, tells its two \
refusals apart: an EMPTY constellation root names the root and $DWARVES_CONSTELLATION \
and never blames the artifact, a POPULATED root that declares no such name names both \
the name and the root, neither leaves a half-built matrix behind, and a staged \
declaration still resolves to its recipe coordinate and row — so both refusals are \
real signals, not constants",
);
}
#[test]
fn a_dead_upstream_puts_the_proxy_code_on_the_grpc_status_and_the_wire() {
// The REAL dwarves proxy in front of a DEAD upstream.
let proxy = dwarves::warehouse_proxy::spawn_proxy(DEAD_UPSTREAM.to_string(), String::new());
// Scan through the proxy — the forwarded read cannot reach the upstream and must come
// back as an honest, CODED Unavailable.
let err = nornir_warehouse_embed::scan_warehouse_table(
&proxy.endpoint,
"",
"nordisk",
"symbol_facts",
10,
)
.expect_err("a dead upstream cannot serve a scan");
let text = err.to_string();
// CHANNEL 1 — the code is in the STATUS MESSAGE (so a client that only logs the
// message still records it, and a log grep finds every occurrence).
let in_message = errcode::carries(&text, "dwarves-proxy-2");
assert!(
in_message,
"the dead-upstream gRPC Status carries dwarves-proxy-2 in its message: {text}"
);
// …and it is READABLE BACK OUT as a registered code across the string boundary.
let parsed = errcode::parse(&text).expect("the code parses back out of the wire error");
assert_eq!(parsed.code, "dwarves-proxy-2");
assert_eq!(
parsed.status,
errcode::Status::Wired,
"proxy-2 is a WIRED code"
);
// The HUMAN half survived too — dual channels, not a code-only regression.
let human_kept = text.contains("unreachable") || text.contains("warehouse-proxy");
assert!(human_kept, "the human reason rides beside the code: {text}");
drop(proxy);
let ok = in_message && human_kept;
matrix(
"error_code_proxy_dead_upstream_grpc_status",
ok,
"the REAL dwarves warehouse-proxy fronting a DEAD upstream answers a Warehouse.Scan with \
an honest Unavailable whose message carries the STABLE code dwarves-proxy-2 (parsed back \
out via errcode::parse) beside the unchanged human reason — the code reaches a gRPC \
client, not only the UI's state_json",
);
}
#[test]
fn every_wired_registry_code_is_reachable_and_the_split_is_honest() {
// UNIQUENESS — no code repeats globally, no n repeats within a subsystem.
let total = errcode::check_unique().expect("the registry is unique");
assert_eq!(total, errcode::REGISTRY.len());
// THE WIRING GUARD, re-asserted from the integration side: every `wired` row is really
// raised in its declared file and no `reserved` row is secretly raised. This is the
// anti-fiction net — a catalog claiming coverage it does not have fails HERE too.
let (wired, reserved) = match errcode::check_wiring() {
Ok(split) => split,
Err(problems) => panic!(
"the dwarves error-code registry claims coverage it does not have:\n {}",
problems.join("\n ")
),
};
assert!(wired > 0, "at least one code is actually wired");
assert_eq!(
wired + reserved,
total,
"every row is either wired or reserved"
);
eprintln!("[errcode] {total} codes — {wired} wired, {reserved} reserved");
// Every code is well-formed and resolves to a source URL.
for e in errcode::REGISTRY {
assert_eq!(e.code, format!("dwarves-{}-{}", e.subsystem, e.n));
assert!(e
.source_url()
.starts_with("https://gunnar.rs/nordisk/dwarves"));
}
matrix(
"error_code_registry_wiring_is_honest",
true,
&format!(
"the dwarves error-code REGISTRY is unique ({total} codes, no repeat globally or \
within a subsystem) AND its wired/reserved split is TRUE: {wired} wired codes are \
each really raised in their declared source file and {reserved} reserved codes are \
raised nowhere — the guard fails in BOTH directions, so the catalog can never \
claim coverage it does not have"
),
);
}