holger-recipe/tests/mvp_formats.rs
//! **The MVP suite serves the MVP formats, and so does `cargo install holger`**
//! (lane HOL-MVP-FORMATS, owner 2026-10-30: "holger.rs must serve every format of the MVP
//! suite, but not every format in the source").
//!
//! The MVP format set is twelve formats: raw, Rust, npm, Maven, Python, Docker/OCI, Go,
//! Helm, deb, rpm, the znippy package and the Build Thing's history. Before this, the MVP server rows (holger.rs's payload among them) carried
//! raw, Rust and npm only, while the suite's own downstream carried Maven, Python, OCI and Go:
//! an MVP downstream could serve formats its MVP upstream could not.
//!
//! Held here, over the declared rows and server/cli's manifest (no cargo process):
//!
//! * every MVP server row of the `holger` package (the open, the metered and both musl
//! payloads, their DEV rows, and the downstream medium) serves exactly the twelve;
//! * server/cli's `default` (`cargo install holger`) serves exactly the same twelve;
//! * no such row or default names a format outside the twelve (NuGet, gems, conda,
//! Composer) or `fmt-all`: those stay opt-in features;
//! * every MVP server row carries `sync`, and none carries `online` (the MVP is zero-egress
//! by design, `.nornir/SUITES.md` "MVP OMITS online").
use std::collections::BTreeSet;
use std::path::{Path, PathBuf};
use holger_recipe::variants::{variants, SERVER_CLI};
use nornir_build_thing::plugin::Role;
/// The MVP format set, as server/cli's own feature names.
const MVP_FORMATS: [&str; 12] = [
"fmt-raw",
"fmt-rust",
"fmt-npm",
"fmt-maven",
"fmt-python",
"fmt-docker",
"fmt-go",
"fmt-helm",
"fmt-deb",
"fmt-rpm",
"fmt-znippy",
"fmt-build-thing",
];
/// The formats the source has and the MVP does not serve (opt-in only), and the umbrella.
const NOT_MVP: [&str; 5] = [
"fmt-all",
"fmt-nuget",
"fmt-gem",
"fmt-conda",
"fmt-composer",
];
fn repo_root() -> PathBuf {
Path::new(env!("CARGO_MANIFEST_DIR"))
.parent()
.unwrap()
.to_path_buf()
}
fn cli_features() -> toml::value::Table {
let p = repo_root().join("server/cli/Cargo.toml");
let text = std::fs::read_to_string(&p).unwrap_or_else(|e| panic!("read {}: {e}", p.display()));
let m: toml::Value =
toml::from_str(&text).unwrap_or_else(|e| panic!("parse {}: {e}", p.display()));
m["features"].as_table().expect("[features]").clone()
}
/// Every server/cli feature `roots` turn on, followed through the manifest. A server-lib
/// format named straight (`server-lib/fmt-maven`) counts as that format, so a row cannot
/// serve a format by going around server/cli's own feature.
fn closure(table: &toml::value::Table, roots: &[String]) -> BTreeSet<String> {
let mut seen = BTreeSet::new();
let mut todo: Vec<String> = roots.to_vec();
while let Some(f) = todo.pop() {
let f = match f.strip_prefix("server-lib/") {
Some(s) if s.starts_with("fmt-") => s.to_string(),
Some(_) => continue,
None if f.contains('/') || f.starts_with("dep:") => continue,
None => f,
};
if !seen.insert(f.clone()) {
continue;
}
if let Some(sub) = table.get(&f).and_then(|v| v.as_array()) {
todo.extend(sub.iter().filter_map(|v| v.as_str()).map(String::from));
}
}
seen
}
fn formats(set: &BTreeSet<String>) -> BTreeSet<String> {
set.iter()
.filter(|f| f.starts_with("fmt-"))
.cloned()
.collect()
}
fn mvp() -> BTreeSet<String> {
MVP_FORMATS.iter().map(|s| s.to_string()).collect()
}
/// The MVP server rows of the `holger` package, with the features each one turns on.
fn mvp_server_rows() -> Vec<(String, BTreeSet<String>)> {
let table = cli_features();
let default: Vec<String> = table["default"]
.as_array()
.unwrap()
.iter()
.filter_map(|v| v.as_str())
.map(String::from)
.collect();
variants()
.into_iter()
.filter(|v| {
v.package.as_deref() == Some(SERVER_CLI)
&& v.role == Some(Role::Server)
&& v.suites.iter().any(|s| s == "MVP")
})
.map(|v| {
let mut roots = v.features.clone();
if !v.no_default_features {
roots.extend(default.iter().cloned());
}
(v.name.clone(), closure(&table, &roots))
})
.collect()
}
#[test]
fn every_mvp_server_row_serves_exactly_the_twelve_mvp_formats() {
let rows = mvp_server_rows();
let names: BTreeSet<&str> = rows.iter().map(|(n, _)| n.as_str()).collect();
// The product `holger` (its default) and the estate's builds of the server (HOL-PRODUCTS);
// the downstream's crate is held below.
for must in [
"holger",
"mvp-server-metered",
"mvp-server-musl",
"mvp-server-musl-metered",
] {
assert!(
names.contains(must),
"no MVP server row `{must}` among {names:?}"
);
}
let mut bad = Vec::new();
for (name, set) in &rows {
let got = formats(set);
if got != mvp() {
let want = mvp();
let missing: Vec<&String> = want.difference(&got).collect();
let extra: Vec<&String> = got.difference(&want).collect();
bad.push(format!(
"{name}: missing {missing:?}, outside the MVP set {extra:?}"
));
}
for f in NOT_MVP {
if set.contains(f) {
bad.push(format!("{name}: names `{f}`, which is no MVP format"));
}
}
}
assert!(
bad.is_empty(),
"the MVP server rows do not serve the MVP format set {MVP_FORMATS:?}:\n {}",
bad.join("\n ")
);
}
/// `cargo install holger-downstream` is the server's `downstream` (its one dependency edge),
/// and serves the same twelve.
#[test]
fn the_downstream_crate_serves_the_same_twelve_formats() {
let table = cli_features();
let down = closure(&table, &["downstream".to_string()]);
assert_eq!(
formats(&down),
mvp(),
"`cargo install holger-downstream` serves the MVP format set"
);
let m: toml::Value = toml::from_str(
&std::fs::read_to_string(repo_root().join("holger-downstream/Cargo.toml")).unwrap(),
)
.unwrap();
let edge = &m["dependencies"]["holger"];
assert_eq!(edge["default-features"].as_bool(), Some(false));
let feats: Vec<&str> = edge["features"]
.as_array()
.unwrap()
.iter()
.filter_map(|v| v.as_str())
.collect();
assert_eq!(
feats,
["downstream"],
"the product is the server's `downstream` and nothing else"
);
}
#[test]
fn the_default_install_serves_the_same_twelve_formats() {
let table = cli_features();
let default = closure(&table, &["default".to_string()]);
assert_eq!(
formats(&default),
mvp(),
"`cargo install holger` (server/cli `default`) serves the MVP format set"
);
for f in NOT_MVP {
assert!(
!default.contains(f),
"`cargo install holger` names `{f}`, which is no MVP format"
);
}
assert!(!default.contains("online"), "the default stays zero-egress");
}
#[test]
fn every_mvp_server_row_carries_sync_and_never_online() {
for (name, set) in mvp_server_rows() {
assert!(
set.contains("sync"),
"{name}: the MVP server rows carry `sync` (the MVP downstream already does)"
);
assert!(!set.contains("online"), "{name}: the MVP is zero-egress by design (SUITES.md \"MVP OMITS online\"); `online` is no MVP feature");
}
}
/// Each of the twelve is server/cli's own passthrough to the server-lib format of the same
/// name, so a row names `fmt-helm`, never `server-lib/fmt-helm`.
#[test]
fn each_mvp_format_is_a_server_cli_passthrough() {
let table = cli_features();
for f in MVP_FORMATS {
let v: Vec<&str> = table
.get(f)
.unwrap_or_else(|| panic!("server/cli declares no feature `{f}`"))
.as_array()
.unwrap()
.iter()
.filter_map(|v| v.as_str())
.collect();
assert_eq!(
v,
[format!("server-lib/{f}").as_str()],
"server/cli `{f}` is the passthrough to server-lib `{f}`"
);
}
// And no feature of server/cli names a server-lib format around its passthrough.
for (name, list) in &table {
// `all-formats` is the opt-in of every format (its old name `fmt-all` is NOT_MVP's).
if MVP_FORMATS.contains(&name.as_str())
|| NOT_MVP.contains(&name.as_str())
|| name == "all-formats"
{
continue;
}
for v in list
.as_array()
.into_iter()
.flatten()
.filter_map(|v| v.as_str())
{
if let Some(f) = v
.strip_prefix("server-lib/")
.filter(|f| f.starts_with("fmt-"))
{
assert!(
!MVP_FORMATS.contains(&f),
"server/cli `{name}` names `{v}`; name the passthrough `{f}`"
);
}
}
}
}