use std::path::Path;
use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256};
use crate::config::normalize_profile_name;
pub const CONTRACT_VERSION: u32 = 1;
pub const CONTRACT_FILE_NAME: &str = "capacity.lock";
const CONTRACT_HEADER: &str = "\
# Autumn capacity contract (issue #1733) — generated by `autumn calibrate`.
#
# Committed on purpose: `autumn calibrate --check` gates rebuilds against it in
# CI, and the runtime can source its load-shedding admission limit from it
# (`[server] capacity_contract`). Re-generate it with `autumn calibrate`
# rather than editing it by hand — the numbers below are measured, and a
# hand-edited envelope is a guarantee nobody proved.
";
#[derive(Debug, thiserror::Error)]
pub enum CapacityError {
#[error("failed to read capacity contract '{path}': {source}")]
Io {
path: String,
#[source]
source: std::io::Error,
},
#[error("capacity contract is not valid TOML: {0}")]
Parse(#[from] toml::de::Error),
#[error("failed to serialize capacity contract: {0}")]
Serialize(#[from] toml::ser::Error),
#[error(
"capacity contract declares schema version {found}, but this build understands \
up to {supported}; re-run `autumn calibrate` with a matching autumn version"
)]
UnsupportedVersion {
found: u32,
supported: u32,
},
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum ResourceShape {
DbBound,
IoBound,
#[default]
ComputeBound,
}
impl ResourceShape {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::DbBound => "db-bound",
Self::IoBound => "io-bound",
Self::ComputeBound => "compute-bound",
}
}
#[must_use]
pub fn from_pools<S: AsRef<str>>(pools: &[S]) -> Self {
if pools.iter().any(|p| p.as_ref() == POOL_DB) {
Self::DbBound
} else if pools.is_empty() {
Self::ComputeBound
} else {
Self::IoBound
}
}
}
impl std::fmt::Display for ResourceShape {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.as_str())
}
}
impl std::str::FromStr for ResourceShape {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"db-bound" => Ok(Self::DbBound),
"io-bound" => Ok(Self::IoBound),
"compute-bound" => Ok(Self::ComputeBound),
_ => Err(()),
}
}
}
impl Serialize for ResourceShape {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
serializer.serialize_str(self.as_str())
}
}
impl<'de> Deserialize<'de> for ResourceShape {
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let s = String::deserialize(deserializer)?;
Ok(s.parse().unwrap_or_default())
}
}
pub const POOL_DB: &str = "db";
pub const POOL_TAGS: &[&str] = &[POOL_DB, "events", "mail", "notifications", "presence"];
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct RouteShape {
pub method: String,
pub path: String,
pub handler: String,
pub shape: ResourceShape,
#[serde(default)]
pub pools: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct HostProfile {
pub os: String,
pub arch: String,
pub logical_cpus: usize,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub total_memory_mb: Option<u64>,
}
impl HostProfile {
const EMPTY: Self = Self {
os: String::new(),
arch: String::new(),
logical_cpus: 0,
total_memory_mb: None,
};
#[must_use]
pub fn detect() -> Self {
Self {
os: std::env::consts::OS.to_owned(),
arch: std::env::consts::ARCH.to_owned(),
logical_cpus: std::thread::available_parallelism().map_or(1, std::num::NonZero::get),
total_memory_mb: detect_total_memory_mb(),
}
}
#[must_use]
pub fn matches(&self, other: &Self) -> bool {
self.os == other.os && self.arch == other.arch && self.logical_cpus == other.logical_cpus
}
#[must_use]
pub fn summary(&self) -> String {
format!("{}/{} {} vCPU", self.os, self.arch, self.logical_cpus)
}
}
fn detect_total_memory_mb() -> Option<u64> {
#[cfg(target_os = "linux")]
{
let meminfo = std::fs::read_to_string("/proc/meminfo").ok()?;
let kb: u64 = meminfo
.lines()
.find_map(|line| line.strip_prefix("MemTotal:"))?
.split_whitespace()
.next()?
.parse()
.ok()?;
Some(kb / 1024)
}
#[cfg(not(target_os = "linux"))]
{
None
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Provenance {
pub autumn_version: String,
pub calibrated_at: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub git_commit: Option<String>,
#[serde(default)]
pub git_dirty: bool,
pub route_graph_digest: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Calibration {
#[serde(default = "default_calibration_profile")]
pub profile: String,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub features: Vec<String>,
#[serde(default, skip_serializing_if = "is_false_flag")]
pub all_features: bool,
#[serde(default, skip_serializing_if = "is_false_flag")]
pub no_default_features: bool,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub targets: Vec<String>,
pub seed: u64,
pub concurrency: Vec<usize>,
pub rung_ms: u64,
#[serde(default = "default_runs")]
pub runs: u32,
pub warmup_ms: u64,
}
#[allow(clippy::trivially_copy_pass_by_ref)]
const fn is_false_flag(flag: &bool) -> bool {
!*flag
}
const fn default_runs() -> u32 {
DEFAULT_RUNS
}
fn default_calibration_profile() -> String {
DEFAULT_PROFILE.to_owned()
}
impl Default for Calibration {
fn default() -> Self {
Self {
profile: default_calibration_profile(),
features: Vec::new(),
all_features: false,
no_default_features: false,
targets: Vec::new(),
seed: DEFAULT_SEED,
concurrency: DEFAULT_LADDER.to_vec(),
rung_ms: DEFAULT_RUNG_MS,
runs: DEFAULT_RUNS,
warmup_ms: DEFAULT_WARMUP_MS,
}
}
}
pub const DEFAULT_PROFILE: &str = "prod";
pub const DEFAULT_SEED: u64 = 1733;
pub const DEFAULT_LADDER: &[usize] = &[1, 2, 4, 8, 16, 32, 64];
pub const DEFAULT_RUNG_MS: u64 = 2000;
pub const DEFAULT_WARMUP_MS: u64 = 1000;
pub const DEFAULT_RUNS: u32 = 3;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Envelope {
pub sustained_rps: f64,
pub p99_latency_ms: f64,
pub saturation_concurrency: usize,
pub admission_limit: usize,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct CapacityContract {
pub version: u32,
pub provenance: Provenance,
pub host: HostProfile,
pub envelope: Envelope,
#[serde(default)]
pub calibration: Calibration,
#[serde(default, rename = "routes")]
pub routes: Vec<RouteShape>,
}
#[derive(Deserialize)]
struct VersionProbe {
version: u32,
}
impl CapacityContract {
pub fn parse(toml_src: &str) -> Result<Self, CapacityError> {
let probe: VersionProbe = toml::from_str(toml_src)?;
if probe.version > CONTRACT_VERSION {
return Err(CapacityError::UnsupportedVersion {
found: probe.version,
supported: CONTRACT_VERSION,
});
}
Ok(toml::from_str(toml_src)?)
}
pub fn load(path: impl AsRef<Path>) -> Result<Self, CapacityError> {
let path = path.as_ref();
let src = std::fs::read_to_string(path).map_err(|source| CapacityError::Io {
path: path.display().to_string(),
source,
})?;
Self::parse(&src)
}
pub fn to_toml(&self) -> Result<String, CapacityError> {
let mut canonical = self.clone();
canonical.canonicalize();
let body = toml::to_string_pretty(&canonical)?;
Ok(format!("{CONTRACT_HEADER}{body}"))
}
pub fn canonicalize(&mut self) {
for route in &mut self.routes {
route.pools.sort_unstable();
route.pools.dedup();
}
self.routes
.sort_by(|a, b| a.path.cmp(&b.path).then_with(|| a.method.cmp(&b.method)));
}
#[must_use]
pub fn admission_limit_for_host(&self, host: &HostProfile) -> Option<usize> {
if !self.host.matches(host) {
return None;
}
(self.envelope.admission_limit > 0).then_some(self.envelope.admission_limit)
}
#[must_use]
pub(crate) fn calibrated_under(&self, running: Option<&str>) -> bool {
let Some(running) = running.and_then(normalize_profile_name) else {
return true;
};
normalize_profile_name(&self.calibration.profile).is_some_and(|own| own == running)
}
}
#[must_use]
pub fn resolve_configured_admission_limit(
explicit: Option<usize>,
contract_path: Option<&str>,
) -> AdmissionLimit {
resolve_configured_admission_limit_with_default(explicit, contract_path, None)
}
#[must_use]
pub fn resolve_configured_admission_limit_with_default(
explicit: Option<usize>,
contract_path: Option<&str>,
profile_default: Option<usize>,
) -> AdmissionLimit {
resolve_configured_admission_limit_for_profile(explicit, contract_path, profile_default, None)
}
#[must_use]
pub fn resolve_configured_admission_limit_for_profile(
explicit: Option<usize>,
contract_path: Option<&str>,
profile_default: Option<usize>,
running_profile: Option<&str>,
) -> AdmissionLimit {
let path = contract_path.filter(|p| !p.is_empty());
if explicit.is_some() || path.is_none() {
return resolve_admission_limit_for_profile(
explicit,
None,
&HostProfile::EMPTY,
profile_default,
running_profile,
);
}
resolve_admission_limit_for_profile(
explicit,
path.map(Path::new),
&HostProfile::detect(),
profile_default,
running_profile,
)
}
#[must_use]
pub fn route_graph_digest(routes: &[RouteShape]) -> String {
let mut lines: Vec<String> = routes
.iter()
.map(|route| {
let mut pools = route.pools.clone();
pools.sort_unstable();
pools.dedup();
format!(
"{} {} {} {}",
route.method,
route.path,
route.shape.as_str(),
pools.join(",")
)
})
.collect();
lines.sort_unstable();
let mut hasher = Sha256::new();
for line in &lines {
hasher.update(line.as_bytes());
hasher.update(b"\n");
}
format!("sha256:{:x}", hasher.finalize())
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum AdmissionLimit {
Configured(usize),
Contract(usize),
ProfileDefault(usize),
Unlimited,
}
impl AdmissionLimit {
#[must_use]
pub const fn limit(self) -> Option<usize> {
match self {
Self::Configured(n) | Self::Contract(n) | Self::ProfileDefault(n) => Some(n),
Self::Unlimited => None,
}
}
#[must_use]
pub const fn source(self) -> &'static str {
match self {
Self::Configured(_) => "server.max_concurrent_requests",
Self::Contract(_) => "capacity contract",
Self::ProfileDefault(_) => "profile default",
Self::Unlimited => "unset",
}
}
}
#[must_use]
pub fn resolve_admission_limit(
explicit: Option<usize>,
contract_path: Option<&Path>,
host: &HostProfile,
) -> AdmissionLimit {
resolve_admission_limit_with_default(explicit, contract_path, host, None)
}
#[must_use]
pub fn resolve_admission_limit_with_default(
explicit: Option<usize>,
contract_path: Option<&Path>,
host: &HostProfile,
profile_default: Option<usize>,
) -> AdmissionLimit {
resolve_admission_limit_for_profile(explicit, contract_path, host, profile_default, None)
}
#[must_use]
pub fn resolve_admission_limit_for_profile(
explicit: Option<usize>,
contract_path: Option<&Path>,
host: &HostProfile,
profile_default: Option<usize>,
running_profile: Option<&str>,
) -> AdmissionLimit {
let fallback = profile_default
.filter(|n| *n > 0)
.map_or(AdmissionLimit::Unlimited, AdmissionLimit::ProfileDefault);
if let Some(configured) = explicit {
return if configured > 0 {
AdmissionLimit::Configured(configured)
} else {
AdmissionLimit::Unlimited
};
}
let Some(path) = contract_path else {
return fallback;
};
let contract = match CapacityContract::load(path) {
Ok(contract) => contract,
Err(error) => {
tracing::warn!(
path = %path.display(),
%error,
fallback = fallback.source(),
"capacity contract could not be read; using the fallback admission limit"
);
return fallback;
}
};
if !contract.calibrated_under(running_profile) {
tracing::warn!(
path = %path.display(),
contract_profile = %contract.calibration.profile,
running_profile = running_profile.unwrap_or_default(),
fallback = fallback.source(),
"capacity contract was calibrated under another profile, so \
the fallback admission limit applies"
);
return fallback;
}
if let Some(limit) = contract.admission_limit_for_host(host) {
AdmissionLimit::Contract(limit)
} else {
tracing::warn!(
path = %path.display(),
contract_host = %contract.host.summary(),
running_host = %host.summary(),
admission_limit = contract.envelope.admission_limit,
fallback = fallback.source(),
"capacity contract licenses no admission limit here (different host \
class, or no limit recorded); using the fallback admission limit"
);
fallback
}
}
#[cfg(test)]
mod tests {
use super::*;
fn sample_routes() -> Vec<RouteShape> {
vec![
RouteShape {
method: "GET".to_owned(),
path: "/posts".to_owned(),
handler: "posts::index".to_owned(),
shape: ResourceShape::DbBound,
pools: vec!["db".to_owned()],
},
RouteShape {
method: "GET".to_owned(),
path: "/about".to_owned(),
handler: "pages::about".to_owned(),
shape: ResourceShape::ComputeBound,
pools: Vec::new(),
},
]
}
fn sample_contract() -> CapacityContract {
let routes = sample_routes();
CapacityContract {
version: CONTRACT_VERSION,
provenance: Provenance {
autumn_version: "0.7.0".to_owned(),
calibrated_at: "2026-09-01T12:00:00Z".to_owned(),
git_commit: Some("abc1234".to_owned()),
git_dirty: false,
route_graph_digest: route_graph_digest(&routes),
},
host: HostProfile {
os: "linux".to_owned(),
arch: "x86_64".to_owned(),
logical_cpus: 8,
total_memory_mb: Some(16384),
},
envelope: Envelope {
sustained_rps: 4210.5,
p99_latency_ms: 18.42,
saturation_concurrency: 64,
admission_limit: 64,
},
calibration: Calibration::default(),
routes,
}
}
#[test]
fn contract_round_trips_through_toml() {
let contract = sample_contract();
let rendered = contract.to_toml().expect("contract should serialize");
let parsed = CapacityContract::parse(&rendered).expect("contract should parse back");
assert_eq!(parsed.version, CONTRACT_VERSION);
assert_eq!(parsed.host.logical_cpus, 8);
assert_eq!(parsed.envelope.admission_limit, 64);
assert!((parsed.envelope.sustained_rps - 4210.5).abs() < 1e-9);
assert_eq!(parsed.routes.len(), 2);
assert_eq!(parsed.calibration, Calibration::default());
assert!(
parsed.calibration.targets.is_empty(),
"an unset target list round-trips as 'discover them'"
);
assert_eq!(parsed.calibration.concurrency, DEFAULT_LADDER.to_vec());
}
#[test]
fn explicitly_named_targets_survive_the_round_trip() {
let mut contract = sample_contract();
contract.calibration.targets = vec!["/search".to_owned(), "/report".to_owned()];
let rendered = contract.to_toml().expect("serialize");
let parsed = CapacityContract::parse(&rendered).expect("parse");
assert_eq!(
parsed.calibration.targets,
vec!["/search".to_owned(), "/report".to_owned()]
);
}
#[test]
fn to_toml_sorts_routes_for_stable_diffs() {
let mut contract = sample_contract();
contract.routes.reverse();
let rendered = contract.to_toml().expect("contract should serialize");
let parsed = CapacityContract::parse(&rendered).expect("contract should parse back");
let paths: Vec<&str> = parsed.routes.iter().map(|r| r.path.as_str()).collect();
assert_eq!(paths, ["/about", "/posts"]);
}
#[test]
fn parse_rejects_a_newer_contract_version() {
let mut contract = sample_contract();
contract.version = CONTRACT_VERSION + 1;
let rendered = toml::to_string_pretty(&contract).expect("raw serialize");
let err = CapacityContract::parse(&rendered).expect_err("newer version must be rejected");
assert!(
matches!(err, CapacityError::UnsupportedVersion { .. }),
"expected UnsupportedVersion, got {err}"
);
}
#[test]
fn parse_reports_malformed_toml() {
let err = CapacityContract::parse("this is not = = toml").expect_err("must reject garbage");
assert!(matches!(err, CapacityError::Parse(_)), "got {err}");
}
#[test]
fn host_profiles_match_on_os_arch_and_cpu_count() {
let a = HostProfile {
os: "linux".to_owned(),
arch: "x86_64".to_owned(),
logical_cpus: 8,
total_memory_mb: Some(16384),
};
let b = HostProfile {
total_memory_mb: None,
..a.clone()
};
assert!(a.matches(&b));
let fewer_cpus = HostProfile {
logical_cpus: 4,
..a.clone()
};
assert!(!a.matches(&fewer_cpus));
let other_arch = HostProfile {
arch: "aarch64".to_owned(),
..a.clone()
};
assert!(!a.matches(&other_arch));
}
#[test]
fn admission_limit_is_offered_only_on_a_matching_host() {
let contract = sample_contract();
assert_eq!(
contract.admission_limit_for_host(&contract.host.clone()),
Some(64)
);
let other = HostProfile {
logical_cpus: 2,
..contract.host.clone()
};
assert_eq!(contract.admission_limit_for_host(&other), None);
}
#[test]
fn a_zero_admission_limit_is_never_enforced() {
let mut contract = sample_contract();
contract.envelope.admission_limit = 0;
assert_eq!(
contract.admission_limit_for_host(&contract.host.clone()),
None
);
}
#[test]
fn every_pool_tag_classifies_and_the_database_tag_dominates() {
assert!(POOL_TAGS.contains(&POOL_DB));
let mut sorted = POOL_TAGS.to_vec();
sorted.sort_unstable();
assert_eq!(sorted, POOL_TAGS, "POOL_TAGS must stay sorted");
for tag in POOL_TAGS {
let shape = ResourceShape::from_pools(&[*tag]);
let expected = if *tag == POOL_DB {
ResourceShape::DbBound
} else {
ResourceShape::IoBound
};
assert_eq!(shape, expected, "tag {tag} classified wrongly");
}
assert_eq!(
ResourceShape::from_pools(&["mail", POOL_DB]),
ResourceShape::DbBound
);
}
#[test]
fn resource_shape_serializes_as_a_stable_tag() {
assert_eq!(ResourceShape::DbBound.as_str(), "db-bound");
assert_eq!(ResourceShape::IoBound.as_str(), "io-bound");
assert_eq!(ResourceShape::ComputeBound.as_str(), "compute-bound");
assert_eq!(
"db-bound".parse::<ResourceShape>().expect("parses"),
ResourceShape::DbBound
);
}
#[test]
fn route_graph_digest_ignores_ordering_but_tracks_shape() {
let routes = sample_routes();
let mut reordered = routes.clone();
reordered.reverse();
assert_eq!(route_graph_digest(&routes), route_graph_digest(&reordered));
let mut changed = routes.clone();
changed[0].shape = ResourceShape::ComputeBound;
assert_ne!(route_graph_digest(&routes), route_graph_digest(&changed));
}
use std::io::Write as _;
fn write_contract(contract: &CapacityContract) -> (tempfile::TempDir, std::path::PathBuf) {
let dir = tempfile::tempdir().expect("temp dir");
let path = dir.path().join(CONTRACT_FILE_NAME);
let mut file = std::fs::File::create(&path).expect("create contract");
file.write_all(contract.to_toml().expect("serialize").as_bytes())
.expect("write contract");
(dir, path)
}
#[test]
fn an_explicit_ceiling_wins_over_the_contract() {
let mut contract = sample_contract();
contract.host = HostProfile::detect();
let (_dir, path) = write_contract(&contract);
let resolved = resolve_admission_limit(Some(16), Some(&path), &HostProfile::detect());
assert_eq!(resolved, AdmissionLimit::Configured(16));
assert_eq!(resolved.limit(), Some(16));
}
#[test]
fn an_explicit_zero_disables_shedding_and_never_consults_the_contract() {
let mut contract = sample_contract();
contract.host = HostProfile::detect();
let (_dir, path) = write_contract(&contract);
let resolved = resolve_admission_limit(Some(0), Some(&path), &HostProfile::detect());
assert_eq!(resolved, AdmissionLimit::Unlimited);
assert_eq!(resolved.limit(), None);
}
#[test]
fn the_contract_supplies_the_limit_when_no_ceiling_is_configured() {
let mut contract = sample_contract();
contract.host = HostProfile::detect();
let (_dir, path) = write_contract(&contract);
let resolved = resolve_admission_limit(None, Some(&path), &HostProfile::detect());
assert_eq!(resolved, AdmissionLimit::Contract(64));
}
#[test]
fn a_contract_measured_on_another_host_class_is_not_enforced() {
let mut contract = sample_contract();
contract.host = HostProfile {
logical_cpus: HostProfile::detect().logical_cpus.saturating_add(7),
..HostProfile::detect()
};
let (_dir, path) = write_contract(&contract);
assert_eq!(
resolve_admission_limit(None, Some(&path), &HostProfile::detect()),
AdmissionLimit::Unlimited
);
}
#[test]
fn an_unreadable_or_malformed_contract_leaves_admission_unlimited() {
let missing = std::path::Path::new("/nonexistent/capacity.lock");
assert_eq!(
resolve_admission_limit(None, Some(missing), &HostProfile::detect()),
AdmissionLimit::Unlimited
);
let dir = tempfile::tempdir().expect("temp dir");
let path = dir.path().join(CONTRACT_FILE_NAME);
std::fs::write(&path, "not = = a contract").expect("write garbage");
assert_eq!(
resolve_admission_limit(None, Some(&path), &HostProfile::detect()),
AdmissionLimit::Unlimited
);
}
#[test]
fn no_contract_configured_leaves_todays_behaviour_untouched() {
assert_eq!(
resolve_admission_limit(None, None, &HostProfile::detect()),
AdmissionLimit::Unlimited
);
assert_eq!(
resolve_admission_limit(Some(32), None, &HostProfile::detect()),
AdmissionLimit::Configured(32)
);
}
#[test]
fn the_profile_default_applies_when_nothing_else_is_set() {
let resolved =
resolve_admission_limit_with_default(None, None, &HostProfile::detect(), Some(320));
assert_eq!(resolved, AdmissionLimit::ProfileDefault(320));
assert_eq!(resolved.limit(), Some(320));
assert_eq!(resolved.source(), "profile default");
}
#[test]
fn explicit_settings_win_over_the_profile_default() {
let host = HostProfile::detect();
assert_eq!(
resolve_admission_limit_with_default(Some(16), None, &host, Some(320)),
AdmissionLimit::Configured(16)
);
assert_eq!(
resolve_admission_limit_with_default(Some(0), None, &host, Some(320)),
AdmissionLimit::Unlimited
);
}
#[test]
fn the_contract_wins_over_the_profile_default() {
let mut contract = sample_contract();
contract.host = HostProfile::detect();
let (_dir, path) = write_contract(&contract);
assert_eq!(
resolve_admission_limit_with_default(
None,
Some(&path),
&HostProfile::detect(),
Some(320)
),
AdmissionLimit::Contract(64)
);
}
#[test]
fn contract_failures_fall_back_to_the_profile_default() {
let host = HostProfile::detect();
let missing = std::path::Path::new("/nonexistent/capacity.lock");
assert_eq!(
resolve_admission_limit_with_default(None, Some(missing), &host, Some(320)),
AdmissionLimit::ProfileDefault(320)
);
let mut contract = sample_contract();
contract.host = HostProfile {
logical_cpus: host.logical_cpus.saturating_add(7),
..host.clone()
};
let (_dir, path) = write_contract(&contract);
assert_eq!(
resolve_admission_limit_with_default(None, Some(&path), &host, Some(320)),
AdmissionLimit::ProfileDefault(320)
);
}
#[test]
fn a_zero_profile_default_never_sheds_everything() {
assert_eq!(
resolve_admission_limit_with_default(None, None, &HostProfile::detect(), Some(0)),
AdmissionLimit::Unlimited
);
}
#[test]
fn the_configured_wrapper_threads_the_profile_default() {
assert_eq!(
resolve_configured_admission_limit_with_default(None, None, Some(320)),
AdmissionLimit::ProfileDefault(320)
);
assert_eq!(
resolve_configured_admission_limit_with_default(None, Some(""), Some(320)),
AdmissionLimit::ProfileDefault(320)
);
assert_eq!(
resolve_configured_admission_limit_with_default(Some(0), None, Some(320)),
AdmissionLimit::Unlimited
);
}
fn local_contract_under(profile: &str) -> (tempfile::TempDir, std::path::PathBuf) {
let mut contract = sample_contract();
contract.host = HostProfile::detect();
contract.calibration.profile = profile.to_owned();
write_contract(&contract)
}
#[test]
fn a_contract_calibrated_under_another_profile_fails_open() {
let (_dir, path) = local_contract_under("staging");
let host = HostProfile::detect();
assert_eq!(
resolve_admission_limit_for_profile(None, Some(&path), &host, Some(320), Some("prod")),
AdmissionLimit::ProfileDefault(320)
);
assert_eq!(
resolve_admission_limit_for_profile(None, Some(&path), &host, None, Some("prod")),
AdmissionLimit::Unlimited
);
}
#[test]
fn a_contract_calibrated_under_the_running_profile_is_enforced() {
let (_dir, path) = local_contract_under("prod");
let host = HostProfile::detect();
assert_eq!(
resolve_admission_limit_for_profile(None, Some(&path), &host, Some(320), Some("prod")),
AdmissionLimit::Contract(64)
);
}
#[test]
fn profile_aliases_and_case_compare_equal() {
let (_dir, path) = local_contract_under("production");
let host = HostProfile::detect();
for running in ["prod", "PROD", " production "] {
assert_eq!(
resolve_admission_limit_for_profile(None, Some(&path), &host, None, Some(running)),
AdmissionLimit::Contract(64),
"{running}"
);
}
}
#[test]
fn custom_profile_names_must_match_exactly() {
let (_dir, path) = local_contract_under("staging");
let host = HostProfile::detect();
assert_eq!(
resolve_admission_limit_for_profile(None, Some(&path), &host, None, Some("staging")),
AdmissionLimit::Contract(64)
);
assert_eq!(
resolve_admission_limit_for_profile(None, Some(&path), &host, None, Some("Staging")),
AdmissionLimit::Unlimited
);
}
#[test]
fn a_blank_calibrated_profile_matches_no_named_profile() {
let (_dir, path) = local_contract_under(" ");
let host = HostProfile::detect();
assert_eq!(
resolve_admission_limit_for_profile(None, Some(&path), &host, None, Some("prod")),
AdmissionLimit::Unlimited
);
}
#[test]
fn an_unknown_runtime_profile_skips_the_profile_check() {
let (_dir, path) = local_contract_under("staging");
let host = HostProfile::detect();
for running in [None, Some(""), Some(" ")] {
assert_eq!(
resolve_admission_limit_for_profile(None, Some(&path), &host, None, running),
AdmissionLimit::Contract(64),
"{running:?}"
);
}
}
#[test]
fn the_configured_wrapper_checks_the_profile() {
let (_dir, path) = local_contract_under("staging");
let path = path.to_str().expect("utf-8 path");
assert_eq!(
resolve_configured_admission_limit_for_profile(
None,
Some(path),
Some(320),
Some("prod")
),
AdmissionLimit::ProfileDefault(320)
);
assert_eq!(
resolve_configured_admission_limit_for_profile(
None,
Some(path),
Some(320),
Some("staging")
),
AdmissionLimit::Contract(64)
);
}
}