crates/gunnar-grpc/tests/allowance_is_labelled.rs
//! **A cap gunnar reports must say what gunnar DOES at it.**
//!
//! `Usage.Read` reports seven caps to the tenant — `pack_bytes`, `cache_bytes`,
//! `cold_bytes`, `lfs_bytes`, `tombstoned_bytes`, `repos`, `objects` — and until
//! this file existed it reported all seven the same way: a number, in the
//! meter's unit, under a message called `Allowance`. **Three of them are a
//! wall.** The other four are a reading.
//!
//! > *"If a signed fact carries `caps["repos"]=5`, the console shows the tenant
//! > a limit of 5 and nothing on the box refuses the sixth."*
//!
//! monetize has always known the difference — `monetize_product::Enforcement`
//! is `Enforced` / `Measured` / `Provisioned` and `products/gunnar`'s `METERS`
//! marks `repos` as `Measured` with a test pinning it — but nothing carried that
//! word across the wire, so gunnar's own surface flattened it back into "a
//! limit". A number a tenant is shown as a limit that no code enforces is a
//! promise the product does not keep, whatever a table in another repository
//! says about it.
//!
//! # Red first — MEASURED 2026-09-07
//!
//! Run against `Allowance` with the field added to `usage.proto` and nothing
//! filling it, which is the honest shape of the defect: the message could
//! finally SAY what a cap does and `allowance_of` still said nothing.
//!
//! ```text
//! ---- a_measured_cap_is_not_reported_as_a_wall stdout ----
//! thread 'a_measured_cap_is_not_reported_as_a_wall' panicked at
//! crates/gunnar-grpc/tests/allowance_is_labelled.rs:96:5:
//! assertion `left == right` failed: `repos` is reported as a cap of 5 and the
//! tenant is told nothing about what happens at it
//! left: None
//! right: Some(Measured)
//! ```
//!
//! # Why the enforcement word is reported for a meter with NO cap too
//!
//! Because "nothing caps your repositories, and nothing would" and "you have no
//! repository cap yet" are different sentences, and a console rendering a usage
//! row needs the first one even where there is no cap to put beside it. The map
//! therefore has all seven entries on every read, on the metered appliance and
//! on the community one alike — it describes the CODE, not the tenant.
#![cfg(feature = "metered")]
use std::collections::BTreeMap;
use gunnar_grpc::service::usage::allowance_of;
use gunnar_proto::Enforcement;
/// The word this build attaches to `meter`, or `None` when it attached none.
fn word(allowance: &gunnar_proto::Allowance, meter: &str) -> Option<Enforcement> {
allowance
.enforcement
.get(meter)
.copied()
.and_then(|code| Enforcement::try_from(code).ok())
}
fn caps(pairs: &[(&str, u64)]) -> BTreeMap<String, u64> {
pairs
.iter()
.map(|(name, cap)| ((*name).to_owned(), *cap))
.collect()
}
/// **The defect, exactly as the auditor wrote it.** A fact sells five
/// repositories; gunnar refuses the sixth nowhere; the tenant must be told
/// which of those two facts they are looking at.
#[test]
fn a_measured_cap_is_not_reported_as_a_wall() {
let allowance = allowance_of(&caps(&[("repos", 5), ("pack_bytes", 10 << 30)]));
// The cap is still REPORTED. Suppressing it was the other candidate fix and
// it is the wrong one: the tenant bought the number, monetize prices the
// order by it, and hiding it would answer "what did I buy" with silence.
assert_eq!(allowance.repos, Some(5));
assert_eq!(allowance.pack_bytes, Some(10 << 30));
assert_eq!(
word(&allowance, "repos"),
Some(Enforcement::Measured),
"`repos` is reported as a cap of 5 and the tenant is told nothing about \
what happens at it"
);
assert_eq!(
word(&allowance, "pack_bytes"),
Some(Enforcement::Enforced),
"`pack_bytes` is cut mid-stream by the receive loop; this one IS a wall"
);
}
/// **All seven, always** — including the four with no cap in this fact. See the
/// module comment for why an uncapped meter still carries the word.
#[test]
fn every_meter_the_message_has_a_field_for_carries_a_word() {
let allowance = allowance_of(&caps(&[]));
for meter in [
"pack_bytes",
"cache_bytes",
"cold_bytes",
"lfs_bytes",
"tombstoned_bytes",
"repos",
"objects",
] {
assert!(
matches!(
word(&allowance, meter),
Some(Enforcement::Measured) | Some(Enforcement::Enforced)
),
"{meter} has an `Allowance` field and no word about what a cap on it \
would do: {:?}",
word(&allowance, meter)
);
}
assert_eq!(
allowance.enforcement.len(),
7,
"the map describes the seven meters this message has fields for and \
nothing else: {:?}",
allowance.enforcement
);
}
/// **The three doors, named.** This is the list a future meter has to argue its
/// way onto: a `Meter` is `Enforced` here only when a REFUSAL exists on this
/// box, and the doc comment on `service::meters::METERS` names the file and the
/// line for each of them. A meter promoted here without a door would make this
/// test green and the product a liar, which is why the assertion is by name and
/// not a count.
#[test]
fn exactly_the_meters_with_a_door_are_enforced() {
let allowance = allowance_of(&caps(&[]));
let mut walls: Vec<&str> = allowance
.enforcement
.iter()
.filter(|(_, code)| Enforcement::try_from(**code) == Ok(Enforcement::Enforced))
.map(|(meter, _)| meter.as_str())
.collect();
walls.sort_unstable();
assert_eq!(
walls,
["cache_bytes", "lfs_bytes", "pack_bytes"],
"the set of caps this box actually refuses on has changed; a meter joins \
it when a door lands, not before"
);
}