crates/holger-ui-recipe/tests/toml_parity.rs
//! **`.nornir/build-variants.toml` IS the code's emission — and this fails for
//! any reason it is not.**
//!
//! 1. the committed bytes are `emit`'s bytes (a row added to the code and not
//! re-emitted, a hand edit, a comment typed into the output: all red);
//! 2. the emission reads back, through the ONE loader, to the declaration;
//! 3. the file is inert — an edit is visible to a reader and invisible to the code;
//! 4. the comparison can go red at all (a set differing by one field is unequal).
use holger_ui_recipe::{declared, emitted_toml, repo_root, HolgerUiBuildThing};
use nornir_build_thing::emit::first_difference;
use nornir_build_thing::plugin::{BuildThing, Role};
use nornir_build_thing::variant::{ArtifactKind, BuildVariantSet, Profile, ServiceShape};
fn committed() -> String {
let path = BuildVariantSet::conventional_path(&repo_root());
std::fs::read_to_string(&path).unwrap_or_else(|e| panic!("read {}: {e}", path.display()))
}
#[test]
fn the_committed_toml_is_the_codes_emission_byte_for_byte() {
let emitted = emitted_toml().expect("the declaration emits");
if let Some(diff) = first_difference(&committed(), &emitted) {
panic!(
".nornir/build-variants.toml is not the code's emission — the code is the source. \
Run `cargo run -p holger-ui-build-thing -- emit` and commit the result; never edit \
the toml by hand. {diff}"
);
}
let back = BuildVariantSet::from_toml_str(&emitted).expect("the emission parses back");
assert_eq!(back, declared());
back.validate_all().expect("and every variant validates");
holger_ui_recipe::require_committed_is_emitted(&repo_root())
.expect("the door's own check agrees");
}
#[test]
fn an_edited_toml_has_zero_effect_on_what_the_code_declares() {
let before = declared();
let edited = emitted_toml()
.unwrap()
.replace("name = \"mvp-ui-web\"", "name = \"mvp-ui-web-edited\"");
let read = BuildVariantSet::from_toml_str(&edited).expect("still parses");
assert_ne!(
read, before,
"the edit must be visible to a reader, else this proves nothing"
);
assert_eq!(
HolgerUiBuildThing.variants(),
before,
"the code read the file — it must not"
);
}
#[test]
fn the_comparison_reports_red_on_a_set_that_differs_by_one_field() {
let set =
BuildVariantSet::load_file(&BuildVariantSet::conventional_path(&repo_root())).unwrap();
assert_eq!(set.variants.len(), 4, "4 [[build.variant]] rows: the open bundle, the metered bundle, the BFF and the OPEN `ui` (H5)");
let mut p = set.clone();
p.variants[0].target = None;
assert_ne!(p, set, "a variant losing its target must compare unequal");
let mut p = set.clone();
p.variants[0].suites.clear();
assert_ne!(
p, set,
"a variant losing its suite tag must compare unequal"
);
}
/// **Every row is a build this repository already performs**, held to the values
/// the doors that perform it use: `Trunk.toml`, `README.md` §Release build
/// (`trunk build --release`) and `xtask publish` (`trunk build --release --dist
/// ~/.local/share/holger-console/dist`).
#[test]
fn the_rows_describe_the_builds_that_already_happen() {
let set = declared();
let v = set.get("mvp-ui-web").expect("mvp-ui-web is declared");
assert_eq!(v.package.as_deref(), Some("holger-ui-web"));
assert_eq!(v.bin.as_deref(), Some("holger-ui-web"));
assert_eq!(v.target.as_deref(), Some("wasm32-unknown-unknown"));
assert_eq!(v.profile, Profile::Release);
assert_eq!(v.kind, ArtifactKind::Wasm);
assert_eq!(
v.role,
Some(Role::Client),
"a UI is a client, not a new role — `nornir_build_thing::plugin::Role` is \
Server | Client | Solo and no `Ui` exists to spell"
);
assert!(
v.member.is_none(),
"a browser bundle is no system service: nothing installs a unit or a user for it"
);
assert_eq!(v.shape, ServiceShape::ThinStandalone);
assert!(v.embeds.is_empty(), "nothing here compiles a sibling in");
assert!(
v.reaches.contains("holger"),
"the console is a blank page without a running holger — the wire is gRPC-web \
straight to the tonic-web door, with no BFF in between"
);
assert!(
v.features.is_empty(),
"the open bundle is what a bare `trunk build --release` makes: no feature"
);
// The suite tag, on the one row, although this repository has one delivery.
// `workspace_nordisk/.nornir/SUITE-MODEL.md`: tagging is what lets one
// command shape work house-wide. MVP because this console's surface is the
// Secure Update Gateway's; ORIGINAL's `ui` atom is holger's egui app.
assert_eq!(v.suites, ["MVP"]);
// The feature universe is the paid half's one word (A28 M13).
assert_eq!(set.offers.iter().map(String::as_str).collect::<Vec<_>>(), ["metered"]);
// Exactly one normal case per role group, and there are two groups now.
assert!(
set.check_defaults().is_empty(),
"{:?}",
set.check_defaults()
);
assert!(
set.get("mvp-ui-web").unwrap().is_default,
"what a bare `trunk build --release` makes"
);
assert!(
set.get("mvp-ui").unwrap().is_default,
"what a bare `cargo build --release -p holger-ui` makes"
);
}
/// ★ **The `mvp-ui` BFF row, and it names a build that runs.**
///
/// This test used to assert the OPPOSITE — `no_bff_row_is_declared_because_no_bff_package_exists`,
/// whose whole job was to make adding the row a deliberate act that came WITH
/// the crate rather than a copy of gunnar-ui's declaration describing nothing.
/// It carried its own retirement instruction:
///
/// > holger-ui-server now EXISTS — declare its row (see this test's doc comment)
/// > and delete this assertion
///
/// The crate landed 2026-09-17 and this is what replaced it: the same guard,
/// pointing the other way. A row whose package is not in the workspace is still
/// a row naming a build that cannot run, and that is now checked for the row
/// that exists rather than asserted about the one that did not.
#[test]
fn the_bff_row_names_a_package_that_is_in_this_workspace() {
let set = declared();
let v = set.get("mvp-ui").expect(
"`mvp-ui` is the backend-for-frontend row; it was added the day \
crates/holger-ui-server did",
);
// The program is the product crate `holger-ui` (HOL-PRODUCTS), over the library.
assert_eq!(v.package.as_deref(), Some("holger-ui"));
assert_eq!(v.bin.as_deref(), Some("holger-ui"));
assert!(
repo_root()
.join("crates/holger-ui/Cargo.toml")
.is_file(),
"the row names a package this workspace does not contain, so \
`cargo build -p holger-ui-server` fails with `package not found`"
);
assert_eq!(v.profile, Profile::Release);
// ★ `service` since 2026-09-19, and the three facts that made it true are
// checked here rather than assumed. This assertion said `Exe` until that
// day, with the reason "this binary installs no unit — it has
// --env-template and --check-env, which write nothing, and no --install".
// All three clauses are now false, so the assertion moved with them.
assert_eq!(
v.kind,
ArtifactKind::Service,
"`holger-ui-server --install` mints a unit through skidbladnir \
(holger_ui_server::lifecycle), so `service` is what is built"
);
assert_eq!(
v.member.as_deref(),
Some("holger-ui"),
"a `service` REQUIRES a member: it is the account the unit runs as and the \
one an uninstall knows to leave alone. It must equal \
holger_ui_server::lifecycle::{{UNIT, USER}}"
);
assert_eq!(
v.target.as_deref(),
Some("x86_64-unknown-linux-musl"),
"the triple `cargo xtask front plan` step 15 in private-holger-ops builds this \
binary for. The row said `None` while the only plan that builds it said musl, \
and a row that disagrees with its own door is the row that is wrong"
);
assert_eq!(v.role, Some(Role::Server), "it opens a port and holds state");
assert_eq!(v.shape, ServiceShape::ThinStandalone);
assert!(v.embeds.is_empty(), "nothing here compiles a sibling in");
assert!(
v.reaches.contains("holger"),
"without a reachable holger every /api/ answer is a gateway refusal"
);
assert!(
v.features.is_empty(),
"the BFF row builds the open server: its `metered` half is turned on by \
holger-estate-front, which links it as a library, and no door here builds it"
);
assert_eq!(v.suites, ["MVP"]);
assert!(v.is_default, "the only row in the server group");
}
/// **NO `[[build.wasm]]` cell, and the absence is the declaration.**
///
/// The bundle is built by trunk, which runs the row's cargo build and then
/// wasm-bindgen, `wasm-opt` and the `index.html` asset pipeline — writing
/// CONTENT-HASHED names (`holger-ui-web-<hash>_bg.wasm`, which `xtask publish`
/// globs for by that `_bg.wasm` suffix). `BindgenStage` DERIVES its outputs from
/// the package name, so a cell here would name `holger_ui_web_bg.wasm` and
/// `holger_ui_web.js`, two files trunk never writes, and anything chaining the
/// cell would be checked against a claim that is false.
#[test]
fn the_console_declares_no_wasm_cell_because_trunk_is_not_wasm_bindgen() {
let set = declared();
assert!(
set.wasms.is_empty(),
"a [[build.wasm]] cell would have to describe trunk, and BindgenStage cannot: \
trunk's outputs are content-hashed and it also runs wasm-opt and the index.html \
pipeline. See this test's doc comment."
);
let bundle = repo_root().join("Trunk.toml");
assert!(
bundle.is_file(),
"the bundler this repository actually uses: {}",
bundle.display()
);
}
/// ★ A28 M13: **the paid console is its own bundle.** `mvp-ui-web-metered` is the open row
/// with `metered`, into `dist-metered/` from `index-metered.html`; the open row stays the
/// client group's default, into `dist/` from `index.html`.
#[test]
fn the_metered_bundle_is_its_own_row_and_its_own_dist() {
let set = declared();
let open = set.get("mvp-ui-web").expect("the open bundle");
let paid = set.get("mvp-ui-web-metered").expect("the metered bundle");
assert_eq!(paid.features, ["metered"]);
assert!(!paid.is_default, "a bare `trunk build --release` makes the open bundle");
assert!(open.is_default);
assert_eq!((paid.package.as_deref(), paid.bin.as_deref(), paid.target.as_deref(), paid.kind, paid.role), (open.package.as_deref(), open.bin.as_deref(), open.target.as_deref(), open.kind, open.role));
let apps: Vec<(&str, &str, &str)> = set.web_apps.iter().map(|a| (a.name.as_str(), a.out_dir.as_str(), a.index.as_str())).collect();
assert_eq!(apps, [("mvp-ui-web", "dist", "index.html"), ("mvp-ui-web-metered", "dist-metered", "index-metered.html")]);
for (_, _, page) in &apps {
assert!(repo_root().join(page).is_file(), "{page} is committed");
}
}