use std::time::Duration;
use serde::{Deserialize, Serialize};
use thiserror::Error;
use crate::supervisor;
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct WitContract {
pub de: String,
pub para: String,
pub wit: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub endpoint: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub subject: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub slot: Option<String>,
}
pub const WIT_HTTP_SHAPE_PREFIXES: &[&str] = &["wasi:http/", "http:"];
pub const WIT_PUBSUB_SHAPE_PREFIXES: &[&str] = &["nats:", "kafka:"];
pub const WIT_STORE_SHAPE_PREFIXES: &[&str] = &["wasi:keyvalue/", "kv:"];
#[must_use]
pub fn wit_shape_matches(wit: &str, prefixes: &[&str]) -> bool {
prefixes.iter().any(|p| wit.starts_with(p))
}
#[must_use]
pub fn wit_shape_is_http(wit: &str) -> bool {
wit_shape_matches(wit, WIT_HTTP_SHAPE_PREFIXES)
}
#[must_use]
pub fn wit_shape_is_pubsub(wit: &str) -> bool {
wit_shape_matches(wit, WIT_PUBSUB_SHAPE_PREFIXES)
}
#[must_use]
pub fn wit_shape_is_store(wit: &str) -> bool {
wit_shape_matches(wit, WIT_STORE_SHAPE_PREFIXES)
}
impl WitContract {
#[must_use]
pub fn source(&self) -> &str {
self.de.as_str()
}
#[must_use]
pub fn destination(&self) -> &str {
self.para.as_str()
}
#[must_use]
pub fn world_ref(&self) -> &str {
self.wit.as_str()
}
#[must_use]
pub fn endpoint(&self) -> Option<&str> {
self.endpoint.as_deref()
}
#[must_use]
pub fn subject(&self) -> Option<&str> {
self.subject.as_deref()
}
#[must_use]
pub fn slot(&self) -> Option<&str> {
self.slot.as_deref()
}
#[must_use]
pub fn edge_pair(&self) -> (String, String) {
(self.source().to_string(), self.destination().to_string())
}
#[must_use]
pub fn edge_triple(&self) -> (String, String, String) {
(
self.source().to_string(),
self.destination().to_string(),
self.world_ref().to_string(),
)
}
#[must_use]
pub fn identity(&self) -> ContratoIdentity<'_> {
(
self.source(),
self.destination(),
self.world_ref(),
self.endpoint(),
self.subject(),
self.slot(),
)
}
#[must_use]
pub fn is_http(&self) -> bool {
wit_shape_is_http(self.world_ref())
}
#[must_use]
pub fn is_pubsub(&self) -> bool {
wit_shape_is_pubsub(self.world_ref())
}
#[must_use]
pub fn is_store(&self) -> bool {
wit_shape_is_store(self.world_ref())
}
#[must_use]
pub fn is_self_loop(&self) -> bool {
self.source() == self.destination()
}
pub fn target(&self) -> Result<WitTarget<'_>, AplicacaoError> {
let endpoint = self.endpoint();
let subject = self.subject();
let slot = self.slot();
let edge = || self.edge_triple();
if let Err(reason) = crate::render::is_wit_world_ref(&self.wit) {
let (de, para, wit) = edge();
return Err(AplicacaoError::ContratoWitInvalid {
de,
para,
wit,
reason,
});
}
if self.is_http() {
if subject.is_some() || slot.is_some() {
let (de, para, wit) = edge();
return Err(AplicacaoError::ContratoWrongTarget {
de,
para,
wit,
expected: WitTarget::HTTP_FIELD_NAME,
});
}
let ep = endpoint.ok_or_else(|| {
let (de, para, wit) = edge();
AplicacaoError::ContratoMissingTarget {
de,
para,
wit,
expected: WitTarget::HTTP_FIELD_NAME,
}
})?;
if ep.is_empty() {
let (de, para) = self.edge_pair();
return Err(AplicacaoError::ContratoEndpointEmpty { de, para });
}
if !ep.starts_with('/') {
let (de, para) = self.edge_pair();
return Err(AplicacaoError::ContratoEndpointNotAbsolute {
de,
para,
endpoint: ep.to_string(),
});
}
if let Err(reason) = crate::render::is_gateway_api_http_path(ep) {
let (de, para) = self.edge_pair();
return Err(AplicacaoError::ContratoEndpointInvalid {
de,
para,
endpoint: ep.to_string(),
reason,
});
}
return Ok(WitTarget::Http { endpoint: ep });
}
if self.is_pubsub() {
if endpoint.is_some() || slot.is_some() {
let (de, para, wit) = edge();
return Err(AplicacaoError::ContratoWrongTarget {
de,
para,
wit,
expected: WitTarget::PUBSUB_FIELD_NAME,
});
}
let s = subject.ok_or_else(|| {
let (de, para, wit) = edge();
AplicacaoError::ContratoMissingTarget {
de,
para,
wit,
expected: WitTarget::PUBSUB_FIELD_NAME,
}
})?;
if s.is_empty() {
let (de, para) = self.edge_pair();
return Err(AplicacaoError::ContratoSubjectEmpty { de, para });
}
if let Err(reason) = crate::render::is_nats_subject(s) {
let (de, para) = self.edge_pair();
return Err(AplicacaoError::ContratoSubjectInvalid {
de,
para,
subject: s.to_string(),
reason,
});
}
return Ok(WitTarget::PubSub { subject: s });
}
if self.is_store() {
if endpoint.is_some() || subject.is_some() {
let (de, para, wit) = edge();
return Err(AplicacaoError::ContratoWrongTarget {
de,
para,
wit,
expected: WitTarget::STORE_FIELD_NAME,
});
}
let sl = slot.ok_or_else(|| {
let (de, para, wit) = edge();
AplicacaoError::ContratoMissingTarget {
de,
para,
wit,
expected: WitTarget::STORE_FIELD_NAME,
}
})?;
if sl.is_empty() {
let (de, para) = self.edge_pair();
return Err(AplicacaoError::ContratoSlotEmpty { de, para });
}
if let Err(reason) = crate::render::is_wasi_keyvalue_slot(sl) {
let (de, para) = self.edge_pair();
return Err(AplicacaoError::ContratoSlotInvalid {
de,
para,
slot: sl.to_string(),
reason,
});
}
return Ok(WitTarget::Store { slot: sl });
}
if endpoint.is_some() || subject.is_some() || slot.is_some() {
let (de, para, wit) = edge();
return Err(AplicacaoError::ContratoWrongTarget {
de,
para,
wit,
expected: WitTarget::CAPABILITY_EXPECTED,
});
}
Ok(WitTarget::Capability)
}
}
pub type ContratoIdentity<'a> = (
&'a str,
&'a str,
&'a str,
Option<&'a str>,
Option<&'a str>,
Option<&'a str>,
);
#[derive(Debug, Clone, Copy, PartialEq, Eq, gen_platform::IsVariant)]
pub enum WitTarget<'a> {
Http { endpoint: &'a str },
#[is_variant(name = "pubsub")]
PubSub { subject: &'a str },
Store { slot: &'a str },
Capability,
}
impl<'a> WitTarget<'a> {
pub const HTTP_FIELD_NAME: &'static str = "endpoint";
pub const PUBSUB_FIELD_NAME: &'static str = "subject";
pub const STORE_FIELD_NAME: &'static str = "slot";
pub const CAPABILITY_LABEL: &'static str = "(capability — no payload)";
pub const CAPABILITY_EXPECTED: &'static str = "none";
#[must_use]
pub const fn payload_pair(&self) -> Option<(&'static str, &'a str)> {
match *self {
WitTarget::Http { endpoint } => Some((Self::HTTP_FIELD_NAME, endpoint)),
WitTarget::PubSub { subject } => Some((Self::PUBSUB_FIELD_NAME, subject)),
WitTarget::Store { slot } => Some((Self::STORE_FIELD_NAME, slot)),
WitTarget::Capability => None,
}
}
#[must_use]
pub const fn field_name(&self) -> Option<&'static str> {
match self.payload_pair() {
Some((f, _)) => Some(f),
None => None,
}
}
#[must_use]
pub fn label(&self) -> String {
match self.payload_pair() {
Some((field, payload)) => format!(":{field} {payload:?}"),
None => Self::CAPABILITY_LABEL.to_string(),
}
}
}
impl std::fmt::Display for WitTarget<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&self.label())
}
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct Membro {
pub caixa: String,
pub versao: String,
}
impl Membro {
#[must_use]
pub fn nome(&self) -> &str {
self.caixa.as_str()
}
#[must_use]
pub fn versao_requirement(&self) -> &str {
self.versao.as_str()
}
}
#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct MeshPolicy {
#[serde(
default,
skip_serializing_if = "Option::is_none",
with = "supervisor::duration_codec"
)]
pub timeout: Option<Duration>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub retries: Option<u32>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub circuit_breaker: Option<CircuitBreaker>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub mtls_required: Option<bool>,
#[serde(
default,
skip_serializing_if = "Option::is_none",
with = "rate_limit_codec"
)]
pub rate_limit: Option<RateLimit>,
}
impl MeshPolicy {
#[must_use]
pub const fn is_empty(&self) -> bool {
self.timeout().is_none()
&& self.retries().is_none()
&& self.circuit_breaker().is_none()
&& self.mtls_required().is_none()
&& self.rate_limit().is_none()
}
#[must_use]
pub const fn timeout(&self) -> Option<Duration> {
self.timeout
}
#[must_use]
pub const fn retries(&self) -> Option<u32> {
self.retries
}
#[must_use]
pub const fn mtls_required(&self) -> Option<bool> {
self.mtls_required
}
#[must_use]
pub const fn rate_limit(&self) -> Option<RateLimit> {
self.rate_limit
}
#[must_use]
pub const fn circuit_breaker(&self) -> Option<CircuitBreaker> {
self.circuit_breaker
}
}
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct CircuitBreaker {
pub max_failures: u32,
#[serde(with = "supervisor::duration_codec_required")]
pub window: Duration,
}
impl CircuitBreaker {
#[must_use]
pub const fn max_failures(&self) -> u32 {
self.max_failures
}
#[must_use]
pub const fn window(&self) -> Duration {
self.window
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct RateLimit {
pub rate: u32,
pub window: Duration,
}
impl RateLimit {
#[must_use]
pub const fn rate(&self) -> u32 {
self.rate
}
#[must_use]
pub const fn window(&self) -> Duration {
self.window
}
#[must_use]
pub fn canonical_unit(&self) -> Option<RateLimitUnit> {
RateLimitUnit::from_window(self.window)
}
}
#[derive(
Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash, gen_platform::IsVariant,
)]
pub enum RateLimitUnit {
Second,
Minute,
Hour,
}
impl RateLimitUnit {
pub const ALL: &'static [Self] = &[Self::Second, Self::Minute, Self::Hour];
#[must_use]
pub const fn as_suffix(self) -> &'static str {
match self {
Self::Second => "s",
Self::Minute => "m",
Self::Hour => "h",
}
}
#[must_use]
pub const fn window(self) -> Duration {
Duration::from_secs(match self {
Self::Second => 1,
Self::Minute => 60,
Self::Hour => 3_600,
})
}
#[must_use]
pub fn from_suffix(suffix: &str) -> Option<Self> {
Self::ALL.iter().copied().find(|u| u.as_suffix() == suffix)
}
#[must_use]
pub fn from_window(window: Duration) -> Option<Self> {
if window.subsec_nanos() != 0 {
return None;
}
Self::ALL.iter().copied().find(|u| u.window() == window)
}
#[must_use]
pub fn window_from_suffix(suffix: &str) -> Option<Duration> {
Self::from_suffix(suffix).map(Self::window)
}
}
impl std::fmt::Display for RateLimitUnit {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.as_suffix())
}
}
pub const POLICY_TIMEOUT_MAX: Duration = Duration::from_secs(3600);
pub const POLICY_RETRIES_MAX: u32 = 10;
pub const POLICY_BREAKER_MAX_FAILURES_MAX: u32 = 1000;
pub const POLICY_BREAKER_WINDOW_MAX: Duration = Duration::from_secs(3600);
pub const POLICY_RATE_LIMIT_MAX: u32 = 1_000_000;
const PLACEMENT_SHARD_KEY_MAX_LEN: usize = 63;
fn validate_membro_caixa(caixa: &str) -> Result<(), AplicacaoError> {
crate::render::require_valid_dns_1123_label(
caixa,
|| AplicacaoError::MembroCaixaEmpty,
|reason| AplicacaoError::MembroCaixaInvalid {
caixa: caixa.to_string(),
reason,
},
)
}
fn validate_placement_cluster(cluster: &str) -> Result<(), AplicacaoError> {
crate::render::require_valid_dns_1123_label(
cluster,
|| AplicacaoError::PlacementClusterEmpty,
|reason| AplicacaoError::PlacementClusterInvalid {
cluster: cluster.to_string(),
reason,
},
)
}
fn validate_placement_affinity(affinity: &str) -> Result<(), AplicacaoError> {
crate::render::require_valid_dns_1123_label(
affinity,
|| AplicacaoError::PlacementAffinityEmpty,
|reason| AplicacaoError::PlacementAffinityInvalid {
affinity: affinity.to_string(),
reason,
},
)
}
fn validate_placement_shard_key(key: &str) -> Result<(), AplicacaoError> {
if key.is_empty() {
return Err(AplicacaoError::ShardedKeyEmpty);
}
if key.len() > PLACEMENT_SHARD_KEY_MAX_LEN {
return Err(AplicacaoError::ShardKeyInvalid {
shard_key: key.to_string(),
reason: format!(
"exceeds :shard-key max length of {PLACEMENT_SHARD_KEY_MAX_LEN} bytes \
(got {} bytes; realistic Akka-style entity-id extractor expressions \
— `tenantId`, `$tenantId`, `metadata.tenantId`, `${{tenant}}` — sit \
well under 32 bytes, this length suggests a paste-from-doc \
multi-line blob landed in `:shard-key` instead of a single-token \
extractor expression)",
key.len()
),
});
}
for &b in key.as_bytes() {
if (0x21..=0x7E).contains(&b) {
continue;
}
let reason = if b == b' ' {
"contains a space (Akka-style entity-id extractor expressions are \
single-token references like `tenantId` / `$tenantId` / `metadata.tenantId`; \
whitespace breaks the extractor's token boundary at the runtime layer, \
and the paste-from-aligned-doc / paste-from-CSV footgun silently lands \
a multi-token blob in one `:shard-key` slot)"
.to_string()
} else if b == b'\t' {
"contains a tab character (paste-from-aligned-doc footgun; the \
Akka-style entity-id extractor reads `:shard-key` as a single-token \
reference, embedded whitespace breaks the token boundary at the \
runtime hash-extractor pass)"
.to_string()
} else if b == b'\n' || b == b'\r' {
format!(
"contains line terminator 0x{b:02x} (paste-from-shell-heredoc / \
paste-from-multiline-doc footgun; the Akka-style entity-id \
extractor reads `:shard-key` as a single-token reference, embedded \
newlines either truncate the value at the YAML emitter layer or \
break the token boundary at the runtime hash-extractor pass)"
)
} else if b < 0x20 || b == 0x7F {
format!(
"contains control character 0x{b:02x} (the canonical \
paste-from-binary / paste-from-screen-cleared-terminal footgun; \
control characters silently corrupt round-trip serialization \
across YAML emitters and break the runtime hash-extractor's \
single-token parser)"
)
} else {
format!(
"contains non-ASCII byte 0x{b:02x} (the canonical \
paste-from-Unicode-doc footgun; non-ASCII bytes round-trip \
inconsistently across NFC/NFD normalization on APFS / ext4 / \
across YAML emitter implementations — the same entity ID can \
silently map to two distinct shards on a re-render. Use a \
printable-ASCII extractor expression like `tenantId`, \
`$tenantId`, or `metadata.tenantId`)"
)
};
return Err(AplicacaoError::ShardKeyInvalid {
shard_key: key.to_string(),
reason,
});
}
Ok(())
}
fn validate_contrato_caixa(slot: &'static str, caixa: &str) -> Result<(), AplicacaoError> {
crate::render::require_valid_dns_1123_label(
caixa,
|| AplicacaoError::ContratoCaixaEmpty { slot },
|reason| AplicacaoError::ContratoCaixaInvalid {
slot,
caixa: caixa.to_string(),
reason,
},
)
}
fn validate_entrada_para(para: &str) -> Result<(), AplicacaoError> {
crate::render::require_valid_dns_1123_label(
para,
|| AplicacaoError::EntradaParaEmpty,
|reason| AplicacaoError::EntradaParaInvalid {
para: para.to_string(),
reason,
},
)
}
fn validate_entrada_host(host: &str) -> Result<(), AplicacaoError> {
if host.is_empty() {
return Err(AplicacaoError::EmptyEntradaHost);
}
if host.len() > crate::render::GATEWAY_API_HOSTNAME_MAX_LEN {
return Err(AplicacaoError::EntradaHostInvalid {
host: host.to_string(),
reason: format!(
"exceeds Gateway API v1 Hostname max length of {cap} bytes \
(got {} bytes; the K8s apiserver rejects longer hostnames at admission time)",
host.len(),
cap = crate::render::GATEWAY_API_HOSTNAME_MAX_LEN,
),
});
}
if host.contains("://") {
return Err(AplicacaoError::EntradaHostInvalid {
host: host.to_string(),
reason: "must not carry a scheme (drop the `https://` or `http://` prefix; \
Gateway API takes the bare hostname)"
.to_string(),
});
}
if host.contains('/') {
return Err(AplicacaoError::EntradaHostInvalid {
host: host.to_string(),
reason: "must not carry a path (drop the `/…` suffix; Gateway API path \
matching is in `:entrada :paths`)"
.to_string(),
});
}
if host.contains(':') {
return Err(AplicacaoError::EntradaHostInvalid {
host: host.to_string(),
reason: "must not contain `:` (the port belongs in the `:entrada :port` \
slot — a separate `u16` axis on the same `:entrada` block, \
defaulting to 8080 — not in the host body; drop the `:<port>` \
suffix and author the bare hostname. If you intended an IPv6 \
literal (`2001:db8::1` / `::1` / `fe80::1`), Gateway API v1 \
Hostname forbids IP literals identically to the IPv4-literal \
arm — use a DNS name)"
.to_string(),
});
}
if let Some(b) = crate::render::find_ascii_whitespace_byte(host) {
return Err(AplicacaoError::EntradaHostInvalid {
host: host.to_string(),
reason: format!(
"contains ASCII whitespace byte 0x{b:02x} (Gateway API v1 \
Hostname is a single-token DNS name — leading, trailing, \
or embedded whitespace breaks the K8s apiserver's Hostname \
regex at admission time; the paste-from-aligned-doc / \
paste-from-shell-history / paste-from-CSV footgun silently \
lands a multi-token blob in `:entrada :host`. Strip every \
whitespace byte and author the bare hostname — space \
`0x20`, tab `0x09`, LF `0x0a`, FF `0x0c`, CR `0x0d` all \
refuse identically)"
),
});
}
if let Some(ch) = crate::render::find_non_ascii_whitespace_char(host) {
return Err(AplicacaoError::EntradaHostInvalid {
host: host.to_string(),
reason: format!(
"contains non-ASCII Unicode whitespace character {ch:?} \
(U+{codepoint:04X}) — Gateway API v1 Hostname is a \
single-token DNS name limited to `[a-z0-9-]` labels; \
the paste-from-typography footgun silently lands an \
invisible codepoint (NBSP `U+00A0`, LINE SEPARATOR \
`U+2028`, EM-SPACE `U+2003`, IDEOGRAPHIC SPACE \
`U+3000`, and every other member of the Unicode \
`White_Space` property outside the ASCII byte range) \
in `:entrada :host`, which the K8s apiserver's \
Hostname regex refuses at admission time far from the \
caixa.lisp source line. Strip every non-ASCII \
whitespace character and author the bare hostname \
with only ASCII bytes (write \"checkout.quero.cloud\" \
verbatim)",
codepoint = ch as u32,
),
});
}
let (had_wildcard, rest) = match host.strip_prefix("*.") {
Some(r) => (true, r),
None => (false, host),
};
if had_wildcard && rest.is_empty() {
return Err(AplicacaoError::EntradaHostInvalid {
host: host.to_string(),
reason: "wildcard `*.` must be followed by a domain (e.g. `*.example.com`)".to_string(),
});
}
if rest.contains('*') {
return Err(AplicacaoError::EntradaHostInvalid {
host: host.to_string(),
reason: "wildcard `*` is allowed only as the first label (`*.example.com`); \
no inner or trailing `*` labels"
.to_string(),
});
}
if rest.ends_with('.') {
return Err(AplicacaoError::EntradaHostInvalid {
host: host.to_string(),
reason: "must not have a trailing `.` (Gateway API hostnames are not \
fully-qualified with a root dot; the apiserver regex rejects \
trailing dots)"
.to_string(),
});
}
let labels: Vec<&str> = rest.split('.').collect();
if labels.len() == 4
&& labels
.iter()
.all(|l| !l.is_empty() && l.bytes().all(|b| b.is_ascii_digit()))
{
return Err(AplicacaoError::EntradaHostInvalid {
host: host.to_string(),
reason: "must not be an IPv4 literal (Gateway API v1 Hostname forbids IP \
literals; use a DNS name)"
.to_string(),
});
}
for label in &labels {
if label.is_empty() {
return Err(AplicacaoError::EntradaHostInvalid {
host: host.to_string(),
reason: "has an empty label (consecutive `..` or a leading `.`)".to_string(),
});
}
if label.len() > crate::render::DNS_1123_LABEL_MAX_LEN {
return Err(AplicacaoError::EntradaHostInvalid {
host: host.to_string(),
reason: format!(
"label {label:?} exceeds DNS-1123 label max length of \
{cap} bytes (got {} bytes)",
label.len(),
cap = crate::render::DNS_1123_LABEL_MAX_LEN,
),
});
}
let bytes = label.as_bytes();
if !bytes[0].is_ascii_alphanumeric() || !bytes[bytes.len() - 1].is_ascii_alphanumeric() {
return Err(AplicacaoError::EntradaHostInvalid {
host: host.to_string(),
reason: format!(
"label {label:?} must start and end with an alphanumeric \
(no leading or trailing `-`)"
),
});
}
for &b in bytes {
let valid = b.is_ascii_digit() || b.is_ascii_lowercase() || b == b'-';
if !valid {
let msg = if b.is_ascii_uppercase() {
format!(
"label {label:?} contains uppercase character {ch:?} \
(Gateway API hostnames are lowercase-only; use {lower:?})",
ch = b as char,
lower = label.to_ascii_lowercase()
)
} else if b == b'_' {
format!(
"label {label:?} contains `_` (Gateway API hostnames \
allow only `[a-z0-9-]`; use `-` instead)"
)
} else {
format!(
"label {label:?} contains invalid character {ch:?} \
(Gateway API hostnames allow only `[a-z0-9-]`)",
ch = b as char
)
};
return Err(AplicacaoError::EntradaHostInvalid {
host: host.to_string(),
reason: msg,
});
}
}
}
Ok(())
}
fn validate_entrada_path(path: &str) -> Result<(), AplicacaoError> {
if path.is_empty() {
return Err(AplicacaoError::EntradaPathEmpty);
}
if !path.starts_with('/') {
return Err(AplicacaoError::EntradaPathNotAbsolute {
path: path.to_string(),
});
}
crate::render::is_gateway_api_http_path(path).map_err(|reason| {
AplicacaoError::EntradaPathInvalid {
path: path.to_string(),
reason,
}
})
}
mod rate_limit_codec {
use super::{RateLimit, RateLimitUnit};
use serde::{Deserialize, Deserializer, Serializer};
pub fn serialize<S: Serializer>(v: &Option<RateLimit>, s: S) -> Result<S::Ok, S::Error> {
match v {
Some(rl) => s.serialize_str(&render(*rl)),
None => s.serialize_none(),
}
}
pub fn deserialize<'de, D: Deserializer<'de>>(d: D) -> Result<Option<RateLimit>, D::Error> {
let opt: Option<String> = Option::deserialize(d)?;
match opt {
None => Ok(None),
Some(s) => parse(&s).map(Some).map_err(serde::de::Error::custom),
}
}
fn parse(s: &str) -> Result<RateLimit, String> {
if let Some(b) = crate::render::find_ascii_whitespace_byte(s) {
return Err(format!(
"rate-limit: value {s:?} contains whitespace byte 0x{b:02x} — the canonical \
authoring form for `:politicas :rate-limit` is `<integer>/<s|m|h>` (e.g. \
`\"100/s\"`, `\"5000/m\"`, `\"10000/h\"`) with no whitespace bytes \
anywhere. A whitespace-carrying shape (`\" 100/s\"`, `\"100/s \"`, \
`\"100 /s\"`, `\"100/ s\"`, `\"100 / s\"`, `\"100/s\\n\"`, `\"\\t100/s\"`) \
round-trips through `render` to a *different* canonical form (`\"100/s\"`) \
on first serialize — breaking the THEORY.md Part V render-determinism \
contract every typed slot carries. Strip every whitespace byte (write \
`\"100/s\"` verbatim)"
));
}
if let Some(ch) = crate::render::find_non_ascii_whitespace_char(s) {
return Err(format!(
"rate-limit: value {s:?} contains non-ASCII Unicode whitespace character \
{ch:?} (U+{cp:04X}) — the canonical authoring form for `:politicas \
:rate-limit` is `<integer>/<s|m|h>` (e.g. `\"100/s\"`, `\"5000/m\"`, \
`\"10000/h\"`) with no whitespace characters anywhere (ASCII or Unicode). \
A non-ASCII-whitespace-carrying shape (`\"\\u{{00A0}}100/s\"`, \
`\"100/s\\u{{2028}}\"`, `\"100\\u{{2003}}/s\"`) survives the ASCII \
byte-scan but `str::trim` (which uses `char::is_whitespace` — the \
Unicode `White_Space` property, strictly wider than the ASCII byte set) \
silently strips it at parse entry, and the value round-trips through \
`render` to a *different* canonical form (`\"100/s\"`) on first \
serialize — breaking the THEORY.md Part V render-determinism contract \
every typed slot carries. Strip every non-ASCII whitespace character \
(write `\"100/s\"` verbatim with only ASCII bytes)",
cp = ch as u32
));
}
let s = s.trim();
let (rate_str, unit) = s
.split_once('/')
.ok_or_else(|| format!("rate-limit must be `<n>/<unit>`, got {s:?}"))?;
let rate_trim = rate_str.trim();
let digit_only = crate::render::is_digit_only_magnitude(rate_trim);
if !digit_only {
let numeric = rate_trim.parse::<f64>().is_ok() || rate_trim.parse::<i64>().is_ok();
if numeric {
return Err(format!(
"rate-limit: rate {rate_trim:?} is not a non-negative integer — the \
canonical authoring form for `:politicas :rate-limit` is \
`<integer>/<s|m|h>` (e.g. `\"100/s\"`, `\"5000/m\"`, `\"10000/h\"`) \
with no decimal point and no leading `+` / `-` sign. A fractional / \
signed magnitude (`\"1.5/s\"`, `\"+100/s\"`, `\"-1/s\"`) round-trips \
through `render` to a *different* canonical form (`\"1/s\"`, \
`\"100/s\"`, parser-reject) on first serialize — breaking the \
THEORY.md Part V render-determinism contract every typed slot \
carries. Pick an integer rate that fits the desired window \
(write `\"6000/m\"` instead of `\"1.66/s\"`)"
));
}
return Err(format!("rate-limit rate {rate_str:?} not a u32"));
}
if crate::render::is_leading_zero_padded_magnitude(rate_trim) {
return Err(format!(
"rate-limit: rate {rate_trim:?} has a non-canonical leading zero — the \
canonical authoring form for `:politicas :rate-limit` is \
`<integer>/<s|m|h>` (e.g. `\"100/s\"`, `\"5000/m\"`, `\"10000/h\"`) \
with no leading-zero padding on the magnitude. A leading-zero magnitude \
(`\"0100/s\"`, `\"00/s\"`, `\"007/h\"`) round-trips through `render` to \
a *different* canonical form (`\"100/s\"`, `\"0/s\"`, `\"7/h\"`) on \
first serialize — breaking the THEORY.md Part V render-determinism \
contract every typed slot carries. Strip the leading zeros (write \
`\"100/s\"` instead of `\"0100/s\"`)"
));
}
let rate: u32 = rate_trim.parse::<u32>().map_err(|_| {
format!("rate-limit rate {rate_trim:?} (digit-only magnitude overflows u32)")
})?;
let unit = unit.trim();
let window = RateLimitUnit::window_from_suffix(unit)
.ok_or_else(|| format!("unknown rate-limit window unit {unit:?}"))?;
Ok(RateLimit { rate, window })
}
fn render(rl: RateLimit) -> String {
if let Some(unit) = rl.canonical_unit() {
format!("{}/{unit}", rl.rate())
} else {
format!("{}/{}s", rl.rate(), rl.window().as_secs())
}
}
}
#[derive(
Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash, gen_platform::IsVariant,
)]
pub enum PlacementStrategy {
SingleNode,
Replicated,
Sharded,
}
impl Default for PlacementStrategy {
fn default() -> Self {
Self::Replicated
}
}
impl PlacementStrategy {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::SingleNode => crate::render::M3_PLACEMENT_ESTRATEGIA_SINGLE_NODE,
Self::Replicated => crate::render::M3_PLACEMENT_ESTRATEGIA_REPLICATED,
Self::Sharded => crate::render::M3_PLACEMENT_ESTRATEGIA_SHARDED,
}
}
}
impl std::fmt::Display for PlacementStrategy {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.as_str())
}
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct Placement {
#[serde(default)]
pub estrategia: PlacementStrategy,
#[serde(default)]
pub clusters: Vec<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub affinity: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub shard_key: Option<String>,
}
impl Placement {
#[must_use]
pub fn shard_key(&self) -> Option<&str> {
self.shard_key.as_deref()
}
#[must_use]
pub fn affinity(&self) -> Option<&str> {
self.affinity.as_deref()
}
#[must_use]
pub fn estrategia(&self) -> PlacementStrategy {
self.estrategia
}
#[must_use]
pub fn clusters(&self) -> &[String] {
self.clusters.as_slice()
}
}
impl Default for Placement {
fn default() -> Self {
Self {
estrategia: PlacementStrategy::default(),
clusters: Vec::new(),
affinity: None,
shard_key: None,
}
}
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct Entrada {
pub host: String,
pub para: String,
#[serde(default)]
pub paths: Vec<String>,
#[serde(default = "default_port")]
pub port: u16,
}
impl Entrada {
#[must_use]
pub fn resolved_paths(&self) -> Vec<&str> {
if self.paths().is_empty() {
vec![crate::render::GATEWAY_API_DEFAULT_HTTP_ROUTE_PATH]
} else {
self.paths().iter().map(String::as_str).collect()
}
}
#[must_use]
pub fn hostname(&self) -> &str {
self.host.as_str()
}
#[must_use]
pub fn hostnames(&self) -> Vec<&str> {
vec![self.hostname()]
}
#[must_use]
pub fn destination(&self) -> &str {
self.para.as_str()
}
#[must_use]
pub fn port(&self) -> u16 {
self.port
}
#[must_use]
pub fn paths(&self) -> &[String] {
self.paths.as_slice()
}
}
pub const DEFAULT_SERVICO_PORT: u16 = 8080;
pub const SERVICO_PORT_MIN: u16 = 1;
const fn default_port() -> u16 {
DEFAULT_SERVICO_PORT
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct AplicacaoSpec {
pub membros: Vec<Membro>,
pub contratos: Vec<WitContract>,
pub politicas: MeshPolicy,
pub placement: Placement,
pub entrada: Option<Entrada>,
}
impl AplicacaoSpec {
#[must_use]
pub fn membros(&self) -> &[Membro] {
self.membros.as_slice()
}
#[must_use]
pub fn contratos(&self) -> &[WitContract] {
self.contratos.as_slice()
}
#[must_use]
pub fn politicas(&self) -> &MeshPolicy {
&self.politicas
}
#[must_use]
pub fn placement(&self) -> &Placement {
&self.placement
}
#[must_use]
pub fn entrada(&self) -> Option<&Entrada> {
self.entrada.as_ref()
}
pub fn validate(&self) -> Result<(), AplicacaoError> {
self.validate_membros()?;
let names: std::collections::HashSet<&str> =
self.membros().iter().map(Membro::nome).collect();
let mut seen_contracts: std::collections::HashSet<ContratoIdentity<'_>> =
std::collections::HashSet::new();
for c in self.contratos() {
validate_contrato_caixa(crate::render::CONTRATO_AUTHOR_KEY_DE, c.source())?;
validate_contrato_caixa(crate::render::CONTRATO_AUTHOR_KEY_PARA, c.destination())?;
if !names.contains(c.source()) {
return Err(AplicacaoError::ContratoMemberMissing {
caixa: c.source().to_string(),
});
}
if !names.contains(c.destination()) {
return Err(AplicacaoError::ContratoMemberMissing {
caixa: c.destination().to_string(),
});
}
if c.is_self_loop() {
return Err(AplicacaoError::ContratoSelfLoop {
caixa: c.source().to_string(),
wit: c.world_ref().to_string(),
});
}
if c.world_ref().is_empty() {
let (de, para) = c.edge_pair();
return Err(AplicacaoError::EmptyWit { de, para });
}
let target_view = c.target()?;
let key = c.identity();
crate::render::insert_first_seen(&mut seen_contracts, key, || {
let (de, para, wit) = c.edge_triple();
AplicacaoError::ContratoDuplicate {
de,
para,
wit,
target: target_view.label(),
}
})?;
}
self.detect_sync_cycles()?;
if let Some(e) = self.entrada() {
validate_entrada_para(e.destination())?;
if !names.contains(e.destination()) {
return Err(AplicacaoError::EntradaMemberMissing {
para: e.destination().to_string(),
});
}
if e.hostname().is_empty() {
return Err(AplicacaoError::EmptyEntradaHost);
}
validate_entrada_host(e.hostname())?;
if e.port() < SERVICO_PORT_MIN {
return Err(AplicacaoError::EntradaPortZero);
}
let mut seen = std::collections::HashSet::new();
for p in e.paths() {
if p.is_empty() {
return Err(AplicacaoError::EntradaPathEmpty);
}
if !p.starts_with('/') {
return Err(AplicacaoError::EntradaPathNotAbsolute { path: p.clone() });
}
validate_entrada_path(p)?;
crate::render::insert_first_seen(&mut seen, p.as_str(), || {
AplicacaoError::EntradaPathDuplicate { path: p.clone() }
})?;
}
}
self.validate_placement()?;
self.validate_politicas()?;
Ok(())
}
fn validate_membros(&self) -> Result<(), AplicacaoError> {
if self.membros().is_empty() {
return Err(AplicacaoError::NoMembros);
}
let mut seen = std::collections::HashSet::new();
for m in self.membros() {
if m.nome().is_empty() {
return Err(AplicacaoError::MembroCaixaEmpty);
}
validate_membro_caixa(m.nome())?;
crate::render::require_valid_versao_requirement(
m.versao_requirement(),
|| AplicacaoError::MembroVersaoEmpty {
caixa: m.nome().to_string(),
},
|reason| AplicacaoError::MembroVersaoInvalid {
caixa: m.nome().to_string(),
versao: m.versao_requirement().to_string(),
reason,
},
)?;
crate::render::insert_first_seen(&mut seen, m.nome(), || {
AplicacaoError::MembroDuplicate {
caixa: m.nome().to_string(),
}
})?;
}
Ok(())
}
fn validate_placement(&self) -> Result<(), AplicacaoError> {
let p = self.placement();
if p.clusters().is_empty() {
return Err(AplicacaoError::PlacementWithoutClusters {
estrategia: p.estrategia(),
});
}
let mut seen = std::collections::HashSet::new();
for c in p.clusters() {
validate_placement_cluster(c)?;
crate::render::insert_first_seen(&mut seen, c.as_str(), || {
AplicacaoError::PlacementClusterDuplicate { cluster: c.clone() }
})?;
}
if let Some(a) = p.affinity() {
validate_placement_affinity(a)?;
}
match p.estrategia() {
PlacementStrategy::Sharded => match p.shard_key() {
None => return Err(AplicacaoError::ShardedWithoutKey),
Some(k) if k.is_empty() => return Err(AplicacaoError::ShardedKeyEmpty),
Some(k) => validate_placement_shard_key(k)?,
},
PlacementStrategy::Replicated | PlacementStrategy::SingleNode => {
if let Some(k) = p.shard_key() {
return Err(AplicacaoError::ShardKeyOnNonSharded {
estrategia: p.estrategia(),
shard_key: k.to_string(),
});
}
}
}
Ok(())
}
fn validate_politicas(&self) -> Result<(), AplicacaoError> {
let p = self.politicas();
if let Some(t) = p.timeout() {
crate::render::require_positive_canonical_bounded_duration(
t,
POLICY_TIMEOUT_MAX,
|| AplicacaoError::PolicyTimeoutZero,
|timeout| AplicacaoError::PolicyTimeoutNotCanonical { timeout },
|timeout| AplicacaoError::PolicyTimeoutExceedsCap { timeout },
)?;
}
if let Some(r) = p.retries() {
crate::render::require_positive_bounded_u32(
r,
POLICY_RETRIES_MAX,
|| AplicacaoError::PolicyRetriesZero,
|retries| AplicacaoError::PolicyRetriesExceedsCap { retries },
)?;
}
if let Some(cb) = p.circuit_breaker() {
crate::render::require_positive_bounded_u32(
cb.max_failures(),
POLICY_BREAKER_MAX_FAILURES_MAX,
|| AplicacaoError::PolicyBreakerZeroFailures,
|max_failures| AplicacaoError::PolicyBreakerMaxFailuresExceedsCap { max_failures },
)?;
crate::render::require_positive_canonical_bounded_duration(
cb.window(),
POLICY_BREAKER_WINDOW_MAX,
|| AplicacaoError::PolicyBreakerZeroWindow,
|window| AplicacaoError::PolicyBreakerWindowNotCanonical { window },
|window| AplicacaoError::PolicyBreakerWindowExceedsCap { window },
)?;
}
if let Some(rl) = p.rate_limit() {
crate::render::require_positive_bounded_u32(
rl.rate(),
POLICY_RATE_LIMIT_MAX,
|| AplicacaoError::PolicyRateLimitZero,
|rate| AplicacaoError::PolicyRateLimitExceedsCap { rate },
)?;
if rl.canonical_unit().is_none() {
return Err(AplicacaoError::PolicyRateLimitWindowNotCanonical {
window: rl.window(),
});
}
}
Ok(())
}
fn detect_sync_cycles(&self) -> Result<(), AplicacaoError> {
use std::collections::{BTreeMap, BTreeSet};
#[derive(Clone, Copy, PartialEq, Eq)]
enum Mark {
White,
Gray,
Black,
}
let mut adj: BTreeMap<&str, BTreeSet<&str>> = BTreeMap::new();
for m in self.membros() {
adj.entry(m.nome()).or_default();
}
for c in self.contratos() {
if c.target()?.is_pubsub() {
continue;
}
adj.entry(c.source()).or_default().insert(c.destination());
}
let mut color: BTreeMap<&str, Mark> = adj.keys().map(|k| (*k, Mark::White)).collect();
let mut parent: BTreeMap<&str, &str> = BTreeMap::new();
let roots: Vec<&str> = adj.keys().copied().collect();
for root in roots {
if color.get(root).copied().unwrap_or(Mark::White) != Mark::White {
continue;
}
let root_neighbors: Vec<&str> = adj
.get(root)
.map(|s| s.iter().copied().collect())
.unwrap_or_default();
let mut stack: Vec<(&str, Vec<&str>, usize)> = vec![(root, root_neighbors, 0)];
color.insert(root, Mark::Gray);
loop {
let step: Option<(&str, Option<&str>)> = stack.last_mut().map(|top| {
let node = top.0;
if top.2 >= top.1.len() {
(node, None)
} else {
let nxt = top.1[top.2];
top.2 += 1;
(node, Some(nxt))
}
});
let Some((node, nxt_opt)) = step else { break };
let Some(nxt) = nxt_opt else {
color.insert(node, Mark::Black);
stack.pop();
continue;
};
let nxt_color = color.get(nxt).copied().unwrap_or(Mark::White);
match nxt_color {
Mark::Gray => {
let mut cycle = Vec::new();
let mut cur = node;
cycle.push(cur.to_string());
while cur != nxt {
match parent.get(cur).copied() {
Some(p) => {
cur = p;
cycle.push(cur.to_string());
}
None => break,
}
}
cycle.reverse();
cycle.push(nxt.to_string());
return Err(AplicacaoError::ContratoCycle { cycle });
}
Mark::White => {
parent.insert(nxt, node);
color.insert(nxt, Mark::Gray);
let nxt_neighbors: Vec<&str> = adj
.get(nxt)
.map(|s| s.iter().copied().collect())
.unwrap_or_default();
stack.push((nxt, nxt_neighbors, 0));
}
Mark::Black => {}
}
}
}
Ok(())
}
#[must_use]
pub fn port_for_destination(&self, destination: &str) -> u16 {
self.entrada()
.filter(|e| e.destination() == destination)
.map_or(DEFAULT_SERVICO_PORT, Entrada::port)
}
}
pub fn validate_no_self_membership(
membros: &[Membro],
parent_nome: &str,
) -> Result<(), AplicacaoError> {
for m in membros {
if m.nome() == parent_nome {
return Err(AplicacaoError::MembroIsSelfAplicacao {
caixa: parent_nome.to_string(),
});
}
}
Ok(())
}
#[derive(Debug, Error, PartialEq, Eq)]
pub enum AplicacaoError {
#[error("Aplicacao must declare at least one :membros entry")]
NoMembros,
#[error(
":membros entry has empty :caixa (every member must name a Servico; \
omit the entry instead of carrying an empty name)"
)]
MembroCaixaEmpty,
#[error(
":membros entry :caixa {caixa:?} is not a valid DNS-1123 label: {reason} \
(the K8s apiserver enforces this rule on every `metadata.name` / Service \
name / label value the member name lands in; use a lowercase \
alphanumeric + hyphen identifier like `\"checkout\"` or `\"cart-v2\"`)"
)]
MembroCaixaInvalid { caixa: String, reason: String },
#[error(
":membros entry {caixa:?} has empty :versao (every member must pin a \
semver constraint that resolves through the lacre pipeline)"
)]
MembroVersaoEmpty { caixa: String },
#[error(
":membros entry {caixa:?} :versao {versao:?} is not a valid semver \
requirement: {reason} (use Cargo-shaped forms like `\"^0.1\"`, \
`\"~0.1.2\"`, `\"0.1.0\"`, or `\"*\"` — the same shape `:deps :versao` \
carries; the lacre pipeline resolves both through the same parser)"
)]
MembroVersaoInvalid {
caixa: String,
versao: String,
reason: String,
},
#[error(
":membros entry {caixa:?} appears more than once (the graph node set \
is a set, not a multiset; duplicate members produce duplicate \
programs.yaml entries and ambiguous :contratos membership lookups)"
)]
MembroDuplicate { caixa: String },
#[error(
"aplicacao {caixa:?} lists itself as a :membros entry — an Aplicacao is \
never its own constituent Servico (the application graph is a DAG rooted \
at the Aplicacao; :membros names the *other* caixas that compose the \
app, not the app itself). Since every :nome is a globally-unique \
substrate identity, a member naming the Aplicacao's own :nome is a \
one-node lacre-closure recursion, not a coincidentally-named peer; \
drop the self-referential :membros entry or rename it to the actual \
constituent caixa."
)]
MembroIsSelfAplicacao { caixa: String },
#[error(
"contrato {slot} is empty (every :contratos entry's :de and :para must name a \
caixa declared in :membros; omit the contract or fill the {slot} field with a \
member name)"
)]
ContratoCaixaEmpty { slot: &'static str },
#[error(
"contrato {slot} {caixa:?} is not a valid DNS-1123 label: {reason} (every \
:contratos {slot} value names a member of :membros, which is itself a \
DNS-1123 label per the K8s apiserver's `metadata.name` rule on every \
object the member name lands in — Service, Pod, identity-based Cilium \
selector; use a lowercase alphanumeric + hyphen identifier like \
`\"checkout\"` or `\"cart-v2\"`)"
)]
ContratoCaixaInvalid {
slot: &'static str,
caixa: String,
reason: String,
},
#[error("contrato references caixa {caixa:?} not declared in :membros")]
ContratoMemberMissing { caixa: String },
#[error(
"contrato {caixa:?} → {caixa:?} (:wit {wit:?}) is a self-edge — a :contratos \
entry is an inter-Servico contract whose :de and :para must name distinct \
:membros; a Servico's calls to itself are in-process, not mesh edges (drop \
the contract, or point :para at the member it actually calls)"
)]
ContratoSelfLoop { caixa: String, wit: String },
#[error("contrato {de:?} → {para:?} has empty :wit")]
EmptyWit { de: String, para: String },
#[error(
"contrato {de:?} → {para:?} :wit {wit:?} is not a valid WIT world reference: \
{reason} (the substrate dispatches `:wit` values on the canonical \
lowercase `<namespace>:<package>(/<interface>)?(@<version>)?` shape — \
`wasi:http/proxy`, `nats:pub-sub`, `wasi:keyvalue/store` — and silently \
demotes unmatched shapes to a capability-only L4 edge; use a lowercase \
kebab-case identifier per segment)"
)]
ContratoWitInvalid {
de: String,
para: String,
wit: String,
reason: String,
},
#[error(
":entrada :para is empty (every :entrada must route to a caixa declared in \
:membros; fill the :para field with a member name)"
)]
EntradaParaEmpty,
#[error(
":entrada :para {para:?} is not a valid DNS-1123 label: {reason} (every \
:entrada :para value names a member of :membros, which is itself a DNS-1123 \
label per the K8s apiserver's `metadata.name` rule on every object the \
member name lands in — Service backendRefs, HTTPRoute spec, identity-based \
Cilium selector; use a lowercase alphanumeric + hyphen identifier like \
`\"checkout\"` or `\"cart-v2\"`)"
)]
EntradaParaInvalid { para: String, reason: String },
#[error(":entrada routes to caixa {para:?} not declared in :membros")]
EntradaMemberMissing { para: String },
#[error(":entrada must declare a non-empty :host")]
EmptyEntradaHost,
#[error(
":entrada :host {host:?} is not a valid Gateway API v1 Hostname: {reason} \
(the K8s apiserver enforces the same shape on Gateway `Listener.hostname` and \
`HTTPRoute.spec.hostnames` at admission time; use a lowercase RFC 1123 DNS name \
like `\"checkout.quero.cloud\"` or `\"*.quero.cloud\"`)"
)]
EntradaHostInvalid { host: String, reason: String },
#[error(":entrada :port must be in 1..=65535, got 0")]
EntradaPortZero,
#[error(":entrada :paths entry is empty (use the empty list to match all)")]
EntradaPathEmpty,
#[error(
":entrada :paths entry {path:?} must start with `/` (Gateway API PathPrefix invariant)"
)]
EntradaPathNotAbsolute { path: String },
#[error(
":entrada :paths entry {path:?} is not a valid Gateway API v1 HTTPPathMatch \
value: {reason} (the K8s apiserver enforces the same shape on \
`HTTPRoute.spec.rules[].matches[].path.value` at admission time; use a \
single-`/`-prefixed printable-ASCII path like `\"/api/cart\"` — RFC 3986 \
requires percent-encoding `%XX` for non-ASCII and whitespace)"
)]
EntradaPathInvalid { path: String, reason: String },
#[error(":entrada :paths entry {path:?} appears more than once")]
EntradaPathDuplicate { path: String },
#[error(
":placement {estrategia} requires at least one :clusters entry \
(Replicated/SingleNode: hosting/takeover candidates; Sharded: shard pool)"
)]
PlacementWithoutClusters { estrategia: PlacementStrategy },
#[error(":placement :clusters entry is empty (cluster names must be non-empty)")]
PlacementClusterEmpty,
#[error(
":placement :clusters entry {cluster:?} is not a valid DNS-1123 label: {reason} \
(cluster names land in the K8s context keying every per-cluster `kubeconfig`, \
in the `lareira-fleet-programs` aggregator's `clusters[]` filter, and in the \
future M4 cross-cluster fan-out's per-entry namespace prefix / cluster identity \
— each enforces the DNS-1123 label rule; use a lowercase alphanumeric + hyphen \
identifier like `\"rio\"` or `\"mar-east\"`)"
)]
PlacementClusterInvalid { cluster: String, reason: String },
#[error(":placement :clusters entry {cluster:?} appears more than once")]
PlacementClusterDuplicate { cluster: String },
#[error(
":placement :affinity must be non-empty when set (omit :affinity to express \
`no placement hint`)"
)]
PlacementAffinityEmpty,
#[error(
":placement :affinity {affinity:?} is not a valid DNS-1123 label: {reason} \
(placement hints land verbatim in the M3 Adaptive compression overlay's \
`placement.affinity` field and in every future M4 placement-engine routing \
axis keying off the hint as a K8s `app.pleme.io/affinity-hint=<value>` label \
selector — both enforce the DNS-1123 label rule on admission; use a \
lowercase alphanumeric + hyphen hint like `\"data-locality\"`, \
`\"low-latency\"`, or `\"anti-affinity\"`)"
)]
PlacementAffinityInvalid { affinity: String, reason: String },
#[error(":placement Sharded requires :shard-key")]
ShardedWithoutKey,
#[error(
":placement Sharded :shard-key must be non-empty (a `Some(\"\")` shard key \
hashes every entity onto the same shard, defeating sharding entirely)"
)]
ShardedKeyEmpty,
#[error(
":placement Sharded :shard-key {shard_key:?} is not a valid Akka-style \
entity-id extractor expression: {reason} (the future M4 Akka-style \
cluster-sharding reconciler — MESH-COMPOSITION §II.4 — reads `:shard-key` \
as a single-token property reference and hashes the extracted entity ID \
to compute shard placement; use a printable-ASCII extractor expression \
like `\"tenantId\"`, `\"$tenantId\"`, `\"metadata.tenantId\"`, or \
`\"${{tenant}}\"`)"
)]
ShardKeyInvalid { shard_key: String, reason: String },
#[error(
":placement {estrategia} carries :shard-key {shard_key:?} — only :estrategia \
Sharded consumes :shard-key (hash-keyed entity distribution, Akka cluster-sharding \
convention); :estrategia Replicated runs every cluster active-active and \
:estrategia SingleNode takes over a single cluster at a time (Erlang/OTP \
distributed-app convention) — both ignore the slot. Drop :shard-key, or switch \
to :estrategia Sharded if hash-keyed routing is the intent"
)]
ShardKeyOnNonSharded {
estrategia: PlacementStrategy,
shard_key: String,
},
#[error("contrato {de:?} → {para:?} (:wit {wit:?}) is missing required `:{expected}` field")]
ContratoMissingTarget {
de: String,
para: String,
wit: String,
expected: &'static str,
},
#[error(
"contrato {de:?} → {para:?} (:wit {wit:?}) carries the wrong target field — \
expected `:{expected}` only"
)]
ContratoWrongTarget {
de: String,
para: String,
wit: String,
expected: &'static str,
},
#[error(
"HTTP contrato {de:?} → {para:?} :endpoint is empty (use a non-empty path \
like `/charge`; an empty endpoint renders as a `path: \"\"` Cilium L7 rule \
that matches no traffic and silently drops every request)"
)]
ContratoEndpointEmpty { de: String, para: String },
#[error(
"HTTP contrato {de:?} → {para:?} :endpoint {endpoint:?} must start with `/` \
(Cilium L7 :path + Gateway API PathPrefix invariant — same shape required of \
:entrada :paths)"
)]
ContratoEndpointNotAbsolute {
de: String,
para: String,
endpoint: String,
},
#[error(
"HTTP contrato {de:?} → {para:?} :endpoint {endpoint:?} is not a valid \
Cilium L7 `path:` / Gateway API v1 HTTPPathMatch value: {reason} (caixa-mesh \
emits the :endpoint verbatim as the Cilium L7 `path:` rule at \
caixa-mesh/src/lib.rs:311; the K8s apiserver enforces the same HTTPPathMatch \
shape on `:entrada :paths`. Use a single-`/`-prefixed printable-ASCII path \
like `\"/charge\"` — RFC 3986 requires percent-encoding `%XX` for non-ASCII \
and whitespace)"
)]
ContratoEndpointInvalid {
de: String,
para: String,
endpoint: String,
reason: String,
},
#[error(
"pub-sub contrato {de:?} → {para:?} :subject is empty (publish without a \
subject is a no-op subscribe; omit :subject only if the WIT world is not \
pub-sub-shaped)"
)]
ContratoSubjectEmpty { de: String, para: String },
#[error(
"pub-sub contrato {de:?} → {para:?} :subject {subject:?} is not a valid \
NATS subject: {reason} (the NATS server's subject parser enforces the \
same shape — `.`-separated tokens of `[A-Za-z0-9_-]`, with the `*` \
single-token and `>` multi-token wildcards — at publish/subscribe time; \
use a token-by-token form like `\"checkout.events.charge.failed\"` or \
`\"orders.*.completed\"` — a malformed subject silently drops every \
message at runtime far from the source caixa.lisp)"
)]
ContratoSubjectInvalid {
de: String,
para: String,
subject: String,
reason: String,
},
#[error(
"store contrato {de:?} → {para:?} :slot is empty (an empty slot template \
addresses the bucket root, defeating the per-key isolation the slot exists \
for; omit :slot only if the WIT world is not store-shaped)"
)]
ContratoSlotEmpty { de: String, para: String },
#[error(
"store contrato {de:?} → {para:?} :slot {slot:?} is not a valid \
WASI keyvalue store slot template: {reason} (the substrate enforces \
the printable-ASCII intersection-floor every kv backend admits — \
use a single-token path / template expression like `\"checkout/$orderId\"`, \
`\"users:{{tenant}}/{{id}}\"`, or `\"session.tokens.<sid>\"`; RFC 3986 requires \
percent-encoding `%XX` for non-ASCII and whitespace — a malformed \
slot either gets rejected on write by strict backends or silently \
corrupts the next read on permissive ones, far from the source caixa.lisp)"
)]
ContratoSlotInvalid {
de: String,
para: String,
slot: String,
reason: String,
},
#[error(
"synchronous :contratos form a cycle ({}); break with a NATS pub-sub edge \
or an event-sourced indirection (MESH-COMPOSITION §III.3)",
cycle.join(" → ")
)]
ContratoCycle { cycle: Vec<String> },
#[error(
":contratos entry {de:?} → {para:?} (:wit {wit:?} {target}) appears more \
than once (the typed graph edges are a set, not a multiset; duplicate \
contracts would render as colliding `CiliumNetworkPolicy` `metadata.name` \
values that K8s admission rejects far from the source caixa.lisp)"
)]
ContratoDuplicate {
de: String,
para: String,
wit: String,
target: String,
},
#[error(
":politicas :timeout must be > 0 (Envoy interprets a zero timeout as `infinite`, \
contradicting MESH-COMPOSITION §V `no infinite blocking`); omit :timeout to \
express `no per-call deadline on this axis`"
)]
PolicyTimeoutZero,
#[error(
":politicas :retries must be > 0 when set; omit :retries to express \
`no retries on transient failure`"
)]
PolicyRetriesZero,
#[error(
":politicas :retries ({retries}) exceeds the mesh-policy ceiling \
(POLICY_RETRIES_MAX = 10) — a value above this cap turns the typed \
retry policy into a thundering-herd amplification vector on transient \
failure (one caller request fans out to `(retries+1)^depth` server-side \
calls across the synchronous-:contratos subgraph), exactly the failure \
mode AWS App Mesh's `maxRetries ≤ 10` schema cap exists to prevent. \
Pin a value in 1..=10 (Envoy / Istio production playbooks recommend ≤ 5) \
or omit :retries to disable retries entirely"
)]
PolicyRetriesExceedsCap { retries: u32 },
#[error(
":politicas :circuit-breaker :max-failures must be > 0 (a zero-threshold \
breaker trips on the first call); omit :circuit-breaker to disable it"
)]
PolicyBreakerZeroFailures,
#[error(
":politicas :circuit-breaker :max-failures ({max_failures}) exceeds the \
mesh-policy ceiling (POLICY_BREAKER_MAX_FAILURES_MAX = 1000) — a value \
above this cap turns the typed breaker policy into a no-op: the trip \
threshold is structurally so high that no realistic failures-per-:window \
traffic shape can reach it, so the breaker never trips and every typed-slot \
consumer (the future CiliumClusterwideEnvoyConfig per-:politicas overlay, \
Envoy's outlier_detection.consecutive_5xx) emits a protection that is \
structurally never enforced. Pin a value in 1..=1000 (Hystrix / Istio / \
Envoy / Polly / Resilience4j production playbooks recommend 5..=50) or \
omit :circuit-breaker to disable the breaker entirely"
)]
PolicyBreakerMaxFailuresExceedsCap { max_failures: u32 },
#[error(
":politicas :circuit-breaker :window must be > 0 (a zero-window breaker \
tracks no failures); omit :circuit-breaker to disable it"
)]
PolicyBreakerZeroWindow,
#[error(
":politicas :rate-limit rate must be > 0 (a zero-rate limit denies every \
request); omit :rate-limit to disable rate limiting"
)]
PolicyRateLimitZero,
#[error(
":politicas :rate-limit rate ({rate}) exceeds the mesh-policy ceiling \
(POLICY_RATE_LIMIT_MAX = 1000000) — a value above this cap turns the typed \
rate-limit policy into a no-op limiter: the token-bucket capacity is \
structurally so high that no realistic per-edge traffic shape can drain it, \
so the limiter never trips and every typed-slot consumer (the future \
CiliumClusterwideEnvoyConfig per-:politicas overlay, Envoy's \
local_rate_limit.token_bucket.max_tokens) emits a rate-limit declaration \
that is structurally never enforced. Pin a value in 1..=1000000 (Envoy / \
Istio / Kong / NGINX production playbooks recommend 10..=10000 RPS; \
Cloudflare / AWS API Gateway typical 10000..=100000 per-minute; \
Cloudflare Enterprise rate-plans run to ~1M per-hour) or omit :rate-limit \
to disable rate limiting entirely"
)]
PolicyRateLimitExceedsCap { rate: u32 },
#[error(
":politicas :rate-limit :window must be exactly 1s, 1m (60s), or 1h (3600s) — \
the canonical authoring forms `\"<n>/s\"`, `\"<n>/m\"`, `\"<n>/h\"` the \
rate-limit codec round-trips losslessly; got {window:?} which renders to a \
non-round-trippable form (omit :rate-limit to disable, or pick one of the \
three canonical windows)"
)]
PolicyRateLimitWindowNotCanonical { window: Duration },
#[error(
":politicas :timeout must be an integer number of milliseconds — the canonical \
authoring form `\"<integer><unit>\"` for unit ∈ {{`ms`,`s`,`m`,`h`}} the shared \
duration codec round-trips losslessly; got {timeout:?} which carries a \
sub-millisecond residue that either truncates to a different `Duration` on \
re-parse (e.g. `Duration::from_micros(1500)` → renders `\"1ms\"` → parses back \
to 1ms, not 1.5ms) or renders as `\"0s\"` (sub-millisecond magnitude) the \
zero-floor gate rejects on re-validate. Pick an integer-millisecond magnitude \
(e.g. `\"30s\"`, `\"1500ms\"`, `\"2m\"`, `\"1h\"`)"
)]
PolicyTimeoutNotCanonical { timeout: Duration },
#[error(
":politicas :timeout ({timeout:?}) exceeds the mesh-policy ceiling \
(POLICY_TIMEOUT_MAX = 1h = 3600s) — a value above this cap turns the typed \
per-call deadline into a nominal-only contract (Envoy / Cilium L7 timeout \
overlays carry a deadline so long no realistic synchronous-:contratos \
traversal can reach it), and the MESH-COMPOSITION §V \"no infinite blocking\" \
CSE invariant degenerates to enforcement only at the per-Servico \
`:limits :wall-clock` layer — far above the per-edge granularity the typed \
`:politicas :timeout` slot is meant to express. Pin a value in 1ms..=1h \
(Envoy / Istio / Linkerd / AWS App Mesh production playbooks all recommend \
≤ 60s; the Kubernetes ingress-nginx documented `proxy_read_timeout` band \
maxes out at the same `3600s` ceiling) or omit :timeout to express \
`no per-call deadline on this axis` (the synchronous-call deadline then \
relies entirely on the per-Servico `:limits :wall-clock` axis)"
)]
PolicyTimeoutExceedsCap { timeout: Duration },
#[error(
":politicas :circuit-breaker :window must be an integer number of milliseconds — \
the canonical authoring form `\"<integer><unit>\"` for unit ∈ {{`ms`,`s`,`m`,`h`}} \
the shared duration codec round-trips losslessly; got {window:?} which carries a \
sub-millisecond residue that either truncates to a different `Duration` on \
re-parse or renders as `\"0s\"` the zero-floor gate rejects on re-validate. \
Pick an integer-millisecond magnitude (e.g. `\"60s\"`, `\"500ms\"`, `\"2m\"`)"
)]
PolicyBreakerWindowNotCanonical { window: Duration },
#[error(
":politicas :circuit-breaker :window ({window:?}) exceeds the mesh-policy ceiling \
(POLICY_BREAKER_WINDOW_MAX = 1h = 3600s) — a value above this cap turns the typed \
rolling-window breaker into a lifetime-counter breaker: the failure-counting window \
is structurally so long that transient failures are never forgotten, the breaker \
trips once and stays tripped for the lifetime of the component, and every typed-slot \
consumer (the future CiliumClusterwideEnvoyConfig per-:politicas overlay, Envoy's \
outlier_detection.interval) emits a \"rolling\" window that exists only nominally. \
Pin a value in 1ms..=1h (Hystrix / resilience4j / Istio / Envoy production playbooks \
default to 10s; AWS App Mesh maxes out at ~5m) or omit :circuit-breaker to disable \
the breaker entirely"
)]
PolicyBreakerWindowExceedsCap { window: Duration },
}
#[cfg(test)]
mod tests {
use super::*;
fn membro(name: &str, ver: &str) -> Membro {
Membro {
caixa: name.into(),
versao: ver.into(),
}
}
fn contract_http(de: &str, para: &str, ep: &str) -> WitContract {
WitContract {
de: de.into(),
para: para.into(),
wit: "wasi:http/proxy".into(),
endpoint: Some(ep.into()),
subject: None,
slot: None,
}
}
fn three_member_spec() -> AplicacaoSpec {
AplicacaoSpec {
membros: vec![
membro("catalog", "^0.1"),
membro("cart", "^0.1"),
membro("payment", "^0.2"),
],
contratos: vec![
contract_http("cart", "catalog", "/products/:id"),
contract_http("cart", "payment", "/charge"),
],
politicas: MeshPolicy {
timeout: Some(Duration::from_secs(30)),
retries: Some(3),
mtls_required: Some(true),
..Default::default()
},
placement: Placement {
estrategia: PlacementStrategy::Replicated,
clusters: vec!["rio".into(), "mar".into()],
affinity: Some("data-locality".into()),
shard_key: None,
},
entrada: Some(Entrada {
host: "checkout.quero.cloud".into(),
para: "cart".into(),
paths: vec!["/api/cart".into(), "/api/products".into()],
port: 8080,
}),
}
}
#[test]
fn happy_path_validates() {
three_member_spec().validate().unwrap();
}
#[test]
fn rejects_empty_membros() {
let mut s = three_member_spec();
s.membros = vec![];
assert_eq!(s.validate().unwrap_err(), AplicacaoError::NoMembros);
}
#[test]
fn rejects_empty_membro_caixa() {
let mut s = three_member_spec();
s.membros[1].caixa = String::new();
assert_eq!(s.validate().unwrap_err(), AplicacaoError::MembroCaixaEmpty);
}
#[test]
fn rejects_empty_membro_versao() {
let mut s = three_member_spec();
s.membros[2].versao = String::new();
let err = s.validate().unwrap_err();
assert!(
matches!(err, AplicacaoError::MembroVersaoEmpty { ref caixa } if caixa == "payment"),
"got {err:?}"
);
}
#[test]
fn rejects_duplicate_membro_caixa() {
let mut s = three_member_spec();
s.membros.push(membro("cart", "^0.2"));
let err = s.validate().unwrap_err();
assert!(
matches!(err, AplicacaoError::MembroDuplicate { ref caixa } if caixa == "cart"),
"got {err:?}"
);
}
#[test]
fn rejects_invalid_membro_versao_requirement() {
let mut s = three_member_spec();
s.membros[2].versao = "^bad-version".into();
let err = s.validate().unwrap_err();
assert!(
matches!(
err,
AplicacaoError::MembroVersaoInvalid { ref caixa, ref versao, .. }
if caixa == "payment" && versao == "^bad-version"
),
"got {err:?}"
);
}
#[test]
fn rejects_membro_versao_with_double_caret_typo() {
let mut s = three_member_spec();
s.membros[0].versao = "^^0.1".into();
let err = s.validate().unwrap_err();
assert!(
matches!(
err,
AplicacaoError::MembroVersaoInvalid { ref caixa, ref versao, .. }
if caixa == "catalog" && versao == "^^0.1"
),
"got {err:?}"
);
}
#[test]
fn rejects_membro_versao_with_v_prefixed_tag() {
let mut s = three_member_spec();
s.membros[1].versao = "v0.1".into();
let err = s.validate().unwrap_err();
assert!(
matches!(
err,
AplicacaoError::MembroVersaoInvalid { ref caixa, ref versao, .. }
if caixa == "cart" && versao == "v0.1"
),
"got {err:?}"
);
}
#[test]
fn accepts_canonical_membro_versao_forms() {
for form in [
"^0.1", "~0.1.2", "0.1.0", "*", ">=0.1, <2", ] {
let mut s = three_member_spec();
for m in &mut s.membros {
m.versao = form.into();
}
s.validate()
.unwrap_or_else(|e| panic!("canonical form {form:?} must validate, got {e:?}"));
}
}
#[test]
fn membro_versao_empty_takes_precedence_over_invalid() {
let mut s = three_member_spec();
s.membros[1].versao = String::new();
let err = s.validate().unwrap_err();
assert!(
matches!(err, AplicacaoError::MembroVersaoEmpty { ref caixa } if caixa == "cart"),
"got {err:?}"
);
}
#[test]
fn membro_versao_invalid_fires_before_duplicate_check() {
let mut s = three_member_spec();
s.membros[0].versao = "^bad".into();
s.membros.push(membro("cart", "^0.2")); let err = s.validate().unwrap_err();
assert!(
matches!(
err,
AplicacaoError::MembroVersaoInvalid { ref caixa, .. } if caixa == "catalog"
),
"got {err:?}"
);
}
#[test]
fn membro_versao_invalid_diagnostic_carries_offending_versao() {
let mut s = three_member_spec();
s.membros[2].versao = "not-a-req".into();
let err = s.validate().unwrap_err();
let AplicacaoError::MembroVersaoInvalid {
caixa,
versao,
reason,
} = err
else {
panic!("expected MembroVersaoInvalid, got other variant");
};
assert_eq!(caixa, "payment");
assert_eq!(versao, "not-a-req");
assert!(
!reason.is_empty(),
"MembroVersaoInvalid `reason` must carry the parser's wording verbatim"
);
}
#[test]
fn membro_versao_invalid_runs_before_contratos_check() {
let mut s = three_member_spec();
s.membros[1].versao = "^^0.1".into();
s.contratos
.push(contract_http("cart", "phantom", "/never-reached"));
let err = s.validate().unwrap_err();
assert!(
matches!(err, AplicacaoError::MembroVersaoInvalid { .. }),
"expected MembroVersaoInvalid to fire before ContratoMemberMissing, got {err:?}"
);
}
#[test]
fn membros_validation_runs_before_contratos_membership_check() {
let mut s = three_member_spec();
s.membros = vec![
membro("cart", "^0.1"),
membro("cart", "^0.2"),
membro("catalog", "^0.1"),
membro("payment", "^0.1"),
];
let err = s.validate().unwrap_err();
assert!(
matches!(err, AplicacaoError::MembroDuplicate { ref caixa } if caixa == "cart"),
"got {err:?}"
);
}
#[test]
fn distinct_membros_validate() {
three_member_spec().validate().unwrap();
}
#[test]
fn rejects_membro_caixa_with_uppercase() {
let mut s = three_member_spec();
s.membros[1].caixa = "Cart".into();
let err = s.validate().unwrap_err();
let AplicacaoError::MembroCaixaInvalid { caixa, reason } = err else {
panic!("expected MembroCaixaInvalid, got other variant");
};
assert_eq!(caixa, "Cart");
assert!(
reason.contains("uppercase"),
"diagnostic must name the violation as `uppercase` (got: {reason:?})"
);
assert!(
reason.contains("\"cart\""),
"diagnostic must suggest the lower-cased fix verbatim (got: {reason:?})"
);
}
#[test]
fn rejects_membro_caixa_with_underscore() {
let mut s = three_member_spec();
s.membros[0].caixa = "my_cart".into();
let err = s.validate().unwrap_err();
assert!(
matches!(
err,
AplicacaoError::MembroCaixaInvalid { ref caixa, ref reason }
if caixa == "my_cart" && reason.contains('_')
),
"got {err:?}"
);
}
#[test]
fn rejects_membro_caixa_with_dot() {
let mut s = three_member_spec();
s.membros[2].caixa = "team.cart".into();
let err = s.validate().unwrap_err();
assert!(
matches!(
err,
AplicacaoError::MembroCaixaInvalid { ref caixa, ref reason }
if caixa == "team.cart" && reason.contains('.')
),
"got {err:?}"
);
}
#[test]
fn rejects_membro_caixa_with_leading_hyphen() {
let mut s = three_member_spec();
s.membros[0].caixa = "-cart".into();
let err = s.validate().unwrap_err();
assert!(
matches!(
err,
AplicacaoError::MembroCaixaInvalid { ref caixa, ref reason }
if caixa == "-cart" && reason.contains("start and end")
),
"got {err:?}"
);
}
#[test]
fn rejects_membro_caixa_with_trailing_hyphen() {
let mut s = three_member_spec();
s.membros[1].caixa = "cart-".into();
let err = s.validate().unwrap_err();
assert!(
matches!(
err,
AplicacaoError::MembroCaixaInvalid { ref caixa, .. }
if caixa == "cart-"
),
"got {err:?}"
);
}
#[test]
fn rejects_membro_caixa_with_unicode() {
let mut s = three_member_spec();
s.membros[2].caixa = "café".into();
let err = s.validate().unwrap_err();
assert!(
matches!(
err,
AplicacaoError::MembroCaixaInvalid { ref caixa, .. }
if caixa == "café"
),
"got {err:?}"
);
}
#[test]
fn rejects_membro_caixa_with_whitespace() {
let mut s = three_member_spec();
s.membros[0].caixa = "my cart".into();
let err = s.validate().unwrap_err();
assert!(
matches!(
err,
AplicacaoError::MembroCaixaInvalid { ref caixa, .. }
if caixa == "my cart"
),
"got {err:?}"
);
}
#[test]
fn rejects_membro_caixa_too_long() {
let mut s = three_member_spec();
let too_long = "a".repeat(64);
s.membros[1].caixa = too_long.clone();
let err = s.validate().unwrap_err();
let AplicacaoError::MembroCaixaInvalid { caixa, reason } = err else {
panic!("expected MembroCaixaInvalid");
};
assert_eq!(caixa, too_long);
assert!(
reason.contains("63") && reason.contains("64"),
"diagnostic must name the cap (63) and the actual length (64): {reason:?}"
);
}
#[test]
fn membro_caixa_max_length_validates() {
let mut s = three_member_spec();
s.membros[2].caixa = "a".repeat(63);
s.entrada.as_mut().unwrap().para = "a".repeat(63);
s.contratos
.retain(|c| c.de != "payment" && c.para != "payment");
s.validate().unwrap();
}
#[test]
fn accepts_canonical_membro_caixa_forms() {
for form in [
"checkout",
"cart",
"cart-v2",
"a",
"c0",
"3rd-party-shim",
"x-1-2-3-4",
] {
let mut s = three_member_spec();
s.membros = vec![membro(form, "^0.1")];
s.contratos = vec![];
s.entrada = None;
s.validate()
.unwrap_or_else(|e| panic!("canonical form {form:?} must validate, got {e:?}"));
}
}
#[test]
fn membro_caixa_empty_takes_precedence_over_invalid() {
let mut s = three_member_spec();
s.membros[1].caixa = String::new();
let err = s.validate().unwrap_err();
assert_eq!(err, AplicacaoError::MembroCaixaEmpty);
}
#[test]
fn membro_caixa_invalid_fires_before_versao_check() {
let mut s = three_member_spec();
s.membros[1].caixa = "Cart".into();
s.membros[1].versao = String::new(); let err = s.validate().unwrap_err();
assert!(
matches!(
err,
AplicacaoError::MembroCaixaInvalid { ref caixa, .. } if caixa == "Cart"
),
"got {err:?}"
);
}
#[test]
fn membro_caixa_invalid_fires_before_duplicate_check() {
let mut s = three_member_spec();
s.membros[0].caixa = "Catalog".into();
s.membros.push(membro("cart", "^0.2")); let err = s.validate().unwrap_err();
assert!(
matches!(
err,
AplicacaoError::MembroCaixaInvalid { ref caixa, .. } if caixa == "Catalog"
),
"got {err:?}"
);
}
#[test]
fn membro_caixa_invalid_diagnostic_carries_offending_caixa() {
let mut s = three_member_spec();
s.membros[2].caixa = "BAD_NAME".into();
let err = s.validate().unwrap_err();
let AplicacaoError::MembroCaixaInvalid { caixa, reason } = err else {
panic!("expected MembroCaixaInvalid");
};
assert_eq!(caixa, "BAD_NAME");
assert!(
!reason.is_empty(),
"MembroCaixaInvalid `reason` must carry a parser-shaped wording"
);
}
#[test]
fn rejects_contrato_with_unknown_de() {
let mut s = three_member_spec();
s.contratos.push(contract_http("phantom", "catalog", "/x"));
let err = s.validate().unwrap_err();
assert!(
matches!(err, AplicacaoError::ContratoMemberMissing { caixa } if caixa == "phantom")
);
}
#[test]
fn rejects_contrato_with_unknown_para() {
let mut s = three_member_spec();
s.contratos.push(contract_http("cart", "phantom", "/x"));
let err = s.validate().unwrap_err();
assert!(
matches!(err, AplicacaoError::ContratoMemberMissing { caixa } if caixa == "phantom")
);
}
#[test]
fn contrato_unknown_de_diagnostic_routes_caixa_field_through_source_accessor() {
let mut s = three_member_spec();
let phantom = contract_http("phantom", "catalog", "/x");
s.contratos.push(phantom.clone());
let err = s.validate().unwrap_err();
let AplicacaoError::ContratoMemberMissing { caixa } = err else {
panic!("expected ContratoMemberMissing on phantom :de, got {err:?}");
};
assert_eq!(
caixa,
phantom.source(),
"ContratoMemberMissing.caixa on the phantom-:de arm must \
byte-equal WitContract::source — the wrap envelope must \
route through the lifted accessor rather than the raw \
.de.clone() field-access String-carry"
);
}
#[test]
fn contrato_unknown_para_diagnostic_routes_caixa_field_through_destination_accessor() {
let mut s = three_member_spec();
let phantom = contract_http("cart", "phantom", "/x");
s.contratos.push(phantom.clone());
let err = s.validate().unwrap_err();
let AplicacaoError::ContratoMemberMissing { caixa } = err else {
panic!("expected ContratoMemberMissing on phantom :para, got {err:?}");
};
assert_eq!(
caixa,
phantom.destination(),
"ContratoMemberMissing.caixa on the phantom-:para arm must \
byte-equal WitContract::destination — the wrap envelope \
must route through the lifted accessor rather than the raw \
.para.clone() field-access String-carry"
);
}
#[test]
fn contrato_malformed_de_diagnostic_routes_caixa_field_through_source_accessor() {
let mut s = three_member_spec();
let malformed = contract_http("BAD_NAME", "catalog", "/x");
s.contratos.push(malformed.clone());
let err = s.validate().unwrap_err();
let AplicacaoError::ContratoCaixaInvalid { slot, caixa, .. } = err else {
panic!("expected ContratoCaixaInvalid on malformed :de, got {err:?}");
};
assert_eq!(slot, crate::render::CONTRATO_AUTHOR_KEY_DE);
assert_eq!(
caixa,
malformed.source(),
"ContratoCaixaInvalid.caixa on the malformed-:de arm must \
byte-equal WitContract::source — the shape-gate arg + wrap \
envelope must route through the lifted accessor rather \
than the raw &c.de &String-borrow"
);
}
#[test]
fn contrato_malformed_para_diagnostic_routes_caixa_field_through_destination_accessor() {
let mut s = three_member_spec();
let malformed = contract_http("cart", "BAD_NAME", "/x");
s.contratos.push(malformed.clone());
let err = s.validate().unwrap_err();
let AplicacaoError::ContratoCaixaInvalid { slot, caixa, .. } = err else {
panic!("expected ContratoCaixaInvalid on malformed :para, got {err:?}");
};
assert_eq!(slot, crate::render::CONTRATO_AUTHOR_KEY_PARA);
assert_eq!(
caixa,
malformed.destination(),
"ContratoCaixaInvalid.caixa on the malformed-:para arm must \
byte-equal WitContract::destination — the shape-gate arg + \
wrap envelope must route through the lifted accessor \
rather than the raw &c.para &String-borrow"
);
}
#[test]
fn rejects_contrato_de_empty() {
let mut s = three_member_spec();
s.contratos.push(contract_http("", "catalog", "/x"));
let err = s.validate().unwrap_err();
assert_eq!(
err,
AplicacaoError::ContratoCaixaEmpty {
slot: crate::render::CONTRATO_AUTHOR_KEY_DE
},
"got {err:?}"
);
}
#[test]
fn rejects_contrato_para_empty() {
let mut s = three_member_spec();
s.contratos.push(contract_http("cart", "", "/x"));
let err = s.validate().unwrap_err();
assert_eq!(
err,
AplicacaoError::ContratoCaixaEmpty {
slot: crate::render::CONTRATO_AUTHOR_KEY_PARA
},
"got {err:?}"
);
}
#[test]
fn rejects_contrato_de_with_uppercase() {
let mut s = three_member_spec();
s.contratos.push(contract_http("Cart", "catalog", "/x"));
let err = s.validate().unwrap_err();
let AplicacaoError::ContratoCaixaInvalid {
slot,
caixa,
reason,
} = err
else {
panic!("expected ContratoCaixaInvalid, got other variant");
};
assert_eq!(slot, crate::render::CONTRATO_AUTHOR_KEY_DE);
assert_eq!(caixa, "Cart");
assert!(
reason.contains("uppercase"),
"diagnostic must name the violation as `uppercase` (got: {reason:?})"
);
}
#[test]
fn rejects_contrato_para_with_underscore() {
let mut s = three_member_spec();
s.contratos.push(contract_http("cart", "my_catalog", "/x"));
let err = s.validate().unwrap_err();
assert!(
matches!(
err,
AplicacaoError::ContratoCaixaInvalid { slot, ref caixa, ref reason }
if slot == crate::render::CONTRATO_AUTHOR_KEY_PARA && caixa == "my_catalog" && reason.contains('_')
),
"got {err:?}"
);
}
#[test]
fn rejects_contrato_de_with_dot() {
let mut s = three_member_spec();
s.contratos
.push(contract_http("team.cart", "catalog", "/x"));
let err = s.validate().unwrap_err();
assert!(
matches!(
err,
AplicacaoError::ContratoCaixaInvalid { slot, ref caixa, ref reason }
if slot == crate::render::CONTRATO_AUTHOR_KEY_DE && caixa == "team.cart" && reason.contains('.')
),
"got {err:?}"
);
}
#[test]
fn rejects_contrato_para_with_unicode() {
let mut s = three_member_spec();
s.contratos.push(contract_http("cart", "café", "/x"));
let err = s.validate().unwrap_err();
assert!(
matches!(
err,
AplicacaoError::ContratoCaixaInvalid { slot, ref caixa, .. }
if slot == crate::render::CONTRATO_AUTHOR_KEY_PARA && caixa == "café"
),
"got {err:?}"
);
}
#[test]
fn rejects_contrato_de_with_leading_hyphen() {
let mut s = three_member_spec();
s.contratos.push(contract_http("-cart", "catalog", "/x"));
let err = s.validate().unwrap_err();
assert!(
matches!(
err,
AplicacaoError::ContratoCaixaInvalid { slot, ref caixa, ref reason }
if slot == crate::render::CONTRATO_AUTHOR_KEY_DE && caixa == "-cart" && reason.contains("start and end")
),
"got {err:?}"
);
}
#[test]
fn contrato_de_empty_takes_precedence_over_invalid() {
let mut s = three_member_spec();
s.contratos.push(contract_http("", "catalog", "/x"));
let err = s.validate().unwrap_err();
assert_eq!(
err,
AplicacaoError::ContratoCaixaEmpty {
slot: crate::render::CONTRATO_AUTHOR_KEY_DE
}
);
}
#[test]
fn contrato_de_shape_fires_before_para_shape() {
let mut s = three_member_spec();
s.contratos.push(contract_http("Cart", "Catalog", "/x"));
let err = s.validate().unwrap_err();
assert!(
matches!(
err,
AplicacaoError::ContratoCaixaInvalid { slot, ref caixa, .. }
if slot == crate::render::CONTRATO_AUTHOR_KEY_DE && caixa == "Cart"
),
"got {err:?}"
);
}
#[test]
fn contrato_shape_fires_before_membership_lookup() {
let mut s = three_member_spec();
s.contratos.push(contract_http("Cart", "catalog", "/x"));
let err = s.validate().unwrap_err();
assert!(
matches!(
err,
AplicacaoError::ContratoCaixaInvalid { slot, .. } if slot == crate::render::CONTRATO_AUTHOR_KEY_DE
),
"got {err:?}"
);
let mut s = three_member_spec();
s.contratos.push(contract_http("cart", "Catalog", "/x"));
let err = s.validate().unwrap_err();
assert!(
matches!(
err,
AplicacaoError::ContratoCaixaInvalid { slot, .. } if slot == crate::render::CONTRATO_AUTHOR_KEY_PARA
),
"got {err:?}"
);
}
#[test]
fn contrato_shape_fires_before_self_edge_check() {
let mut s = three_member_spec();
s.contratos.push(contract_http("Cart", "Cart", "/x"));
let err = s.validate().unwrap_err();
assert!(
matches!(
err,
AplicacaoError::ContratoCaixaInvalid { slot, ref caixa, .. }
if slot == crate::render::CONTRATO_AUTHOR_KEY_DE && caixa == "Cart"
),
"got {err:?}"
);
}
#[test]
fn contrato_well_shaped_phantom_still_raises_member_missing() {
let mut s = three_member_spec();
s.contratos
.push(contract_http("phantom-shim", "catalog", "/x"));
let err = s.validate().unwrap_err();
assert!(
matches!(
err,
AplicacaoError::ContratoMemberMissing { ref caixa }
if caixa == "phantom-shim"
),
"got {err:?}"
);
}
#[test]
fn contrato_caixa_invalid_diagnostic_carries_offending_slot_and_value() {
let mut s = three_member_spec();
s.contratos.push(contract_http("cart", "BAD_NAME", "/x"));
let err = s.validate().unwrap_err();
let AplicacaoError::ContratoCaixaInvalid {
slot,
caixa,
reason,
} = err
else {
panic!("expected ContratoCaixaInvalid, got {err:?}");
};
assert_eq!(slot, crate::render::CONTRATO_AUTHOR_KEY_PARA);
assert_eq!(caixa, "BAD_NAME");
assert!(
!reason.is_empty(),
"ContratoCaixaInvalid `reason` must carry a parser-shaped wording"
);
}
#[test]
fn contrato_author_key_consts_pin_canonical_kebab_case_labels() {
assert_eq!(crate::render::CONTRATO_AUTHOR_KEY_DE, ":de");
assert_eq!(crate::render::CONTRATO_AUTHOR_KEY_PARA, ":para");
}
#[test]
fn contrato_shape_gate_routes_through_lifted_contrato_author_key_consts() {
let mut s = three_member_spec();
s.contratos.push(contract_http("", "catalog", "/x"));
assert_eq!(
s.validate().unwrap_err(),
AplicacaoError::ContratoCaixaEmpty {
slot: crate::render::CONTRATO_AUTHOR_KEY_DE
}
);
let mut s = three_member_spec();
s.contratos.push(contract_http("cart", "", "/x"));
assert_eq!(
s.validate().unwrap_err(),
AplicacaoError::ContratoCaixaEmpty {
slot: crate::render::CONTRATO_AUTHOR_KEY_PARA
}
);
}
#[test]
fn accepts_canonical_contrato_caixa_forms() {
for form in ["cart", "cart-v2", "a", "c0", "3rd-party-shim", "x-1-2-3-4"] {
let mut s = three_member_spec();
s.membros = vec![membro("checkout", "^0.1"), membro(form, "^0.1")];
s.contratos = vec![contract_http("checkout", form, "/x")];
s.entrada = None;
s.validate().unwrap_or_else(|e| {
panic!("canonical form {form:?} must validate on `:para`, got {e:?}")
});
let mut s = three_member_spec();
s.membros = vec![membro(form, "^0.1"), membro("catalog", "^0.1")];
s.contratos = vec![contract_http(form, "catalog", "/x")];
s.entrada = None;
s.validate().unwrap_or_else(|e| {
panic!("canonical form {form:?} must validate on `:de`, got {e:?}")
});
}
}
#[test]
fn rejects_empty_wit() {
let mut s = three_member_spec();
s.contratos.push(WitContract {
de: "cart".into(),
para: "catalog".into(),
wit: "".into(),
endpoint: None,
subject: None,
slot: None,
});
let err = s.validate().unwrap_err();
assert!(matches!(err, AplicacaoError::EmptyWit { .. }));
}
#[test]
fn rejects_entrada_to_unknown_member() {
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().para = "phantom".into();
assert!(matches!(
s.validate().unwrap_err(),
AplicacaoError::EntradaMemberMissing { .. }
));
}
#[test]
fn rejects_entrada_para_empty() {
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().para = String::new();
let err = s.validate().unwrap_err();
assert_eq!(err, AplicacaoError::EntradaParaEmpty, "got {err:?}");
}
#[test]
fn rejects_entrada_para_with_uppercase() {
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().para = "Cart".into();
let err = s.validate().unwrap_err();
let AplicacaoError::EntradaParaInvalid { para, reason } = err else {
panic!("expected EntradaParaInvalid, got other variant");
};
assert_eq!(para, "Cart");
assert!(
reason.contains("uppercase"),
"diagnostic must name the violation as `uppercase` (got: {reason:?})"
);
}
#[test]
fn rejects_entrada_para_with_underscore() {
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().para = "my_cart".into();
let err = s.validate().unwrap_err();
assert!(
matches!(
err,
AplicacaoError::EntradaParaInvalid { ref para, ref reason }
if para == "my_cart" && reason.contains('_')
),
"got {err:?}"
);
}
#[test]
fn rejects_entrada_para_with_dot() {
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().para = "team.cart".into();
let err = s.validate().unwrap_err();
assert!(
matches!(
err,
AplicacaoError::EntradaParaInvalid { ref para, ref reason }
if para == "team.cart" && reason.contains('.')
),
"got {err:?}"
);
}
#[test]
fn rejects_entrada_para_with_unicode() {
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().para = "café".into();
let err = s.validate().unwrap_err();
assert!(
matches!(
err,
AplicacaoError::EntradaParaInvalid { ref para, .. } if para == "café"
),
"got {err:?}"
);
}
#[test]
fn rejects_entrada_para_with_leading_hyphen() {
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().para = "-cart".into();
let err = s.validate().unwrap_err();
assert!(
matches!(
err,
AplicacaoError::EntradaParaInvalid { ref para, ref reason }
if para == "-cart" && reason.contains("start and end")
),
"got {err:?}"
);
}
#[test]
fn rejects_entrada_para_with_trailing_hyphen() {
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().para = "cart-".into();
let err = s.validate().unwrap_err();
assert!(
matches!(
err,
AplicacaoError::EntradaParaInvalid { ref para, ref reason }
if para == "cart-" && reason.contains("start and end")
),
"got {err:?}"
);
}
#[test]
fn rejects_entrada_para_too_long() {
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().para = "a".repeat(64);
let err = s.validate().unwrap_err();
assert!(
matches!(
err,
AplicacaoError::EntradaParaInvalid { ref para, ref reason }
if para.len() == 64 && reason.contains("max length")
),
"got {err:?}"
);
}
#[test]
fn entrada_para_empty_takes_precedence_over_invalid() {
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().para = String::new();
assert_eq!(s.validate().unwrap_err(), AplicacaoError::EntradaParaEmpty);
}
#[test]
fn entrada_para_shape_fires_before_membership_lookup() {
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().para = "Cart".into();
let err = s.validate().unwrap_err();
assert!(
matches!(
err,
AplicacaoError::EntradaParaInvalid { ref para, .. } if para == "Cart"
),
"got {err:?}"
);
}
#[test]
fn entrada_para_shape_fires_before_host_gate() {
let mut s = three_member_spec();
let e = s.entrada.as_mut().unwrap();
e.para = "Cart".into();
e.host = "BAD HOST".into();
let err = s.validate().unwrap_err();
assert!(
matches!(
err,
AplicacaoError::EntradaParaInvalid { ref para, .. } if para == "Cart"
),
"got {err:?}"
);
}
#[test]
fn entrada_para_well_shaped_phantom_still_raises_member_missing() {
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().para = "phantom-shim".into();
let err = s.validate().unwrap_err();
assert!(
matches!(
err,
AplicacaoError::EntradaMemberMissing { ref para }
if para == "phantom-shim"
),
"got {err:?}"
);
}
#[test]
fn entrada_para_invalid_diagnostic_carries_offending_para() {
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().para = "BAD_NAME".into();
let err = s.validate().unwrap_err();
let AplicacaoError::EntradaParaInvalid { para, reason } = err else {
panic!("expected EntradaParaInvalid, got {err:?}");
};
assert_eq!(para, "BAD_NAME");
assert!(
!reason.is_empty(),
"EntradaParaInvalid `reason` must carry a parser-shaped wording"
);
}
#[test]
fn accepts_canonical_entrada_para_forms() {
for form in ["cart", "cart-v2", "a", "c0", "3rd-party-shim", "x-1-2-3-4"] {
let mut s = three_member_spec();
s.membros = vec![membro(form, "^0.1"), membro("catalog", "^0.1")];
s.contratos = vec![contract_http(form, "catalog", "/x")];
s.entrada = Some(Entrada {
host: "checkout.quero.cloud".into(),
para: form.into(),
paths: vec!["/api".into()],
port: 8080,
});
s.validate().unwrap_or_else(|e| {
panic!("canonical form {form:?} must validate on `:entrada :para`, got {e:?}")
});
}
}
#[test]
fn rejects_replicated_without_clusters() {
let mut s = three_member_spec();
s.placement.clusters = vec![];
assert!(matches!(
s.validate().unwrap_err(),
AplicacaoError::PlacementWithoutClusters { .. }
));
}
#[test]
fn rejects_sharded_without_key() {
let mut s = three_member_spec();
s.placement.estrategia = PlacementStrategy::Sharded;
s.placement.shard_key = None;
s.placement.clusters = vec!["rio".into()];
assert_eq!(s.validate().unwrap_err(), AplicacaoError::ShardedWithoutKey);
}
#[test]
fn sharded_with_key_validates() {
let mut s = three_member_spec();
s.placement.estrategia = PlacementStrategy::Sharded;
s.placement.shard_key = Some("$tenantId".into());
s.validate().unwrap();
}
#[test]
fn round_trip_via_json_preserves_shape() {
let s = three_member_spec();
let json = serde_json::to_string(&s.membros).unwrap();
let back: Vec<Membro> = serde_json::from_str(&json).unwrap();
assert_eq!(back, s.membros);
let json = serde_json::to_string(&s.contratos).unwrap();
let back: Vec<WitContract> = serde_json::from_str(&json).unwrap();
assert_eq!(back, s.contratos);
let json = serde_json::to_string(&s.placement).unwrap();
let back: Placement = serde_json::from_str(&json).unwrap();
assert_eq!(back, s.placement);
let json = serde_json::to_string(&s.entrada).unwrap();
let back: Option<Entrada> = serde_json::from_str(&json).unwrap();
assert_eq!(back, s.entrada);
}
#[test]
fn rate_limit_round_trip_seconds() {
let policy = MeshPolicy {
rate_limit: Some(RateLimit {
rate: 100,
window: Duration::from_secs(1),
}),
..Default::default()
};
let json = serde_json::to_string(&policy).unwrap();
assert!(json.contains("\"100/s\""));
let back: MeshPolicy = serde_json::from_str(&json).unwrap();
assert_eq!(back.rate_limit.unwrap().rate, 100);
assert_eq!(back.rate_limit.unwrap().window, Duration::from_secs(1));
}
#[test]
fn rate_limit_round_trip_minutes() {
let policy = MeshPolicy {
rate_limit: Some(RateLimit {
rate: 5000,
window: Duration::from_secs(60),
}),
..Default::default()
};
let json = serde_json::to_string(&policy).unwrap();
assert!(json.contains("\"5000/m\""));
}
#[test]
fn circuit_breaker_round_trip() {
let policy = MeshPolicy {
circuit_breaker: Some(CircuitBreaker {
max_failures: 5,
window: Duration::from_secs(60),
}),
..Default::default()
};
let json = serde_json::to_string(&policy).unwrap();
let back: MeshPolicy = serde_json::from_str(&json).unwrap();
assert_eq!(back.circuit_breaker.unwrap().max_failures, 5);
assert_eq!(
back.circuit_breaker.unwrap().window,
Duration::from_secs(60)
);
}
#[test]
fn rejects_http_contrato_without_endpoint() {
let mut s = three_member_spec();
s.contratos.push(WitContract {
de: "cart".into(),
para: "catalog".into(),
wit: "wasi:http/proxy".into(),
endpoint: None,
subject: None,
slot: None,
});
let err = s.validate().unwrap_err();
assert!(matches!(
err,
AplicacaoError::ContratoMissingTarget {
expected: WitTarget::HTTP_FIELD_NAME,
..
}
));
}
#[test]
fn rejects_http_contrato_with_subject() {
let mut s = three_member_spec();
s.contratos.push(WitContract {
de: "cart".into(),
para: "catalog".into(),
wit: "wasi:http/proxy".into(),
endpoint: Some("/x".into()),
subject: Some("not.allowed.here".into()),
slot: None,
});
let err = s.validate().unwrap_err();
assert!(matches!(
err,
AplicacaoError::ContratoWrongTarget {
expected: WitTarget::HTTP_FIELD_NAME,
..
}
));
}
#[test]
fn rejects_pubsub_contrato_without_subject() {
let mut s = three_member_spec();
s.contratos.push(WitContract {
de: "cart".into(),
para: "catalog".into(),
wit: "nats:pub-sub".into(),
endpoint: None,
subject: None,
slot: None,
});
let err = s.validate().unwrap_err();
assert!(matches!(
err,
AplicacaoError::ContratoMissingTarget {
expected: WitTarget::PUBSUB_FIELD_NAME,
..
}
));
}
#[test]
fn rejects_pubsub_contrato_with_endpoint() {
let mut s = three_member_spec();
s.contratos.push(WitContract {
de: "cart".into(),
para: "catalog".into(),
wit: "kafka:topic".into(),
endpoint: Some("/wrong".into()),
subject: Some("topic.x".into()),
slot: None,
});
let err = s.validate().unwrap_err();
assert!(matches!(
err,
AplicacaoError::ContratoWrongTarget {
expected: WitTarget::PUBSUB_FIELD_NAME,
..
}
));
}
#[test]
fn rejects_store_contrato_without_slot() {
let mut s = three_member_spec();
s.contratos.push(WitContract {
de: "cart".into(),
para: "catalog".into(),
wit: "wasi:keyvalue/store".into(),
endpoint: None,
subject: None,
slot: None,
});
let err = s.validate().unwrap_err();
assert!(matches!(
err,
AplicacaoError::ContratoMissingTarget {
expected: WitTarget::STORE_FIELD_NAME,
..
}
));
}
#[test]
fn rejects_http_contrato_with_empty_endpoint() {
let mut s = three_member_spec();
s.contratos.push(WitContract {
de: "cart".into(),
para: "catalog".into(),
wit: "wasi:http/proxy".into(),
endpoint: Some(String::new()),
subject: None,
slot: None,
});
let err = s.validate().unwrap_err();
assert!(
matches!(err, AplicacaoError::ContratoEndpointEmpty { ref de, ref para }
if de == "cart" && para == "catalog"),
"got {err:?}"
);
}
#[test]
fn rejects_http_contrato_with_relative_endpoint() {
let mut s = three_member_spec();
s.contratos.push(WitContract {
de: "cart".into(),
para: "catalog".into(),
wit: "wasi:http/proxy".into(),
endpoint: Some("products/:id".into()),
subject: None,
slot: None,
});
let err = s.validate().unwrap_err();
assert!(
matches!(err, AplicacaoError::ContratoEndpointNotAbsolute { ref endpoint, .. }
if endpoint == "products/:id"),
"got {err:?}"
);
}
#[test]
fn rejects_pubsub_contrato_with_empty_subject() {
let mut s = three_member_spec();
s.contratos.push(WitContract {
de: "cart".into(),
para: "catalog".into(),
wit: "nats:pub-sub".into(),
endpoint: None,
subject: Some(String::new()),
slot: None,
});
let err = s.validate().unwrap_err();
assert!(
matches!(err, AplicacaoError::ContratoSubjectEmpty { ref de, ref para }
if de == "cart" && para == "catalog"),
"got {err:?}"
);
}
#[test]
fn rejects_store_contrato_with_empty_slot() {
let mut s = three_member_spec();
s.contratos.push(WitContract {
de: "cart".into(),
para: "catalog".into(),
wit: "wasi:keyvalue/store".into(),
endpoint: None,
subject: None,
slot: Some(String::new()),
});
let err = s.validate().unwrap_err();
assert!(
matches!(err, AplicacaoError::ContratoSlotEmpty { ref de, ref para }
if de == "cart" && para == "catalog"),
"got {err:?}"
);
}
#[test]
fn http_contrato_root_endpoint_validates() {
let mut s = three_member_spec();
s.contratos.push(contract_http("cart", "catalog", "/"));
s.validate().unwrap();
}
fn contrato_endpoint_err(ep: &str) -> AplicacaoError {
let mut s = three_member_spec();
s.contratos.push(contract_http("cart", "catalog", ep));
s.validate().unwrap_err()
}
#[test]
fn rejects_http_contrato_endpoint_with_query() {
let err = contrato_endpoint_err("/charge?token=X");
assert!(
matches!(err, AplicacaoError::ContratoEndpointInvalid { ref endpoint, ref reason, .. }
if endpoint == "/charge?token=X" && reason.contains("must not contain `?`")),
"got {err:?}"
);
}
#[test]
fn rejects_http_contrato_endpoint_with_fragment() {
let err = contrato_endpoint_err("/charge#frag");
assert!(
matches!(err, AplicacaoError::ContratoEndpointInvalid { ref endpoint, ref reason, .. }
if endpoint == "/charge#frag" && reason.contains("must not contain `#`")),
"got {err:?}"
);
}
#[test]
fn rejects_http_contrato_endpoint_with_whitespace() {
let err = contrato_endpoint_err("/foo bar");
assert!(
matches!(err, AplicacaoError::ContratoEndpointInvalid { ref endpoint, ref reason, .. }
if endpoint == "/foo bar" && reason.contains("whitespace")),
"got {err:?}"
);
}
#[test]
fn rejects_http_contrato_endpoint_with_control_char() {
let err = contrato_endpoint_err("/api/\x01bar");
assert!(
matches!(err, AplicacaoError::ContratoEndpointInvalid { ref endpoint, ref reason, .. }
if endpoint == "/api/\x01bar" && reason.contains("control character")),
"got {err:?}"
);
}
#[test]
fn rejects_http_contrato_endpoint_with_non_ascii() {
let err = contrato_endpoint_err("/api/café");
assert!(
matches!(err, AplicacaoError::ContratoEndpointInvalid { ref endpoint, ref reason, .. }
if endpoint == "/api/café" && reason.contains("non-ASCII")),
"got {err:?}"
);
}
#[test]
fn rejects_http_contrato_endpoint_with_consecutive_slashes() {
let err = contrato_endpoint_err("/api//cart");
assert!(
matches!(err, AplicacaoError::ContratoEndpointInvalid { ref endpoint, ref reason, .. }
if endpoint == "/api//cart" && reason.contains("consecutive `/`")),
"got {err:?}"
);
}
#[test]
fn rejects_http_contrato_endpoint_with_dot_segment() {
let err = contrato_endpoint_err("/api/./cart");
assert!(
matches!(err, AplicacaoError::ContratoEndpointInvalid { ref endpoint, ref reason, .. }
if endpoint == "/api/./cart" && reason.contains("`.` segment")),
"got {err:?}"
);
}
#[test]
fn rejects_http_contrato_endpoint_with_parent_segment() {
let err = contrato_endpoint_err("/api/../etc");
assert!(
matches!(err, AplicacaoError::ContratoEndpointInvalid { ref endpoint, ref reason, .. }
if endpoint == "/api/../etc" && reason.contains("`..` parent-segment")),
"got {err:?}"
);
}
#[test]
fn rejects_http_contrato_endpoint_too_long() {
let big = format!("/api/{}", "a".repeat(1020));
assert_eq!(big.len(), 1025);
let err = contrato_endpoint_err(&big);
assert!(
matches!(err, AplicacaoError::ContratoEndpointInvalid { ref endpoint, ref reason, .. }
if endpoint == &big && reason.contains("max length of 1024")),
"got {err:?}"
);
}
#[test]
fn http_contrato_endpoint_max_length_validates() {
let big = format!("/api/{}", "a".repeat(1019));
assert_eq!(big.len(), 1024);
let mut s = three_member_spec();
s.contratos.push(contract_http("cart", "catalog", &big));
s.validate().unwrap();
}
#[test]
fn http_contrato_endpoint_accepts_canonical_forms() {
for ep in [
"/",
"/charge",
"/v1/charge",
"/api/.config",
"/products/:id",
"/api/cart/",
"/api/caf%C3%A9",
"/foo..bar",
"/...",
] {
let mut s = three_member_spec();
s.contratos.push(contract_http("payment", "catalog", ep));
s.validate()
.unwrap_or_else(|e| panic!("expected {ep:?} to validate, got {e:?}"));
}
}
#[test]
fn contrato_endpoint_empty_takes_precedence_over_invalid() {
let mut s = three_member_spec();
s.contratos.push(WitContract {
de: "cart".into(),
para: "catalog".into(),
wit: "wasi:http/proxy".into(),
endpoint: Some(String::new()),
subject: None,
slot: None,
});
let err = s.validate().unwrap_err();
assert!(
matches!(err, AplicacaoError::ContratoEndpointEmpty { .. }),
"got {err:?}"
);
}
#[test]
fn contrato_endpoint_not_absolute_takes_precedence_over_invalid() {
let err = contrato_endpoint_err("bad path");
assert!(
matches!(err, AplicacaoError::ContratoEndpointNotAbsolute { ref endpoint, .. }
if endpoint == "bad path"),
"got {err:?}"
);
}
#[test]
fn contrato_endpoint_invalid_diagnostic_carries_offending_endpoint() {
let err = contrato_endpoint_err("/api?q=1");
match err {
AplicacaoError::ContratoEndpointInvalid {
de,
para,
endpoint,
reason,
} => {
assert_eq!(de, "cart");
assert_eq!(para, "catalog");
assert_eq!(endpoint, "/api?q=1");
assert!(!reason.is_empty(), "reason field must be non-empty");
}
other => panic!("expected ContratoEndpointInvalid, got {other:?}"),
}
}
#[test]
fn target_view_payload_is_guaranteed_nonempty_after_target_call() {
let http = contract_http("cart", "catalog", "/x");
match http.target().unwrap() {
WitTarget::Http { endpoint } => {
assert!(!endpoint.is_empty());
assert!(endpoint.starts_with('/'));
}
other => panic!("expected Http, got {other:?}"),
}
let nats = WitContract {
de: "a".into(),
para: "b".into(),
wit: "nats:pub-sub".into(),
endpoint: None,
subject: Some("topic.x".into()),
slot: None,
};
match nats.target().unwrap() {
WitTarget::PubSub { subject } => assert!(!subject.is_empty()),
other => panic!("expected PubSub, got {other:?}"),
}
let kv = WitContract {
de: "a".into(),
para: "b".into(),
wit: "wasi:keyvalue/store".into(),
endpoint: None,
subject: None,
slot: Some("checkout/$orderId".into()),
};
match kv.target().unwrap() {
WitTarget::Store { slot } => assert!(!slot.is_empty()),
other => panic!("expected Store, got {other:?}"),
}
}
#[test]
fn target_diagnostic_names_offending_endpoint_value() {
let bad = WitContract {
de: "src".into(),
para: "dst".into(),
wit: "wasi:http/proxy".into(),
endpoint: Some("api/v1/charge".into()),
subject: None,
slot: None,
};
match bad.target().unwrap_err() {
AplicacaoError::ContratoEndpointNotAbsolute { de, para, endpoint } => {
assert_eq!(de, "src");
assert_eq!(para, "dst");
assert_eq!(endpoint, "api/v1/charge");
}
other => panic!("expected ContratoEndpointNotAbsolute, got {other:?}"),
}
}
#[test]
fn rejects_unknown_wit_with_target_set() {
let mut s = three_member_spec();
s.contratos.push(WitContract {
de: "cart".into(),
para: "catalog".into(),
wit: "custom:exchange".into(),
endpoint: Some("/leaked".into()),
subject: None,
slot: None,
});
let err = s.validate().unwrap_err();
assert!(matches!(
err,
AplicacaoError::ContratoWrongTarget {
expected: WitTarget::CAPABILITY_EXPECTED,
..
}
));
}
#[test]
fn wit_target_capability_expected_pins_wrong_target_diagnostic_scalar() {
assert_eq!(WitTarget::CAPABILITY_EXPECTED, "none");
let mut s = three_member_spec();
s.contratos.push(WitContract {
de: "cart".into(),
para: "catalog".into(),
wit: "custom:exchange".into(),
endpoint: Some("/leaked".into()),
subject: None,
slot: None,
});
match s.validate().unwrap_err() {
AplicacaoError::ContratoWrongTarget { expected, .. } => {
assert_eq!(expected, WitTarget::CAPABILITY_EXPECTED);
}
other => panic!("expected ContratoWrongTarget, got {other:?}"),
}
}
#[test]
fn unknown_wit_capability_only_validates() {
let mut s = three_member_spec();
s.contratos.push(WitContract {
de: "cart".into(),
para: "catalog".into(),
wit: "custom:exchange".into(),
endpoint: None,
subject: None,
slot: None,
});
s.validate().unwrap();
let added = s.contratos.last().unwrap();
assert_eq!(added.target().unwrap(), WitTarget::Capability);
}
#[test]
fn target_typed_view_round_trips_each_shape() {
let http = contract_http("cart", "catalog", "/products/:id");
assert_eq!(
http.target().unwrap(),
WitTarget::Http {
endpoint: "/products/:id"
}
);
let nats = WitContract {
de: "a".into(),
para: "b".into(),
wit: "nats:pub-sub".into(),
endpoint: None,
subject: Some("topic.x".into()),
slot: None,
};
assert_eq!(
nats.target().unwrap(),
WitTarget::PubSub { subject: "topic.x" }
);
let kv = WitContract {
de: "a".into(),
para: "b".into(),
wit: "wasi:keyvalue/store".into(),
endpoint: None,
subject: None,
slot: Some("checkout/$orderId".into()),
};
assert_eq!(
kv.target().unwrap(),
WitTarget::Store {
slot: "checkout/$orderId"
}
);
}
#[test]
fn wit_contract_kind_predicates() {
let http = contract_http("a", "b", "/x");
assert!(http.is_http());
assert!(!http.is_pubsub());
assert!(!http.is_store());
let nats = WitContract {
de: "a".into(),
para: "b".into(),
wit: "nats:pub-sub".into(),
endpoint: None,
subject: Some("topic.x".into()),
slot: None,
};
assert!(nats.is_pubsub());
assert!(!nats.is_http());
let kv = WitContract {
de: "a".into(),
para: "b".into(),
wit: "wasi:keyvalue/store".into(),
endpoint: None,
subject: None,
slot: Some("checkout/$orderId".into()),
};
assert!(kv.is_store());
assert!(!kv.is_http());
}
fn contrato_wit_err(wit: &str) -> AplicacaoError {
let mut s = three_member_spec();
s.contratos.push(WitContract {
de: "payment".into(),
para: "catalog".into(),
wit: wit.into(),
endpoint: None,
subject: None,
slot: None,
});
s.validate().unwrap_err()
}
#[test]
fn rejects_wit_with_uppercase_namespace() {
let err = contrato_wit_err("WASI:http/proxy");
assert!(
matches!(err, AplicacaoError::ContratoWitInvalid { ref wit, ref reason, .. }
if wit == "WASI:http/proxy" && reason.contains("lowercase")),
"got {err:?}"
);
}
#[test]
fn rejects_wit_with_hyphen_for_colon_typo() {
let err = contrato_wit_err("wasi-http/proxy");
assert!(
matches!(err, AplicacaoError::ContratoWitInvalid { ref wit, ref reason, .. }
if wit == "wasi-http/proxy" && reason.contains("must contain a `:`")),
"got {err:?}"
);
}
#[test]
fn rejects_wit_with_multiple_colons() {
let err = contrato_wit_err("wasi:http:proxy");
assert!(
matches!(err, AplicacaoError::ContratoWitInvalid { ref wit, ref reason, .. }
if wit == "wasi:http:proxy" && reason.contains("exactly one `:`")),
"got {err:?}"
);
}
#[test]
fn rejects_wit_with_empty_package() {
let err = contrato_wit_err("wasi:");
assert!(
matches!(err, AplicacaoError::ContratoWitInvalid { ref wit, ref reason, .. }
if wit == "wasi:" && reason.contains("package") && reason.contains("must not be empty")),
"got {err:?}"
);
}
#[test]
fn rejects_wit_with_underscore() {
let err = contrato_wit_err("wasi:http_proxy");
assert!(
matches!(err, AplicacaoError::ContratoWitInvalid { ref wit, ref reason, .. }
if wit == "wasi:http_proxy" && reason.contains('_')),
"got {err:?}"
);
}
#[test]
fn rejects_wit_with_whitespace() {
let err = contrato_wit_err("wasi:http proxy");
assert!(
matches!(err, AplicacaoError::ContratoWitInvalid { ref wit, ref reason, .. }
if wit == "wasi:http proxy" && reason.contains("whitespace")),
"got {err:?}"
);
}
#[test]
fn rejects_wit_with_non_ascii() {
let err = contrato_wit_err("wasi:caf\u{e9}/proxy");
assert!(
matches!(err, AplicacaoError::ContratoWitInvalid { ref wit, ref reason, .. }
if wit == "wasi:caf\u{e9}/proxy" && reason.contains("non-ASCII")),
"got {err:?}"
);
}
#[test]
fn rejects_wit_with_consecutive_hyphens() {
let err = contrato_wit_err("nats:pub--sub");
assert!(
matches!(err, AplicacaoError::ContratoWitInvalid { ref wit, ref reason, .. }
if wit == "nats:pub--sub" && reason.contains("consecutive `-`")),
"got {err:?}"
);
}
#[test]
fn rejects_wit_with_trailing_at_no_version() {
let err = contrato_wit_err("wasi:http/proxy@");
assert!(
matches!(err, AplicacaoError::ContratoWitInvalid { ref wit, ref reason, .. }
if wit == "wasi:http/proxy@" && reason.contains("trailing `@`")),
"got {err:?}"
);
}
#[test]
fn rejects_wit_too_long() {
let big = format!("wasi:{}", "a".repeat(124));
assert_eq!(big.len(), 129);
let err = contrato_wit_err(&big);
assert!(
matches!(err, AplicacaoError::ContratoWitInvalid { ref wit, ref reason, .. }
if wit == &big && reason.contains("max length of 128")),
"got {err:?}"
);
}
#[test]
fn wit_max_length_validates() {
let big = format!("wasi:{}", "a".repeat(123));
assert_eq!(big.len(), 128);
let mut s = three_member_spec();
s.contratos.push(WitContract {
de: "payment".into(),
para: "catalog".into(),
wit: big,
endpoint: None,
subject: None,
slot: None,
});
s.validate().unwrap();
}
#[test]
fn wit_accepts_canonical_forms_at_aplicacao_layer() {
for wit in [
"wasi:http/proxy",
"wasi:keyvalue/store",
"nats:pub-sub",
"kafka:topic",
"custom:exchange",
"pleme:cap/audit",
"wasi:http/proxy@0.2.0",
] {
let (endpoint, subject, slot) = if wit_shape_is_http(wit) {
(Some("/x".into()), None, None)
} else if wit_shape_is_pubsub(wit) {
(None, Some("topic.x".into()), None)
} else if wit_shape_is_store(wit) {
(None, None, Some("bucket/$key".into()))
} else {
(None, None, None)
};
let mut s = three_member_spec();
s.contratos.push(WitContract {
de: "payment".into(),
para: "catalog".into(),
wit: wit.into(),
endpoint,
subject,
slot,
});
s.validate()
.unwrap_or_else(|e| panic!("canonical WIT {wit:?} must validate, got {e:?}"));
}
}
#[test]
fn wit_shape_predicates_accept_canonical_prefix_set() {
assert!(wit_shape_is_http("wasi:http/proxy"));
assert!(wit_shape_is_http("wasi:http/proxy@0.2.0"));
assert!(wit_shape_is_http("http:incoming"));
assert!(wit_shape_is_pubsub("nats:pub-sub"));
assert!(wit_shape_is_pubsub("kafka:topic"));
assert!(wit_shape_is_store("wasi:keyvalue/store"));
assert!(wit_shape_is_store("kv:cache/session"));
}
#[test]
fn wit_shape_predicates_reject_uncanonical_forms() {
for wit in ["", "WASI:HTTP/proxy", "wasi-http/proxy", "custom-shape"] {
assert!(!wit_shape_is_http(wit), "{wit:?} must not be HTTP");
assert!(!wit_shape_is_pubsub(wit), "{wit:?} must not be pubsub");
assert!(!wit_shape_is_store(wit), "{wit:?} must not be store");
}
}
#[test]
fn wit_shape_predicates_partition_canonical_set() {
for prefix in WIT_HTTP_SHAPE_PREFIXES {
let sample = format!("{prefix}x");
assert!(wit_shape_is_http(&sample));
assert!(!wit_shape_is_pubsub(&sample));
assert!(!wit_shape_is_store(&sample));
}
for prefix in WIT_PUBSUB_SHAPE_PREFIXES {
let sample = format!("{prefix}x");
assert!(!wit_shape_is_http(&sample));
assert!(wit_shape_is_pubsub(&sample));
assert!(!wit_shape_is_store(&sample));
}
for prefix in WIT_STORE_SHAPE_PREFIXES {
let sample = format!("{prefix}x");
assert!(!wit_shape_is_http(&sample));
assert!(!wit_shape_is_pubsub(&sample));
assert!(wit_shape_is_store(&sample));
}
}
#[test]
fn wit_shape_matches_scans_prefix_set_with_starts_with_semantics() {
let two = &["wasi:http/", "http:"];
assert!(wit_shape_matches("wasi:http/proxy", two));
assert!(wit_shape_matches("http:incoming", two));
assert!(!wit_shape_matches("wasi:keyvalue/store", two));
let one = &["nats:"];
assert!(wit_shape_matches("nats:pub-sub", one));
assert!(!wit_shape_matches("kafka:topic", one));
let empty: &[&str] = &[];
assert!(!wit_shape_matches("wasi:http/proxy", empty));
assert!(!wit_shape_matches("", empty));
assert!(!wit_shape_matches("custom:wasi:http/proxy", two));
}
#[test]
fn wit_shape_predicates_delegate_to_wit_shape_matches() {
let samples = [
String::new(),
"wasi:http/proxy".to_string(),
"http:incoming".to_string(),
"nats:pub-sub".to_string(),
"kafka:topic".to_string(),
"wasi:keyvalue/store".to_string(),
"kv:cache/session".to_string(),
"custom-shape".to_string(),
"WASI:HTTP/proxy".to_string(),
];
for wit in &samples {
assert_eq!(
wit_shape_is_http(wit),
wit_shape_matches(wit, WIT_HTTP_SHAPE_PREFIXES),
"wit_shape_is_http drifted from combinator on {wit:?}",
);
assert_eq!(
wit_shape_is_pubsub(wit),
wit_shape_matches(wit, WIT_PUBSUB_SHAPE_PREFIXES),
"wit_shape_is_pubsub drifted from combinator on {wit:?}",
);
assert_eq!(
wit_shape_is_store(wit),
wit_shape_matches(wit, WIT_STORE_SHAPE_PREFIXES),
"wit_shape_is_store drifted from combinator on {wit:?}",
);
}
}
#[test]
fn wit_contract_shape_methods_delegate_to_free_functions() {
for shape_set in [
WIT_HTTP_SHAPE_PREFIXES,
WIT_PUBSUB_SHAPE_PREFIXES,
WIT_STORE_SHAPE_PREFIXES,
] {
for prefix in shape_set {
let c = WitContract {
de: "cart".into(),
para: "catalog".into(),
wit: format!("{prefix}x"),
endpoint: None,
subject: None,
slot: None,
};
assert_eq!(c.is_http(), wit_shape_is_http(&c.wit));
assert_eq!(c.is_pubsub(), wit_shape_is_pubsub(&c.wit));
assert_eq!(c.is_store(), wit_shape_is_store(&c.wit));
}
}
}
#[test]
fn empty_wit_takes_precedence_over_invalid() {
let mut s = three_member_spec();
s.contratos.push(WitContract {
de: "payment".into(),
para: "catalog".into(),
wit: String::new(),
endpoint: None,
subject: None,
slot: None,
});
let err = s.validate().unwrap_err();
assert!(
matches!(err, AplicacaoError::EmptyWit { .. }),
"got {err:?}"
);
}
#[test]
fn wit_invalid_fires_before_payload_shape_arm() {
let mut s = three_member_spec();
s.contratos.push(WitContract {
de: "payment".into(),
para: "catalog".into(),
wit: "wasi-http/proxy".into(),
endpoint: Some("/x".into()),
subject: None,
slot: None,
});
let err = s.validate().unwrap_err();
assert!(
matches!(err, AplicacaoError::ContratoWitInvalid { ref wit, .. }
if wit == "wasi-http/proxy"),
"got {err:?}"
);
}
#[test]
fn wit_invalid_diagnostic_carries_offending_wit() {
let err = contrato_wit_err("WASI:HTTP/proxy");
match err {
AplicacaoError::ContratoWitInvalid {
de,
para,
wit,
reason,
} => {
assert_eq!(de, "payment");
assert_eq!(para, "catalog");
assert_eq!(wit, "WASI:HTTP/proxy");
assert!(!reason.is_empty(), "reason field must be non-empty");
}
other => panic!("expected ContratoWitInvalid, got {other:?}"),
}
}
fn contrato_subject_err(subject: &str) -> AplicacaoError {
let mut s = three_member_spec();
s.contratos.push(WitContract {
de: "payment".into(),
para: "catalog".into(),
wit: "nats:pub-sub".into(),
endpoint: None,
subject: Some(subject.into()),
slot: None,
});
s.validate().unwrap_err()
}
#[test]
fn rejects_pubsub_contrato_subject_with_whitespace() {
let err = contrato_subject_err("foo bar");
assert!(
matches!(err, AplicacaoError::ContratoSubjectInvalid { ref subject, ref reason, .. }
if subject == "foo bar" && reason.contains("whitespace")),
"got {err:?}"
);
}
#[test]
fn rejects_pubsub_contrato_subject_with_control_char() {
let err = contrato_subject_err("foo\x01bar");
assert!(
matches!(err, AplicacaoError::ContratoSubjectInvalid { ref subject, ref reason, .. }
if subject == "foo\x01bar" && reason.contains("control character")),
"got {err:?}"
);
}
#[test]
fn rejects_pubsub_contrato_subject_with_non_ascii() {
let err = contrato_subject_err("foo.caf\u{e9}");
assert!(
matches!(err, AplicacaoError::ContratoSubjectInvalid { ref subject, ref reason, .. }
if subject == "foo.caf\u{e9}" && reason.contains("non-ASCII")),
"got {err:?}"
);
}
#[test]
fn rejects_pubsub_contrato_subject_with_leading_dot() {
let err = contrato_subject_err(".foo");
assert!(
matches!(err, AplicacaoError::ContratoSubjectInvalid { ref subject, ref reason, .. }
if subject == ".foo" && reason.contains("must not start with `.`")),
"got {err:?}"
);
}
#[test]
fn rejects_pubsub_contrato_subject_with_trailing_dot() {
let err = contrato_subject_err("foo.");
assert!(
matches!(err, AplicacaoError::ContratoSubjectInvalid { ref subject, ref reason, .. }
if subject == "foo." && reason.contains("must not end with `.`")),
"got {err:?}"
);
}
#[test]
fn rejects_pubsub_contrato_subject_with_consecutive_dots() {
let err = contrato_subject_err("foo..bar");
assert!(
matches!(err, AplicacaoError::ContratoSubjectInvalid { ref subject, ref reason, .. }
if subject == "foo..bar" && reason.contains("consecutive `.`")),
"got {err:?}"
);
}
#[test]
fn rejects_pubsub_contrato_subject_with_non_trailing_multi_wildcard() {
let err = contrato_subject_err("foo.>.bar");
assert!(
matches!(err, AplicacaoError::ContratoSubjectInvalid { ref subject, ref reason, .. }
if subject == "foo.>.bar" && reason.contains("only allowed as the final segment")),
"got {err:?}"
);
}
#[test]
fn rejects_pubsub_contrato_subject_with_mid_segment_star() {
let err = contrato_subject_err("foo*.bar");
assert!(
matches!(err, AplicacaoError::ContratoSubjectInvalid { ref subject, ref reason, .. }
if subject == "foo*.bar" && reason.contains("`*` mid-segment")),
"got {err:?}"
);
}
#[test]
fn rejects_pubsub_contrato_subject_with_invalid_char() {
let err = contrato_subject_err("foo,bar");
assert!(
matches!(err, AplicacaoError::ContratoSubjectInvalid { ref subject, ref reason, .. }
if subject == "foo,bar" && reason.contains("invalid character")),
"got {err:?}"
);
}
#[test]
fn rejects_pubsub_contrato_subject_too_long() {
let big = "a".repeat(257);
assert_eq!(big.len(), 257);
let err = contrato_subject_err(&big);
assert!(
matches!(err, AplicacaoError::ContratoSubjectInvalid { ref subject, ref reason, .. }
if subject == &big && reason.contains("max length of 256")),
"got {err:?}"
);
}
#[test]
fn pubsub_contrato_subject_max_length_validates() {
let big = "a".repeat(256);
assert_eq!(big.len(), 256);
let mut s = three_member_spec();
s.contratos.push(WitContract {
de: "payment".into(),
para: "catalog".into(),
wit: "nats:pub-sub".into(),
endpoint: None,
subject: Some(big),
slot: None,
});
s.validate().unwrap();
}
#[test]
fn pubsub_contrato_subject_accepts_canonical_forms() {
for subject in [
"checkout.events.charge.failed",
"rio.events.order.charged",
"orders",
"orders.123",
"snake_case.token",
"kebab-case.token",
"MixedCase.Token",
"orders.*.charged",
"*.events.*",
"orders.>",
] {
let mut s = three_member_spec();
s.contratos.push(WitContract {
de: "payment".into(),
para: "catalog".into(),
wit: "nats:pub-sub".into(),
endpoint: None,
subject: Some(subject.into()),
slot: None,
});
s.validate()
.unwrap_or_else(|e| panic!("expected {subject:?} to validate, got {e:?}"));
}
}
#[test]
fn contrato_subject_empty_takes_precedence_over_invalid() {
let mut s = three_member_spec();
s.contratos.push(WitContract {
de: "payment".into(),
para: "catalog".into(),
wit: "nats:pub-sub".into(),
endpoint: None,
subject: Some(String::new()),
slot: None,
});
let err = s.validate().unwrap_err();
assert!(
matches!(err, AplicacaoError::ContratoSubjectEmpty { .. }),
"got {err:?}"
);
}
#[test]
fn contrato_subject_invalid_diagnostic_carries_offending_subject() {
let err = contrato_subject_err("foo..bar");
match err {
AplicacaoError::ContratoSubjectInvalid {
de,
para,
subject,
reason,
} => {
assert_eq!(de, "payment");
assert_eq!(para, "catalog");
assert_eq!(subject, "foo..bar");
assert!(!reason.is_empty(), "reason field must be non-empty");
}
other => panic!("expected ContratoSubjectInvalid, got {other:?}"),
}
}
#[test]
fn target_view_pubsub_subject_passes_through_to_typed_view() {
let nats = WitContract {
de: "a".into(),
para: "b".into(),
wit: "nats:pub-sub".into(),
endpoint: None,
subject: Some("orders.events.*.charged".into()),
slot: None,
};
match nats.target().unwrap() {
WitTarget::PubSub { subject } => {
assert_eq!(subject, "orders.events.*.charged");
}
other => panic!("expected PubSub, got {other:?}"),
}
}
fn contrato_slot_err(slot: &str) -> AplicacaoError {
let mut s = three_member_spec();
s.contratos.push(WitContract {
de: "payment".into(),
para: "catalog".into(),
wit: "wasi:keyvalue/store".into(),
endpoint: None,
subject: None,
slot: Some(slot.into()),
});
s.validate().unwrap_err()
}
#[test]
fn rejects_store_contrato_slot_with_whitespace() {
let err = contrato_slot_err("check out/$order");
assert!(
matches!(err, AplicacaoError::ContratoSlotInvalid { ref slot, ref reason, .. }
if slot == "check out/$order" && reason.contains("whitespace")),
"got {err:?}"
);
}
#[test]
fn rejects_store_contrato_slot_with_tab() {
let err = contrato_slot_err("check\tout");
assert!(
matches!(err, AplicacaoError::ContratoSlotInvalid { ref slot, ref reason, .. }
if slot == "check\tout" && reason.contains("whitespace")),
"got {err:?}"
);
}
#[test]
fn rejects_store_contrato_slot_with_control_char() {
let err = contrato_slot_err("checkout/\x01order");
assert!(
matches!(err, AplicacaoError::ContratoSlotInvalid { ref slot, ref reason, .. }
if slot == "checkout/\x01order" && reason.contains("control character")),
"got {err:?}"
);
}
#[test]
fn rejects_store_contrato_slot_with_newline() {
let err = contrato_slot_err("checkout\norder");
assert!(
matches!(err, AplicacaoError::ContratoSlotInvalid { ref slot, ref reason, .. }
if slot == "checkout\norder" && reason.contains("control character")),
"got {err:?}"
);
}
#[test]
fn rejects_store_contrato_slot_with_non_ascii() {
let err = contrato_slot_err("ch\u{e9}ckout/$order");
assert!(
matches!(err, AplicacaoError::ContratoSlotInvalid { ref slot, ref reason, .. }
if slot == "ch\u{e9}ckout/$order" && reason.contains("non-ASCII")),
"got {err:?}"
);
}
#[test]
fn rejects_store_contrato_slot_too_long() {
let big = "a".repeat(513);
assert_eq!(big.len(), 513);
let err = contrato_slot_err(&big);
assert!(
matches!(err, AplicacaoError::ContratoSlotInvalid { ref slot, ref reason, .. }
if slot == &big && reason.contains("max length of 512")),
"got {err:?}"
);
}
#[test]
fn store_contrato_slot_max_length_validates() {
let big = "a".repeat(512);
assert_eq!(big.len(), 512);
let mut s = three_member_spec();
s.contratos.push(WitContract {
de: "payment".into(),
para: "catalog".into(),
wit: "wasi:keyvalue/store".into(),
endpoint: None,
subject: None,
slot: Some(big),
});
s.validate().unwrap();
}
#[test]
fn store_contrato_slot_accepts_canonical_forms() {
for slot in [
"checkout",
"checkout/$orderId",
"users:{tenant}/{id}",
"session.<sid>",
"session.tokens.<sid>",
"snake_case_key",
"kebab-case-key",
"MixedCase",
"shard0",
"v2/key",
"users/caf%C3%A9",
] {
let mut s = three_member_spec();
s.contratos.push(WitContract {
de: "payment".into(),
para: "catalog".into(),
wit: "wasi:keyvalue/store".into(),
endpoint: None,
subject: None,
slot: Some(slot.into()),
});
s.validate()
.unwrap_or_else(|e| panic!("expected slot {slot:?} to validate, got {e:?}"));
}
}
#[test]
fn contrato_slot_empty_takes_precedence_over_invalid() {
let mut s = three_member_spec();
s.contratos.push(WitContract {
de: "payment".into(),
para: "catalog".into(),
wit: "wasi:keyvalue/store".into(),
endpoint: None,
subject: None,
slot: Some(String::new()),
});
let err = s.validate().unwrap_err();
assert!(
matches!(err, AplicacaoError::ContratoSlotEmpty { .. }),
"got {err:?}"
);
}
#[test]
fn contrato_slot_invalid_diagnostic_carries_offending_slot() {
let err = contrato_slot_err("check out/$order");
match err {
AplicacaoError::ContratoSlotInvalid {
de,
para,
slot,
reason,
} => {
assert_eq!(de, "payment");
assert_eq!(para, "catalog");
assert_eq!(slot, "check out/$order");
assert!(!reason.is_empty(), "reason field must be non-empty");
}
other => panic!("expected ContratoSlotInvalid, got {other:?}"),
}
}
#[test]
fn target_view_store_slot_passes_through_to_typed_view() {
let store = WitContract {
de: "a".into(),
para: "b".into(),
wit: "wasi:keyvalue/store".into(),
endpoint: None,
subject: None,
slot: Some("checkout/$orderId".into()),
};
match store.target().unwrap() {
WitTarget::Store { slot } => {
assert_eq!(slot, "checkout/$orderId");
}
other => panic!("expected Store, got {other:?}"),
}
}
#[test]
fn rejects_self_loop_in_synchronous_contratos() {
let mut s = three_member_spec();
s.contratos.push(contract_http("cart", "cart", "/loop"));
let err = s.validate().unwrap_err();
match err {
AplicacaoError::ContratoSelfLoop { caixa, wit } => {
assert_eq!(caixa, "cart");
assert_eq!(wit, "wasi:http/proxy");
}
other => panic!("expected ContratoSelfLoop, got {other:?}"),
}
}
#[test]
fn rejects_self_loop_in_pubsub_contratos() {
let mut s = three_member_spec();
s.contratos.push(WitContract {
de: "payment".into(),
para: "payment".into(),
wit: "nats:pub-sub".into(),
endpoint: None,
subject: Some("rio.events.payment".into()),
slot: None,
});
let err = s.validate().unwrap_err();
match err {
AplicacaoError::ContratoSelfLoop { caixa, wit } => {
assert_eq!(caixa, "payment");
assert_eq!(wit, "nats:pub-sub");
}
other => panic!("expected ContratoSelfLoop, got {other:?}"),
}
}
#[test]
fn self_loop_fires_before_payload_shape_check() {
let mut s = three_member_spec();
s.contratos.push(WitContract {
de: "cart".into(),
para: "cart".into(),
wit: "wasi:http/proxy".into(),
endpoint: Some("not-absolute".into()),
subject: None,
slot: None,
});
match s.validate().unwrap_err() {
AplicacaoError::ContratoSelfLoop { caixa, .. } => assert_eq!(caixa, "cart"),
other => panic!("expected ContratoSelfLoop, got {other:?}"),
}
}
#[test]
fn self_loop_fires_before_membership_is_satisfied_but_after_missing_member() {
let mut s = three_member_spec();
s.contratos.push(contract_http("ghost", "ghost", "/loop"));
match s.validate().unwrap_err() {
AplicacaoError::ContratoMemberMissing { caixa } => assert_eq!(caixa, "ghost"),
other => panic!("expected ContratoMemberMissing, got {other:?}"),
}
}
#[test]
fn rejects_two_node_synchronous_cycle() {
let mut s = three_member_spec();
s.contratos
.push(contract_http("catalog", "cart", "/refresh"));
let err = s.validate().unwrap_err();
match err {
AplicacaoError::ContratoCycle { cycle } => {
assert!(cycle.len() >= 3);
assert_eq!(cycle.first(), cycle.last());
let body: std::collections::HashSet<_> = cycle.iter().cloned().collect();
assert!(body.contains("cart"));
assert!(body.contains("catalog"));
}
other => panic!("expected ContratoCycle, got {other:?}"),
}
}
#[test]
fn rejects_three_node_synchronous_cycle() {
let mut s = three_member_spec();
s.contratos = vec![
contract_http("catalog", "cart", "/x"),
contract_http("cart", "payment", "/y"),
contract_http("payment", "catalog", "/z"),
];
let err = s.validate().unwrap_err();
match err {
AplicacaoError::ContratoCycle { cycle } => {
assert_eq!(cycle.first(), cycle.last());
let body: std::collections::HashSet<_> = cycle.iter().cloned().collect();
assert_eq!(body.len(), 3);
assert!(body.contains("cart"));
assert!(body.contains("catalog"));
assert!(body.contains("payment"));
}
other => panic!("expected ContratoCycle, got {other:?}"),
}
}
#[test]
fn pubsub_edge_breaks_cycle_per_mesh_composition_iii_3() {
let mut s = three_member_spec();
s.contratos = vec![
contract_http("catalog", "cart", "/x"),
contract_http("cart", "payment", "/y"),
WitContract {
de: "payment".into(),
para: "catalog".into(),
wit: "nats:pub-sub".into(),
endpoint: None,
subject: Some("checkout.events.charge.completed".into()),
slot: None,
},
];
s.validate().expect("pub-sub edge breaks the sync cycle");
}
#[test]
fn store_edge_counts_as_synchronous_for_cycle_detection() {
let mut s = three_member_spec();
s.contratos = vec![
contract_http("catalog", "cart", "/x"),
WitContract {
de: "cart".into(),
para: "catalog".into(),
wit: "wasi:keyvalue/store".into(),
endpoint: None,
subject: None,
slot: Some("session/$id".into()),
},
];
let err = s.validate().unwrap_err();
assert!(matches!(err, AplicacaoError::ContratoCycle { .. }));
}
#[test]
fn capability_edge_counts_as_synchronous_for_cycle_detection() {
let mut s = three_member_spec();
s.contratos = vec![
contract_http("catalog", "cart", "/x"),
WitContract {
de: "cart".into(),
para: "catalog".into(),
wit: "custom:exchange".into(),
endpoint: None,
subject: None,
slot: None,
},
];
let err = s.validate().unwrap_err();
assert!(matches!(err, AplicacaoError::ContratoCycle { .. }));
}
#[test]
fn long_acyclic_chain_validates() {
let mut s = three_member_spec();
s.membros = vec![
membro("a", "^0.1"),
membro("b", "^0.1"),
membro("c", "^0.1"),
membro("d", "^0.1"),
membro("e", "^0.1"),
];
s.contratos = vec![
contract_http("a", "b", "/1"),
contract_http("b", "c", "/2"),
contract_http("c", "d", "/3"),
contract_http("d", "e", "/4"),
];
s.entrada.as_mut().unwrap().para = "a".into();
s.validate().unwrap();
}
#[test]
fn diamond_acyclic_validates() {
let mut s = three_member_spec();
s.membros = vec![
membro("a", "^0.1"),
membro("b", "^0.1"),
membro("c", "^0.1"),
membro("d", "^0.1"),
];
s.contratos = vec![
contract_http("a", "b", "/1"),
contract_http("a", "c", "/2"),
contract_http("b", "d", "/3"),
contract_http("c", "d", "/4"),
];
s.entrada.as_mut().unwrap().para = "a".into();
s.validate().unwrap();
}
#[test]
fn rejects_duplicate_http_contrato() {
let mut s = three_member_spec();
s.contratos
.push(contract_http("cart", "catalog", "/products/:id"));
let err = s.validate().unwrap_err();
assert!(
matches!(
err,
AplicacaoError::ContratoDuplicate { ref de, ref para, ref wit, .. }
if de == "cart" && para == "catalog" && wit == "wasi:http/proxy"
),
"got {err:?}"
);
}
#[test]
fn rejects_duplicate_pubsub_contrato() {
let mut s = three_member_spec();
let pubsub = WitContract {
de: "payment".into(),
para: "cart".into(),
wit: "nats:pub-sub".into(),
endpoint: None,
subject: Some("checkout.events.charge.failed".into()),
slot: None,
};
s.contratos.push(pubsub.clone());
s.contratos.push(pubsub);
let err = s.validate().unwrap_err();
assert!(
matches!(
err,
AplicacaoError::ContratoDuplicate { ref de, ref para, ref wit, .. }
if de == "payment" && para == "cart" && wit == "nats:pub-sub"
),
"got {err:?}"
);
}
#[test]
fn rejects_duplicate_store_contrato() {
let mut s = three_member_spec();
let store = WitContract {
de: "cart".into(),
para: "payment".into(),
wit: "wasi:keyvalue/store".into(),
endpoint: None,
subject: None,
slot: Some("checkout/$orderId".into()),
};
s.contratos
.retain(|c| !(c.de == "cart" && c.para == "payment"));
s.contratos.push(store.clone());
s.contratos.push(store);
let err = s.validate().unwrap_err();
assert!(
matches!(
err,
AplicacaoError::ContratoDuplicate { ref de, ref para, ref wit, .. }
if de == "cart" && para == "payment" && wit == "wasi:keyvalue/store"
),
"got {err:?}"
);
}
#[test]
fn rejects_duplicate_capability_contrato() {
let mut s = three_member_spec();
let capability = WitContract {
de: "cart".into(),
para: "catalog".into(),
wit: "pleme:cap/audit".into(),
endpoint: None,
subject: None,
slot: None,
};
s.contratos.push(capability.clone());
s.contratos.push(capability);
let err = s.validate().unwrap_err();
match err {
AplicacaoError::ContratoDuplicate {
de,
para,
wit,
target,
} => {
assert_eq!(de, "cart");
assert_eq!(para, "catalog");
assert_eq!(wit, "pleme:cap/audit");
assert!(
target.contains("capability"),
"capability-edge duplicate diagnostic must surface the \
no-payload shape (got target = {target:?})"
);
}
other => panic!("expected ContratoDuplicate, got {other:?}"),
}
}
#[test]
fn accepts_distinct_http_paths_between_same_pair() {
let mut s = three_member_spec();
s.contratos
.push(contract_http("cart", "catalog", "/search"));
s.validate()
.expect("distinct endpoints between same (de, para) must validate");
}
#[test]
fn accepts_same_endpoint_on_different_pairs() {
let mut s = three_member_spec();
s.contratos
.push(contract_http("payment", "catalog", "/charge"));
s.validate()
.expect("same endpoint reused on distinct (de, para) must validate");
}
#[test]
fn rejects_duplicate_contrato_diagnostic_names_offending_target() {
let mut s = three_member_spec();
s.contratos
.push(contract_http("cart", "catalog", "/products/:id"));
let err = s.validate().unwrap_err();
let msg = format!("{err}");
assert!(
msg.contains("\"/products/:id\""),
"duplicate-contrato diagnostic must name the offending \
:endpoint payload (got: {msg:?})"
);
assert!(
msg.contains("cart") && msg.contains("catalog"),
"diagnostic must name both endpoints of the duplicate edge \
(got: {msg:?})"
);
}
#[test]
fn duplicate_contrato_gate_runs_after_membership_check() {
let mut s = three_member_spec();
s.contratos.push(contract_http("phantom", "catalog", "/x"));
s.contratos.push(contract_http("phantom", "catalog", "/x"));
let err = s.validate().unwrap_err();
assert!(
matches!(err, AplicacaoError::ContratoMemberMissing { ref caixa } if caixa == "phantom"),
"membership-missing must fire before duplicate-edge (got {err:?})"
);
}
#[test]
fn duplicate_contrato_gate_runs_after_target_shape_check() {
let mut s = three_member_spec();
let malformed = WitContract {
de: "cart".into(),
para: "catalog".into(),
wit: "wasi:http/proxy".into(),
endpoint: Some(String::new()),
subject: None,
slot: None,
};
s.contratos.push(malformed.clone());
s.contratos.push(malformed);
let err = s.validate().unwrap_err();
assert!(
matches!(err, AplicacaoError::ContratoEndpointEmpty { .. }),
"endpoint-empty must fire before duplicate-edge (got {err:?})"
);
}
#[test]
fn wit_target_label_pins_per_variant_format() {
assert_eq!(
WitTarget::Http {
endpoint: "/charge",
}
.label(),
"\
:endpoint \"/charge\""
);
assert_eq!(
WitTarget::PubSub {
subject: "events.checkout.paid",
}
.label(),
"\
:subject \"events.checkout.paid\""
);
assert_eq!(
WitTarget::Store {
slot: "checkout/$order",
}
.label(),
"\
:slot \"checkout/$order\""
);
assert_eq!(WitTarget::Capability.label(), "(capability — no payload)");
assert_eq!(WitTarget::Capability.label(), WitTarget::CAPABILITY_LABEL,);
assert_eq!(WitTarget::CAPABILITY_LABEL, "(capability — no payload)");
}
#[test]
fn wit_target_display_routes_through_label_helper() {
for variant in [
WitTarget::Http {
endpoint: "/charge",
},
WitTarget::PubSub {
subject: "events.checkout.paid",
},
WitTarget::Store {
slot: "checkout/$order",
},
WitTarget::Capability,
] {
assert_eq!(
variant.to_string(),
variant.label(),
"WitTarget::{variant:?} Display must route through \
WitTarget::label (single source of truth: the lifted \
payload_pair 4-arm dispatch the label helper already \
threads through)"
);
}
}
#[test]
fn wit_target_display_matches_duplicate_contratos_diagnostic_carrier() {
for variant in [
WitTarget::Http {
endpoint: "/charge",
},
WitTarget::PubSub {
subject: "events.checkout.paid",
},
WitTarget::Store {
slot: "checkout/$order",
},
WitTarget::Capability,
] {
assert_eq!(
format!("{variant}"),
variant.label(),
"WitTarget::{variant:?} Display byte-string must match \
the AplicacaoError::ContratoDuplicate `target:` carrier \
the AplicacaoSpec::validate duplicate-`:contratos` gate \
seeds via WitTarget::label — three-path convergence: \
Display + label + payload_pair all resolve to the same \
per-arm byte-string"
);
}
}
#[test]
fn wit_target_payload_pair_pins_per_variant() {
assert_eq!(
WitTarget::Http {
endpoint: "/charge"
}
.payload_pair(),
Some((WitTarget::HTTP_FIELD_NAME, "/charge")),
);
assert_eq!(
WitTarget::PubSub {
subject: "events.x",
}
.payload_pair(),
Some((WitTarget::PUBSUB_FIELD_NAME, "events.x")),
);
assert_eq!(
WitTarget::Store {
slot: "checkout/$order",
}
.payload_pair(),
Some((WitTarget::STORE_FIELD_NAME, "checkout/$order")),
);
assert_eq!(WitTarget::Capability.payload_pair(), None);
}
#[test]
fn wit_target_field_name_pins_per_variant() {
assert_eq!(
WitTarget::Http {
endpoint: "/charge"
}
.field_name(),
Some(WitTarget::HTTP_FIELD_NAME),
);
assert_eq!(
WitTarget::PubSub {
subject: "events.x",
}
.field_name(),
Some(WitTarget::PUBSUB_FIELD_NAME),
);
assert_eq!(
WitTarget::Store {
slot: "checkout/$order",
}
.field_name(),
Some(WitTarget::STORE_FIELD_NAME),
);
assert_eq!(WitTarget::Capability.field_name(), None);
assert_eq!(WitTarget::HTTP_FIELD_NAME, "endpoint");
assert_eq!(WitTarget::PUBSUB_FIELD_NAME, "subject");
assert_eq!(WitTarget::STORE_FIELD_NAME, "slot");
}
#[test]
fn wit_target_field_names_are_pairwise_distinct() {
assert_ne!(WitTarget::HTTP_FIELD_NAME, WitTarget::PUBSUB_FIELD_NAME);
assert_ne!(WitTarget::HTTP_FIELD_NAME, WitTarget::STORE_FIELD_NAME);
assert_ne!(WitTarget::PUBSUB_FIELD_NAME, WitTarget::STORE_FIELD_NAME);
}
#[test]
fn wit_target_expected_scalars_are_pairwise_distinct_across_all_four_arms() {
let all = [
WitTarget::HTTP_FIELD_NAME,
WitTarget::PUBSUB_FIELD_NAME,
WitTarget::STORE_FIELD_NAME,
WitTarget::CAPABILITY_EXPECTED,
];
for (i, a) in all.iter().enumerate() {
for (j, b) in all.iter().enumerate() {
if i != j {
assert_ne!(
a, b,
"WitTarget::{{HTTP_FIELD_NAME, PUBSUB_FIELD_NAME, \
STORE_FIELD_NAME, CAPABILITY_EXPECTED}} consts must be \
pairwise distinct — got duplicate {a:?} at indices \
{i} and {j}; all four scalars thread through the \
shared `AplicacaoError::ContratoWrongTarget::expected` \
&'static str axis, so a collapse silently misdirects \
the diagnostic on which typed shape the WIT world admits",
);
}
}
}
}
#[test]
fn wit_target_is_variant_predicates_partition_the_arm_set() {
let rows: [(WitTarget<'static>, [bool; 4]); 4] = [
(
WitTarget::Http { endpoint: "/x" },
[true, false, false, false],
),
(
WitTarget::PubSub {
subject: "events.x",
},
[false, true, false, false],
),
(
WitTarget::Store { slot: "kv/x" },
[false, false, true, false],
),
(WitTarget::Capability, [false, false, false, true]),
];
for (variant, expected) in rows {
let observed = [
variant.is_http(),
variant.is_pubsub(),
variant.is_store(),
variant.is_capability(),
];
assert_eq!(
observed, expected,
"WitTarget::{variant:?} is_* predicates must partition \
the arm set (http, pubsub, store, capability); got {observed:?}"
);
}
}
#[test]
fn wit_target_is_variant_predicates_are_const_fn() {
const HTTP: WitTarget<'static> = WitTarget::Http { endpoint: "/x" };
const PUBSUB: WitTarget<'static> = WitTarget::PubSub { subject: "e" };
const STORE: WitTarget<'static> = WitTarget::Store { slot: "kv/x" };
const CAPABILITY: WitTarget<'static> = WitTarget::Capability;
const IS_HTTP: bool = HTTP.is_http();
const IS_PUBSUB: bool = PUBSUB.is_pubsub();
const IS_STORE: bool = STORE.is_store();
const IS_CAPABILITY: bool = CAPABILITY.is_capability();
assert!(IS_HTTP);
assert!(IS_PUBSUB);
assert!(IS_STORE);
assert!(IS_CAPABILITY);
}
#[test]
fn detect_sync_cycles_skips_pubsub_edges_through_is_pubsub_predicate() {
let s = AplicacaoSpec {
membros: vec![membro("a", "^0.1"), membro("b", "^0.1")],
contratos: vec![
WitContract {
de: "a".into(),
para: "b".into(),
wit: "nats:pub-sub".into(),
endpoint: None,
subject: Some("events.x".into()),
slot: None,
},
WitContract {
de: "b".into(),
para: "a".into(),
wit: "wasi:http/proxy".into(),
endpoint: Some("/x".into()),
subject: None,
slot: None,
},
],
politicas: MeshPolicy::default(),
placement: Placement {
estrategia: PlacementStrategy::Replicated,
clusters: vec!["rio".into()],
affinity: None,
shard_key: None,
},
entrada: None,
};
s.validate()
.expect("pub-sub edge must be excluded from sync-cycle DFS");
}
#[test]
fn wit_target_field_name_routes_through_label_and_expected_diagnostic() {
let http_label = WitTarget::Http { endpoint: "/x" }.label();
assert!(
http_label.starts_with(&format!(":{} ", WitTarget::HTTP_FIELD_NAME)),
"label must lead with :{} keyword (got {http_label:?})",
WitTarget::HTTP_FIELD_NAME,
);
let mut s = three_member_spec();
s.contratos.push(WitContract {
de: "cart".into(),
para: "catalog".into(),
wit: "kafka:topic".into(),
endpoint: None,
subject: None,
slot: None,
});
match s.validate().unwrap_err() {
AplicacaoError::ContratoMissingTarget { expected, .. } => {
assert_eq!(expected, WitTarget::PUBSUB_FIELD_NAME);
}
other => panic!("expected ContratoMissingTarget, got {other:?}"),
}
}
#[test]
fn duplicate_pubsub_diagnostic_names_offending_subject() {
let mut s = three_member_spec();
let pubsub = WitContract {
de: "payment".into(),
para: "cart".into(),
wit: "nats:pub-sub".into(),
endpoint: None,
subject: Some("events.checkout.paid".into()),
slot: None,
};
s.contratos.push(pubsub.clone());
s.contratos.push(pubsub);
let err = s.validate().unwrap_err();
let msg = format!("{err}");
assert!(
msg.contains(":subject \"events.checkout.paid\""),
"duplicate-pubsub diagnostic must name the offending \
:subject payload (got: {msg:?})"
);
}
#[test]
fn duplicate_store_diagnostic_names_offending_slot() {
let mut s = three_member_spec();
let store = WitContract {
de: "cart".into(),
para: "payment".into(),
wit: "wasi:keyvalue/store".into(),
endpoint: None,
subject: None,
slot: Some("checkout/$orderId".into()),
};
s.contratos
.retain(|c| !(c.de == "cart" && c.para == "payment"));
s.contratos.push(store.clone());
s.contratos.push(store);
let err = s.validate().unwrap_err();
let msg = format!("{err}");
assert!(
msg.contains(":slot \"checkout/$orderId\""),
"duplicate-store diagnostic must name the offending :slot \
payload (got: {msg:?})"
);
}
#[test]
fn rejects_entrada_path_without_leading_slash() {
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().paths = vec!["/api/cart".into(), "api/products".into()];
let err = s.validate().unwrap_err();
assert!(
matches!(err, AplicacaoError::EntradaPathNotAbsolute { ref path } if path == "api/products"),
"got {err:?}"
);
}
#[test]
fn rejects_empty_entrada_path() {
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().paths = vec!["/api/cart".into(), "".into()];
assert_eq!(s.validate().unwrap_err(), AplicacaoError::EntradaPathEmpty);
}
#[test]
fn rejects_duplicate_entrada_paths() {
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().paths = vec![
"/api/cart".into(),
"/api/products".into(),
"/api/cart".into(),
];
let err = s.validate().unwrap_err();
assert!(
matches!(err, AplicacaoError::EntradaPathDuplicate { ref path } if path == "/api/cart"),
"got {err:?}"
);
}
#[test]
fn rejects_zero_entrada_port() {
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().port = 0;
assert_eq!(s.validate().unwrap_err(), AplicacaoError::EntradaPortZero);
}
#[test]
fn rejects_entrada_path_with_query() {
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().paths = vec!["/api/cart?q=1".into()];
let err = s.validate().unwrap_err();
assert!(
matches!(err, AplicacaoError::EntradaPathInvalid { ref path, ref reason }
if path == "/api/cart?q=1" && reason.contains("must not contain `?`")),
"got {err:?}"
);
}
#[test]
fn rejects_entrada_path_with_fragment() {
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().paths = vec!["/api/cart#frag".into()];
let err = s.validate().unwrap_err();
assert!(
matches!(err, AplicacaoError::EntradaPathInvalid { ref path, ref reason }
if path == "/api/cart#frag" && reason.contains("must not contain `#`")),
"got {err:?}"
);
}
#[test]
fn rejects_entrada_path_with_space() {
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().paths = vec!["/api/my cart".into()];
let err = s.validate().unwrap_err();
assert!(
matches!(err, AplicacaoError::EntradaPathInvalid { ref path, ref reason }
if path == "/api/my cart" && reason.contains("whitespace")),
"got {err:?}"
);
}
#[test]
fn rejects_entrada_path_with_tab() {
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().paths = vec!["/api/\tcart".into()];
let err = s.validate().unwrap_err();
assert!(
matches!(err, AplicacaoError::EntradaPathInvalid { ref path, ref reason }
if path == "/api/\tcart" && reason.contains("whitespace")),
"got {err:?}"
);
}
#[test]
fn rejects_entrada_path_with_control_char() {
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().paths = vec!["/api/\x01cart".into()];
let err = s.validate().unwrap_err();
assert!(
matches!(err, AplicacaoError::EntradaPathInvalid { ref path, ref reason }
if path == "/api/\x01cart" && reason.contains("control character")),
"got {err:?}"
);
}
#[test]
fn rejects_entrada_path_with_non_ascii() {
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().paths = vec!["/api/café".into()];
let err = s.validate().unwrap_err();
assert!(
matches!(err, AplicacaoError::EntradaPathInvalid { ref path, ref reason }
if path == "/api/café" && reason.contains("non-ASCII")),
"got {err:?}"
);
}
#[test]
fn rejects_entrada_path_with_consecutive_slashes() {
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().paths = vec!["/api//cart".into()];
let err = s.validate().unwrap_err();
assert!(
matches!(err, AplicacaoError::EntradaPathInvalid { ref path, ref reason }
if path == "/api//cart" && reason.contains("consecutive `/`")),
"got {err:?}"
);
}
#[test]
fn rejects_entrada_path_with_dot_segment() {
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().paths = vec!["/api/./cart".into()];
let err = s.validate().unwrap_err();
assert!(
matches!(err, AplicacaoError::EntradaPathInvalid { ref path, ref reason }
if path == "/api/./cart" && reason.contains("`.` segment")),
"got {err:?}"
);
}
#[test]
fn rejects_entrada_path_with_trailing_dot_segment() {
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().paths = vec!["/api/.".into()];
let err = s.validate().unwrap_err();
assert!(
matches!(err, AplicacaoError::EntradaPathInvalid { ref path, ref reason }
if path == "/api/." && reason.contains("`.` segment")),
"got {err:?}"
);
}
#[test]
fn rejects_entrada_path_with_parent_segment() {
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().paths = vec!["/api/../etc".into()];
let err = s.validate().unwrap_err();
assert!(
matches!(err, AplicacaoError::EntradaPathInvalid { ref path, ref reason }
if path == "/api/../etc" && reason.contains("`..` parent-segment")),
"got {err:?}"
);
}
#[test]
fn rejects_entrada_path_with_trailing_parent_segment() {
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().paths = vec!["/api/..".into()];
let err = s.validate().unwrap_err();
assert!(
matches!(err, AplicacaoError::EntradaPathInvalid { ref path, ref reason }
if path == "/api/.." && reason.contains("`..` parent-segment")),
"got {err:?}"
);
}
#[test]
fn rejects_entrada_path_too_long() {
let mut s = three_member_spec();
let big = format!("/api/{}", "a".repeat(1020));
assert_eq!(big.len(), 1025);
s.entrada.as_mut().unwrap().paths = vec![big.clone()];
let err = s.validate().unwrap_err();
assert!(
matches!(err, AplicacaoError::EntradaPathInvalid { ref path, ref reason }
if path == &big && reason.contains("max length of 1024")),
"got {err:?}"
);
}
#[test]
fn entrada_path_max_length_validates() {
let mut s = three_member_spec();
let big = format!("/api/{}", "a".repeat(1019));
assert_eq!(big.len(), 1024);
s.entrada.as_mut().unwrap().paths = vec![big];
s.validate().unwrap();
}
#[test]
fn entrada_accepts_canonical_paths() {
for path in [
"/",
"/api/cart",
"/healthz",
"/api/.config",
"/v1/products",
"/products/:id",
"/api/cart/",
"/api/caf%C3%A9",
"/foo..bar",
"/...",
] {
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().paths = vec![path.into()];
s.validate()
.unwrap_or_else(|e| panic!("expected {path:?} to validate, got {e:?}"));
}
}
#[test]
fn entrada_path_empty_takes_precedence_over_invalid() {
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().paths = vec!["".into()];
assert_eq!(s.validate().unwrap_err(), AplicacaoError::EntradaPathEmpty);
}
#[test]
fn entrada_path_not_absolute_takes_precedence_over_invalid() {
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().paths = vec!["bad path".into()];
let err = s.validate().unwrap_err();
assert!(
matches!(err, AplicacaoError::EntradaPathNotAbsolute { ref path } if path == "bad path"),
"got {err:?}"
);
}
#[test]
fn entrada_path_invalid_fires_before_duplicate_check() {
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().paths = vec!["/api?q".into(), "/api?q".into()];
let err = s.validate().unwrap_err();
assert!(
matches!(err, AplicacaoError::EntradaPathInvalid { ref path, .. } if path == "/api?q"),
"got {err:?}"
);
}
#[test]
fn entrada_path_diagnostic_carries_offending_path() {
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().paths = vec!["/api?q=1".into()];
let err = s.validate().unwrap_err();
match err {
AplicacaoError::EntradaPathInvalid { path, reason } => {
assert_eq!(path, "/api?q=1");
assert!(!reason.is_empty(), "reason field must be non-empty");
}
other => panic!("expected EntradaPathInvalid, got {other:?}"),
}
}
#[test]
fn rejects_entrada_path_with_curly_brace_template_form() {
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().paths = vec!["/api/cart/{id}".into()];
let err = s.validate().unwrap_err();
assert!(
matches!(err, AplicacaoError::EntradaPathInvalid { ref path, ref reason }
if path == "/api/cart/{id}"
&& reason.contains("reserved character")
&& reason.contains("'{'")
&& reason.contains("%7B")),
"got {err:?}"
);
}
#[test]
fn rejects_http_contrato_endpoint_with_curly_brace_template_form() {
let err = contrato_endpoint_err("/api/cart/{id}");
assert!(
matches!(err, AplicacaoError::ContratoEndpointInvalid { ref endpoint, ref reason, .. }
if endpoint == "/api/cart/{id}"
&& reason.contains("reserved character")
&& reason.contains("'{'")
&& reason.contains("%7B")),
"got {err:?}"
);
}
#[test]
fn rejects_entrada_host_with_scheme() {
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().host = "https://checkout.quero.cloud".into();
let err = s.validate().unwrap_err();
assert!(
matches!(err, AplicacaoError::EntradaHostInvalid { ref host, .. }
if host == "https://checkout.quero.cloud"),
"got {err:?}"
);
}
#[test]
fn rejects_entrada_host_with_port() {
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().host = "checkout.quero.cloud:8080".into();
let err = s.validate().unwrap_err();
assert!(
matches!(err, AplicacaoError::EntradaHostInvalid { ref host, ref reason }
if host == "checkout.quero.cloud:8080"
&& reason.contains(":entrada :port")),
"got {err:?}"
);
}
#[test]
fn rejects_entrada_host_with_trailing_colon() {
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().host = "checkout.quero.cloud:".into();
let err = s.validate().unwrap_err();
assert!(
matches!(err, AplicacaoError::EntradaHostInvalid { ref host, ref reason }
if host == "checkout.quero.cloud:"
&& reason.contains(":entrada :port")),
"got {err:?}"
);
}
#[test]
fn rejects_entrada_host_unbracketed_ipv6_literal() {
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().host = "2001:db8::1".into();
let err = s.validate().unwrap_err();
assert!(
matches!(err, AplicacaoError::EntradaHostInvalid { ref host, ref reason }
if host == "2001:db8::1"
&& reason.contains("IPv6")),
"got {err:?}"
);
}
#[test]
fn rejects_entrada_host_wildcard_with_port() {
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().host = "*.quero.cloud:8080".into();
let err = s.validate().unwrap_err();
assert!(
matches!(err, AplicacaoError::EntradaHostInvalid { ref host, ref reason }
if host == "*.quero.cloud:8080"
&& reason.contains(":entrada :port")),
"got {err:?}"
);
}
#[test]
fn rejects_entrada_host_with_path() {
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().host = "checkout.quero.cloud/api".into();
let err = s.validate().unwrap_err();
assert!(
matches!(err, AplicacaoError::EntradaHostInvalid { ref host, .. }
if host == "checkout.quero.cloud/api"),
"got {err:?}"
);
}
#[test]
fn rejects_entrada_host_with_uppercase() {
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().host = "Checkout.quero.cloud".into();
let err = s.validate().unwrap_err();
assert!(
matches!(err, AplicacaoError::EntradaHostInvalid { ref reason, .. }
if reason.contains("uppercase")),
"got {err:?}"
);
}
#[test]
fn rejects_entrada_host_with_underscore() {
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().host = "checkout_app.quero.cloud".into();
let err = s.validate().unwrap_err();
assert!(
matches!(err, AplicacaoError::EntradaHostInvalid { ref reason, .. }
if reason.contains('_')),
"got {err:?}"
);
}
#[test]
fn rejects_entrada_host_ipv4_literal() {
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().host = "10.0.0.1".into();
let err = s.validate().unwrap_err();
assert!(
matches!(err, AplicacaoError::EntradaHostInvalid { ref reason, .. }
if reason.contains("IPv4")),
"got {err:?}"
);
}
#[test]
fn rejects_entrada_host_with_trailing_dot() {
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().host = "checkout.quero.cloud.".into();
let err = s.validate().unwrap_err();
assert!(
matches!(err, AplicacaoError::EntradaHostInvalid { ref host, .. }
if host == "checkout.quero.cloud."),
"got {err:?}"
);
}
#[test]
fn rejects_entrada_host_with_leading_dot() {
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().host = ".checkout.quero.cloud".into();
let err = s.validate().unwrap_err();
assert!(
matches!(err, AplicacaoError::EntradaHostInvalid { ref reason, .. }
if reason.contains("empty label")),
"got {err:?}"
);
}
#[test]
fn rejects_entrada_host_with_consecutive_dots() {
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().host = "checkout..quero.cloud".into();
let err = s.validate().unwrap_err();
assert!(
matches!(err, AplicacaoError::EntradaHostInvalid { ref reason, .. }
if reason.contains("empty label")),
"got {err:?}"
);
}
#[test]
fn rejects_entrada_host_with_leading_hyphen_label() {
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().host = "-checkout.quero.cloud".into();
let err = s.validate().unwrap_err();
assert!(
matches!(err, AplicacaoError::EntradaHostInvalid { ref reason, .. }
if reason.contains("alphanumeric")),
"got {err:?}"
);
}
#[test]
fn rejects_entrada_host_with_trailing_hyphen_label() {
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().host = "checkout-.quero.cloud".into();
let err = s.validate().unwrap_err();
assert!(
matches!(err, AplicacaoError::EntradaHostInvalid { ref reason, .. }
if reason.contains("alphanumeric")),
"got {err:?}"
);
}
#[test]
fn rejects_entrada_host_with_inner_wildcard() {
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().host = "checkout.*.quero.cloud".into();
let err = s.validate().unwrap_err();
assert!(
matches!(err, AplicacaoError::EntradaHostInvalid { ref reason, .. }
if reason.contains("wildcard")),
"got {err:?}"
);
}
#[test]
fn rejects_entrada_host_bare_wildcard() {
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().host = "*.".into();
let err = s.validate().unwrap_err();
assert!(
matches!(err, AplicacaoError::EntradaHostInvalid { ref reason, .. }
if reason.contains("wildcard")),
"got {err:?}"
);
}
#[test]
fn rejects_entrada_host_with_whitespace() {
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().host = "checkout .quero.cloud".into();
let err = s.validate().unwrap_err();
assert!(
matches!(err, AplicacaoError::EntradaHostInvalid { ref reason, .. }
if reason.contains("whitespace")),
"got {err:?}"
);
}
#[test]
fn rejects_entrada_host_space_names_offending_byte() {
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().host = "checkout .quero.cloud".into();
let err = s.validate().unwrap_err();
let AplicacaoError::EntradaHostInvalid { reason, .. } = err else {
panic!("expected EntradaHostInvalid, got {err:?}");
};
assert!(
reason.contains("ASCII whitespace byte"),
"expected byte-naming diagnostic, got {reason:?}"
);
assert!(
reason.contains("0x20"),
"expected offending space byte 0x20, got {reason:?}"
);
}
#[test]
fn rejects_entrada_host_tab_names_offending_byte() {
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().host = "checkout.\tquero.cloud".into();
let err = s.validate().unwrap_err();
let AplicacaoError::EntradaHostInvalid { reason, .. } = err else {
panic!("expected EntradaHostInvalid, got {err:?}");
};
assert!(
reason.contains("ASCII whitespace byte"),
"expected byte-naming diagnostic, got {reason:?}"
);
assert!(
reason.contains("0x09"),
"expected offending tab byte 0x09, got {reason:?}"
);
}
#[test]
fn rejects_entrada_host_lf_names_offending_byte() {
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().host = "checkout\n.quero.cloud".into();
let err = s.validate().unwrap_err();
let AplicacaoError::EntradaHostInvalid { reason, .. } = err else {
panic!("expected EntradaHostInvalid, got {err:?}");
};
assert!(
reason.contains("ASCII whitespace byte"),
"expected byte-naming diagnostic, got {reason:?}"
);
assert!(
reason.contains("0x0a"),
"expected offending LF byte 0x0a, got {reason:?}"
);
}
#[test]
fn rejects_entrada_host_nbsp_names_offending_codepoint() {
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().host = "\u{00A0}checkout.quero.cloud".into();
let err = s.validate().unwrap_err();
let AplicacaoError::EntradaHostInvalid { reason, .. } = err else {
panic!("expected EntradaHostInvalid, got {err:?}");
};
assert!(
reason.contains("non-ASCII Unicode whitespace character"),
"expected non-ASCII codepoint-naming diagnostic, got {reason:?}"
);
assert!(
reason.contains("U+00A0"),
"expected offending NBSP codepoint U+00A0, got {reason:?}"
);
}
#[test]
fn rejects_entrada_host_line_separator_names_offending_codepoint() {
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().host = "checkout.quero.cloud\u{2028}".into();
let err = s.validate().unwrap_err();
let AplicacaoError::EntradaHostInvalid { reason, .. } = err else {
panic!("expected EntradaHostInvalid, got {err:?}");
};
assert!(
reason.contains("non-ASCII Unicode whitespace character"),
"expected non-ASCII codepoint-naming diagnostic, got {reason:?}"
);
assert!(
reason.contains("U+2028"),
"expected offending LINE SEPARATOR codepoint U+2028, got {reason:?}"
);
}
#[test]
fn rejects_entrada_host_ideographic_space_names_offending_codepoint() {
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().host = "checkout\u{3000}.quero.cloud".into();
let err = s.validate().unwrap_err();
let AplicacaoError::EntradaHostInvalid { reason, .. } = err else {
panic!("expected EntradaHostInvalid, got {err:?}");
};
assert!(
reason.contains("non-ASCII Unicode whitespace character"),
"expected non-ASCII codepoint-naming diagnostic, got {reason:?}"
);
assert!(
reason.contains("U+3000"),
"expected offending IDEOGRAPHIC SPACE codepoint U+3000, got {reason:?}"
);
}
#[test]
fn rejects_entrada_host_too_long() {
let mut s = three_member_spec();
let big = format!(
"{}.{}.{}.{}",
"a".repeat(63),
"b".repeat(63),
"c".repeat(63),
"d".repeat(254 - 63 * 3 - 3)
);
assert_eq!(big.len(), 254);
s.entrada.as_mut().unwrap().host = big;
let err = s.validate().unwrap_err();
assert!(
matches!(err, AplicacaoError::EntradaHostInvalid { ref reason, .. }
if reason.contains("max length of 253")),
"got {err:?}"
);
}
#[test]
fn rejects_entrada_host_label_too_long() {
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().host = format!("{}.quero.cloud", "x".repeat(64));
let err = s.validate().unwrap_err();
assert!(
matches!(err, AplicacaoError::EntradaHostInvalid { ref reason, .. }
if reason.contains("label max length of 63")),
"got {err:?}"
);
}
#[test]
fn entrada_host_diagnostic_carries_offending_host() {
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().host = "checkout.quero.cloud:8080".into();
let err = s.validate().unwrap_err();
match err {
AplicacaoError::EntradaHostInvalid { host, reason } => {
assert_eq!(host, "checkout.quero.cloud:8080");
assert!(!reason.is_empty(), "reason field must be non-empty");
}
other => panic!("expected EntradaHostInvalid, got {other:?}"),
}
}
#[test]
fn entrada_host_empty_takes_precedence_over_invalid() {
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().host = String::new();
assert_eq!(s.validate().unwrap_err(), AplicacaoError::EmptyEntradaHost);
}
#[test]
fn entrada_host_member_missing_takes_precedence_over_host_invalid() {
let mut s = three_member_spec();
let e = s.entrada.as_mut().unwrap();
e.para = "ghost".into();
e.host = "BAD HOST".into();
let err = s.validate().unwrap_err();
assert!(
matches!(err, AplicacaoError::EntradaMemberMissing { ref para } if para == "ghost"),
"got {err:?}"
);
}
#[test]
fn entrada_host_invalid_fires_before_port_zero() {
let mut s = three_member_spec();
let e = s.entrada.as_mut().unwrap();
e.host = "Checkout.quero.cloud".into();
e.port = 0;
let err = s.validate().unwrap_err();
assert!(
matches!(err, AplicacaoError::EntradaHostInvalid { ref host, .. }
if host == "Checkout.quero.cloud"),
"got {err:?}"
);
}
#[test]
fn entrada_accepts_canonical_hosts() {
for host in [
"checkout.quero.cloud",
"*.quero.cloud",
"checkout",
"abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0.quero.cloud",
"foo-bar.quero.cloud",
"xn--bcher-kva.example.com",
] {
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().host = host.into();
s.validate()
.unwrap_or_else(|e| panic!("expected {host:?} to validate, got {e:?}"));
}
}
#[test]
fn entrada_host_max_length_validates() {
let mut s = three_member_spec();
let host = format!(
"{}.{}.{}.{}",
"a".repeat(63),
"b".repeat(63),
"c".repeat(63),
"d".repeat(253 - 63 * 3 - 3)
);
assert_eq!(host.len(), 253);
s.entrada.as_mut().unwrap().host = host;
s.validate().unwrap();
}
#[test]
fn entrada_host_total_length_cap_threads_lifted_render_const() {
let mut s = three_member_spec();
let over_cap = format!(
"{}.{}.{}.{}",
"a".repeat(63),
"b".repeat(63),
"c".repeat(63),
"d".repeat(crate::render::GATEWAY_API_HOSTNAME_MAX_LEN + 1 - 63 * 3 - 3)
);
assert_eq!(
over_cap.len(),
crate::render::GATEWAY_API_HOSTNAME_MAX_LEN + 1
);
s.entrada.as_mut().unwrap().host = over_cap;
let err = s.validate().unwrap_err();
match err {
AplicacaoError::EntradaHostInvalid { reason, .. } => {
let needle = format!(
"max length of {} bytes",
crate::render::GATEWAY_API_HOSTNAME_MAX_LEN,
);
assert!(
reason.contains(&needle),
"diagnostic must name the lifted \
GATEWAY_API_HOSTNAME_MAX_LEN cap verbatim, got: {reason:?}",
);
}
other => panic!("expected EntradaHostInvalid, got {other:?}"),
}
}
#[test]
fn entrada_host_per_label_cap_threads_lifted_dns_1123_const() {
let mut s = three_member_spec();
let over_cap_label = format!(
"{}.quero.cloud",
"x".repeat(crate::render::DNS_1123_LABEL_MAX_LEN + 1),
);
s.entrada.as_mut().unwrap().host = over_cap_label;
let err = s.validate().unwrap_err();
match err {
AplicacaoError::EntradaHostInvalid { reason, .. } => {
let needle = format!(
"label max length of {} bytes",
crate::render::DNS_1123_LABEL_MAX_LEN,
);
assert!(
reason.contains(&needle),
"diagnostic must name the lifted DNS_1123_LABEL_MAX_LEN \
cap verbatim on the per-label arm, got: {reason:?}",
);
}
other => panic!("expected EntradaHostInvalid, got {other:?}"),
}
}
#[test]
fn entrada_with_empty_paths_validates() {
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().paths = vec![];
s.validate().unwrap();
}
#[test]
fn entrada_root_path_validates() {
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().paths = vec![crate::GATEWAY_API_DEFAULT_HTTP_ROUTE_PATH.into()];
s.validate().unwrap();
}
#[test]
fn placement_strategy_variants_round_trip() {
for s in [
PlacementStrategy::SingleNode,
PlacementStrategy::Replicated,
PlacementStrategy::Sharded,
] {
let p = Placement {
estrategia: s,
clusters: vec!["rio".into()],
affinity: None,
shard_key: if s.is_sharded() {
Some("$key".into())
} else {
None
},
};
let json = serde_json::to_string(&p).unwrap();
let back: Placement = serde_json::from_str(&json).unwrap();
assert_eq!(back, p);
}
}
#[test]
fn placement_strategy_variants_serialize_to_lifted_scalar_values() {
for (variant, expected) in [
(
PlacementStrategy::SingleNode,
crate::render::M3_PLACEMENT_ESTRATEGIA_SINGLE_NODE,
),
(
PlacementStrategy::Replicated,
crate::render::M3_PLACEMENT_ESTRATEGIA_REPLICATED,
),
(
PlacementStrategy::Sharded,
crate::render::M3_PLACEMENT_ESTRATEGIA_SHARDED,
),
] {
let json = serde_json::to_string(&variant).unwrap();
assert_eq!(
json,
format!("\"{expected}\""),
"PlacementStrategy::{variant:?} must serialize to {expected:?}"
);
assert_eq!(
variant.as_str(),
expected,
"PlacementStrategy::{variant:?}.as_str() must return the lifted \
M3_PLACEMENT_ESTRATEGIA_* constant"
);
}
}
#[test]
fn m3_placement_estrategia_consts_are_pairwise_distinct() {
let all = [
crate::render::M3_PLACEMENT_ESTRATEGIA_SINGLE_NODE,
crate::render::M3_PLACEMENT_ESTRATEGIA_REPLICATED,
crate::render::M3_PLACEMENT_ESTRATEGIA_SHARDED,
];
for (i, a) in all.iter().enumerate() {
for (j, b) in all.iter().enumerate() {
if i != j {
assert_ne!(
a, b,
"M3_PLACEMENT_ESTRATEGIA_* consts must be pairwise \
distinct — got duplicate {a:?} at indices {i} and {j}",
);
}
}
}
}
#[test]
fn placement_strategy_display_routes_through_as_str_helper() {
for variant in [
PlacementStrategy::SingleNode,
PlacementStrategy::Replicated,
PlacementStrategy::Sharded,
] {
assert_eq!(
variant.to_string(),
variant.as_str(),
"PlacementStrategy::{variant:?} Display must route through \
PlacementStrategy::as_str (single source of truth: the lifted \
M3_PLACEMENT_ESTRATEGIA_* const the wire format also emits)"
);
}
}
#[test]
fn placement_strategy_display_matches_serialized_wire_byte_string() {
for variant in [
PlacementStrategy::SingleNode,
PlacementStrategy::Replicated,
PlacementStrategy::Sharded,
] {
let wire = serde_json::to_string(&variant).unwrap();
let unquoted = wire
.strip_prefix('"')
.and_then(|s| s.strip_suffix('"'))
.expect("serialized PlacementStrategy is a JSON string");
assert_eq!(
variant.to_string(),
unquoted,
"PlacementStrategy::{variant:?} Display byte-string must match the \
Serialize derive's wire byte-string (three-path convergence: \
Display + as_str + Serialize all resolve to the same \
M3_PLACEMENT_ESTRATEGIA_* const)"
);
}
}
#[test]
fn placement_strategy_is_variant_predicates_partition_the_arm_set() {
let rows: [(PlacementStrategy, [bool; 3]); 3] = [
(PlacementStrategy::SingleNode, [true, false, false]),
(PlacementStrategy::Replicated, [false, true, false]),
(PlacementStrategy::Sharded, [false, false, true]),
];
for (variant, expected) in rows {
let observed = [
variant.is_single_node(),
variant.is_replicated(),
variant.is_sharded(),
];
assert_eq!(
observed, expected,
"PlacementStrategy::{variant:?} is_* predicates must partition \
the arm set (single_node, replicated, sharded); got {observed:?}"
);
}
}
#[test]
fn placement_strategy_is_variant_predicates_are_const_fn() {
const IS_SINGLE_NODE: bool = PlacementStrategy::SingleNode.is_single_node();
const IS_REPLICATED: bool = PlacementStrategy::Replicated.is_replicated();
const IS_SHARDED: bool = PlacementStrategy::Sharded.is_sharded();
assert!(IS_SINGLE_NODE);
assert!(IS_REPLICATED);
assert!(IS_SHARDED);
}
#[test]
fn placement_without_clusters_diagnostic_carries_strategy_display_byte_string() {
for (variant, expected_scalar) in [
(
PlacementStrategy::SingleNode,
crate::render::M3_PLACEMENT_ESTRATEGIA_SINGLE_NODE,
),
(
PlacementStrategy::Replicated,
crate::render::M3_PLACEMENT_ESTRATEGIA_REPLICATED,
),
(
PlacementStrategy::Sharded,
crate::render::M3_PLACEMENT_ESTRATEGIA_SHARDED,
),
] {
let err = AplicacaoError::PlacementWithoutClusters {
estrategia: variant,
};
let msg = err.to_string();
assert!(
msg.starts_with(&format!(":placement {expected_scalar} requires")),
"PlacementWithoutClusters diagnostic for {variant:?} must open \
with the lifted `{expected_scalar}` scalar via Display; got {msg:?}"
);
}
}
#[test]
fn shard_key_on_non_sharded_diagnostic_carries_strategy_display_byte_string() {
for (variant, expected_scalar) in [
(
PlacementStrategy::SingleNode,
crate::render::M3_PLACEMENT_ESTRATEGIA_SINGLE_NODE,
),
(
PlacementStrategy::Replicated,
crate::render::M3_PLACEMENT_ESTRATEGIA_REPLICATED,
),
] {
let err = AplicacaoError::ShardKeyOnNonSharded {
estrategia: variant,
shard_key: "$tenantId".into(),
};
let msg = err.to_string();
assert!(
msg.starts_with(&format!(":placement {expected_scalar} carries")),
"ShardKeyOnNonSharded diagnostic for {variant:?} must open with \
the lifted `{expected_scalar}` scalar via Display; got {msg:?}"
);
}
}
#[test]
fn rejects_zero_policy_timeout() {
let mut s = three_member_spec();
s.politicas.timeout = Some(Duration::ZERO);
assert_eq!(s.validate().unwrap_err(), AplicacaoError::PolicyTimeoutZero);
}
#[test]
fn rejects_zero_policy_retries() {
let mut s = three_member_spec();
s.politicas.retries = Some(0);
assert_eq!(s.validate().unwrap_err(), AplicacaoError::PolicyRetriesZero);
}
#[test]
fn rejects_policy_retries_above_cap() {
let mut s = three_member_spec();
s.politicas.retries = Some(POLICY_RETRIES_MAX + 1);
assert_eq!(
s.validate().unwrap_err(),
AplicacaoError::PolicyRetriesExceedsCap {
retries: POLICY_RETRIES_MAX + 1
}
);
}
#[test]
fn rejects_policy_retries_far_above_cap() {
let mut s = three_member_spec();
s.politicas.retries = Some(u32::MAX);
assert_eq!(
s.validate().unwrap_err(),
AplicacaoError::PolicyRetriesExceedsCap { retries: u32::MAX }
);
}
#[test]
fn accepts_policy_retries_at_cap() {
let mut s = three_member_spec();
s.politicas.retries = Some(POLICY_RETRIES_MAX);
s.validate()
.expect("retries == POLICY_RETRIES_MAX must validate");
}
#[test]
fn accepts_policy_retries_typical_values() {
for r in 1..=POLICY_RETRIES_MAX {
let mut s = three_member_spec();
s.politicas.retries = Some(r);
s.validate()
.unwrap_or_else(|e| panic!("retries={r} must validate; got {e:?}"));
}
}
#[test]
fn policy_retries_zero_takes_precedence_over_cap() {
let mut s = three_member_spec();
s.politicas.retries = Some(0);
assert_eq!(
s.validate().unwrap_err(),
AplicacaoError::PolicyRetriesZero,
"Some(0) must surface the zero-floor diagnostic, not the cap diagnostic"
);
}
#[test]
fn policy_retries_cap_diagnostic_carries_offending_value() {
let mut s = three_member_spec();
s.politicas.retries = Some(47);
let err = s.validate().unwrap_err();
assert!(
matches!(err, AplicacaoError::PolicyRetriesExceedsCap { retries: 47 }),
"got {err:?}"
);
let msg = err.to_string();
assert!(
msg.contains("47"),
":politicas :retries cap diagnostic must carry the offending value verbatim (got: {msg})"
);
}
#[test]
fn policy_retries_cap_is_aws_app_mesh_aligned() {
assert_eq!(POLICY_RETRIES_MAX, 10);
}
#[test]
fn rejects_circuit_breaker_zero_max_failures() {
let mut s = three_member_spec();
s.politicas.circuit_breaker = Some(CircuitBreaker {
max_failures: 0,
window: Duration::from_secs(60),
});
assert_eq!(
s.validate().unwrap_err(),
AplicacaoError::PolicyBreakerZeroFailures
);
}
#[test]
fn rejects_circuit_breaker_max_failures_above_cap() {
let mut s = three_member_spec();
s.politicas.circuit_breaker = Some(CircuitBreaker {
max_failures: POLICY_BREAKER_MAX_FAILURES_MAX + 1,
window: Duration::from_secs(60),
});
assert_eq!(
s.validate().unwrap_err(),
AplicacaoError::PolicyBreakerMaxFailuresExceedsCap {
max_failures: POLICY_BREAKER_MAX_FAILURES_MAX + 1,
}
);
}
#[test]
fn rejects_circuit_breaker_max_failures_far_above_cap() {
let mut s = three_member_spec();
s.politicas.circuit_breaker = Some(CircuitBreaker {
max_failures: u32::MAX,
window: Duration::from_secs(60),
});
assert_eq!(
s.validate().unwrap_err(),
AplicacaoError::PolicyBreakerMaxFailuresExceedsCap {
max_failures: u32::MAX,
}
);
}
#[test]
fn accepts_circuit_breaker_max_failures_at_cap() {
let mut s = three_member_spec();
s.politicas.circuit_breaker = Some(CircuitBreaker {
max_failures: POLICY_BREAKER_MAX_FAILURES_MAX,
window: Duration::from_secs(60),
});
s.validate()
.expect("max_failures == POLICY_BREAKER_MAX_FAILURES_MAX must validate");
}
#[test]
fn accepts_circuit_breaker_max_failures_typical_values() {
for n in [1u32, 5, 10, 20, 50, 100, 500, 1000] {
let mut s = three_member_spec();
s.politicas.circuit_breaker = Some(CircuitBreaker {
max_failures: n,
window: Duration::from_secs(60),
});
s.validate()
.unwrap_or_else(|e| panic!("max_failures={n} must validate; got {e:?}"));
}
}
#[test]
fn circuit_breaker_zero_max_failures_takes_precedence_over_cap() {
let mut s = three_member_spec();
s.politicas.circuit_breaker = Some(CircuitBreaker {
max_failures: 0,
window: Duration::from_secs(60),
});
assert_eq!(
s.validate().unwrap_err(),
AplicacaoError::PolicyBreakerZeroFailures,
"max_failures == 0 must surface the zero-floor diagnostic, not the cap diagnostic"
);
}
#[test]
fn circuit_breaker_max_failures_cap_takes_precedence_over_window_gates() {
let mut s = three_member_spec();
s.politicas.circuit_breaker = Some(CircuitBreaker {
max_failures: POLICY_BREAKER_MAX_FAILURES_MAX + 1,
window: Duration::ZERO,
});
assert_eq!(
s.validate().unwrap_err(),
AplicacaoError::PolicyBreakerMaxFailuresExceedsCap {
max_failures: POLICY_BREAKER_MAX_FAILURES_MAX + 1,
},
"over-cap max_failures must surface the cap diagnostic before any window-axis diagnostic"
);
}
#[test]
fn policy_breaker_max_failures_cap_diagnostic_carries_offending_value() {
let mut s = three_member_spec();
s.politicas.circuit_breaker = Some(CircuitBreaker {
max_failures: 50_000,
window: Duration::from_secs(60),
});
let err = s.validate().unwrap_err();
assert!(
matches!(
err,
AplicacaoError::PolicyBreakerMaxFailuresExceedsCap {
max_failures: 50_000
}
),
"got {err:?}"
);
let msg = err.to_string();
assert!(
msg.contains("50000"),
":politicas :circuit-breaker :max-failures cap diagnostic must carry the offending value verbatim (got: {msg})"
);
}
#[test]
fn policy_breaker_max_failures_cap_pins_canonical_value() {
assert_eq!(POLICY_BREAKER_MAX_FAILURES_MAX, 1000);
}
#[test]
fn rejects_circuit_breaker_zero_window() {
let mut s = three_member_spec();
s.politicas.circuit_breaker = Some(CircuitBreaker {
max_failures: 5,
window: Duration::ZERO,
});
assert_eq!(
s.validate().unwrap_err(),
AplicacaoError::PolicyBreakerZeroWindow
);
}
#[test]
fn rejects_zero_rate_limit() {
let mut s = three_member_spec();
s.politicas.rate_limit = Some(RateLimit {
rate: 0,
window: Duration::from_secs(1),
});
assert_eq!(
s.validate().unwrap_err(),
AplicacaoError::PolicyRateLimitZero
);
}
#[test]
fn rejects_rate_limit_zero_window() {
let mut s = three_member_spec();
s.politicas.rate_limit = Some(RateLimit {
rate: 100,
window: Duration::ZERO,
});
assert_eq!(
s.validate().unwrap_err(),
AplicacaoError::PolicyRateLimitWindowNotCanonical {
window: Duration::ZERO
}
);
}
#[test]
fn rejects_rate_limit_arbitrary_seconds_window() {
let mut s = three_member_spec();
let window = Duration::from_secs(45);
s.politicas.rate_limit = Some(RateLimit { rate: 100, window });
assert_eq!(
s.validate().unwrap_err(),
AplicacaoError::PolicyRateLimitWindowNotCanonical { window }
);
}
#[test]
fn rejects_rate_limit_two_minute_window() {
let mut s = three_member_spec();
let window = Duration::from_secs(120);
s.politicas.rate_limit = Some(RateLimit { rate: 50, window });
assert_eq!(
s.validate().unwrap_err(),
AplicacaoError::PolicyRateLimitWindowNotCanonical { window }
);
}
#[test]
fn rejects_rate_limit_subsecond_window() {
let mut s = three_member_spec();
let window = Duration::from_millis(500);
s.politicas.rate_limit = Some(RateLimit { rate: 200, window });
assert_eq!(
s.validate().unwrap_err(),
AplicacaoError::PolicyRateLimitWindowNotCanonical { window }
);
}
#[test]
fn rejects_policy_rate_limit_above_cap() {
let mut s = three_member_spec();
s.politicas.rate_limit = Some(RateLimit {
rate: POLICY_RATE_LIMIT_MAX + 1,
window: Duration::from_secs(1),
});
assert_eq!(
s.validate().unwrap_err(),
AplicacaoError::PolicyRateLimitExceedsCap {
rate: POLICY_RATE_LIMIT_MAX + 1
}
);
}
#[test]
fn rejects_policy_rate_limit_far_above_cap() {
let mut s = three_member_spec();
s.politicas.rate_limit = Some(RateLimit {
rate: u32::MAX,
window: Duration::from_secs(1),
});
assert_eq!(
s.validate().unwrap_err(),
AplicacaoError::PolicyRateLimitExceedsCap { rate: u32::MAX }
);
}
#[test]
fn accepts_policy_rate_limit_at_cap() {
for secs in [1u64, 60, 3600] {
let mut s = three_member_spec();
s.politicas.rate_limit = Some(RateLimit {
rate: POLICY_RATE_LIMIT_MAX,
window: Duration::from_secs(secs),
});
s.validate().unwrap_or_else(|e| {
panic!("rate == POLICY_RATE_LIMIT_MAX must validate (window={secs}s); got {e:?}",)
});
}
}
#[test]
fn accepts_policy_rate_limit_typical_values() {
for rate in [1u32, 10, 100, 1_000, 10_000, 100_000, 1_000_000] {
for secs in [1u64, 60, 3600] {
let mut s = three_member_spec();
s.politicas.rate_limit = Some(RateLimit {
rate,
window: Duration::from_secs(secs),
});
s.validate().unwrap_or_else(|e| {
panic!("rate={rate} window={secs}s must validate; got {e:?}")
});
}
}
}
#[test]
fn policy_rate_limit_zero_takes_precedence_over_cap() {
let mut s = three_member_spec();
s.politicas.rate_limit = Some(RateLimit {
rate: 0,
window: Duration::from_secs(1),
});
assert_eq!(
s.validate().unwrap_err(),
AplicacaoError::PolicyRateLimitZero,
"rate == 0 must surface the zero-floor diagnostic, not the cap diagnostic"
);
}
#[test]
fn policy_rate_limit_cap_takes_precedence_over_non_canonical_window() {
let mut s = three_member_spec();
s.politicas.rate_limit = Some(RateLimit {
rate: POLICY_RATE_LIMIT_MAX + 1,
window: Duration::from_secs(45),
});
assert_eq!(
s.validate().unwrap_err(),
AplicacaoError::PolicyRateLimitExceedsCap {
rate: POLICY_RATE_LIMIT_MAX + 1
},
"above-cap rate must surface the cap diagnostic, not the window diagnostic"
);
}
#[test]
fn policy_rate_limit_cap_diagnostic_carries_offending_value() {
let mut s = three_member_spec();
s.politicas.rate_limit = Some(RateLimit {
rate: 5_000_000,
window: Duration::from_secs(1),
});
let err = s.validate().unwrap_err();
assert!(
matches!(
err,
AplicacaoError::PolicyRateLimitExceedsCap { rate: 5_000_000 }
),
"got {err:?}"
);
let msg = err.to_string();
assert!(
msg.contains("5000000"),
":politicas :rate-limit cap diagnostic must carry the offending value verbatim (got: {msg})"
);
}
#[test]
fn policy_rate_limit_cap_pins_canonical_value() {
assert_eq!(POLICY_RATE_LIMIT_MAX, 1_000_000);
}
#[test]
fn rate_limit_zero_rate_takes_precedence_over_non_canonical_window() {
let mut s = three_member_spec();
s.politicas.rate_limit = Some(RateLimit {
rate: 0,
window: Duration::from_secs(45),
});
assert_eq!(
s.validate().unwrap_err(),
AplicacaoError::PolicyRateLimitZero
);
}
#[test]
fn rate_limit_canonical_windows_validate() {
for secs in [1u64, 60, 3600] {
let mut s = three_member_spec();
s.politicas.rate_limit = Some(RateLimit {
rate: 100,
window: Duration::from_secs(secs),
});
s.validate().expect("canonical window must validate");
}
}
#[test]
fn rate_limit_validated_value_round_trips_through_codec() {
for secs in [1u64, 60, 3600] {
let mut s = three_member_spec();
s.politicas.rate_limit = Some(RateLimit {
rate: 250,
window: Duration::from_secs(secs),
});
s.validate().unwrap();
let json = serde_json::to_string(&s.politicas).unwrap();
let back: MeshPolicy = serde_json::from_str(&json).unwrap();
assert_eq!(
back.rate_limit, s.politicas.rate_limit,
"every validated :rate-limit must round-trip losslessly through the codec"
);
}
}
#[test]
fn rate_limit_canonical_per_hour_renders_with_h_suffix() {
let policy = MeshPolicy {
rate_limit: Some(RateLimit {
rate: 10000,
window: Duration::from_secs(3600),
}),
..Default::default()
};
let json = serde_json::to_string(&policy).unwrap();
assert!(
json.contains("\"10000/h\""),
"hour-window canonical form must render with `h` suffix (got: {json})"
);
let back: MeshPolicy = serde_json::from_str(&json).unwrap();
assert_eq!(back.rate_limit.unwrap().window, Duration::from_secs(3600));
}
#[test]
fn canonical_rate_limit_window_set_tracks_codec_via_canonical_unit() {
let canonical_unit = |window: Duration| -> Option<super::RateLimitUnit> {
RateLimit { rate: 1, window }.canonical_unit()
};
assert!(canonical_unit(Duration::from_secs(1)).is_some());
assert!(canonical_unit(Duration::from_secs(60)).is_some());
assert!(canonical_unit(Duration::from_secs(3600)).is_some());
assert!(canonical_unit(Duration::ZERO).is_none());
assert!(canonical_unit(Duration::from_secs(2)).is_none());
assert!(canonical_unit(Duration::from_secs(30)).is_none());
assert!(canonical_unit(Duration::from_secs(120)).is_none());
assert!(canonical_unit(Duration::from_secs(86400)).is_none());
assert!(canonical_unit(Duration::from_millis(1000)).is_some());
assert!(canonical_unit(Duration::from_millis(500)).is_none());
assert!(canonical_unit(Duration::from_millis(1500)).is_none());
}
#[test]
fn rate_limit_unit_table_projections_are_mutual_inverses() {
for (unit, secs) in [("s", 1u64), ("m", 60), ("h", 3600)] {
let window = super::RateLimitUnit::window_from_suffix(unit)
.unwrap_or_else(|| panic!("canonical unit {unit:?} must resolve to a Duration"));
assert_eq!(
window,
Duration::from_secs(secs),
"unit {unit:?} must resolve to {secs}s"
);
let projected_suffix = RateLimit { rate: 1, window }
.canonical_unit()
.map(super::RateLimitUnit::as_suffix);
assert_eq!(
projected_suffix,
Some(unit),
"Duration({secs}s) must render as {unit:?} \
via RateLimit::canonical_unit + RateLimitUnit::as_suffix"
);
}
assert!(super::RateLimitUnit::window_from_suffix("d").is_none());
assert!(super::RateLimitUnit::window_from_suffix("ms").is_none());
assert!(super::RateLimitUnit::window_from_suffix("").is_none());
let projected_suffix = |window: Duration| -> Option<&'static str> {
RateLimit { rate: 1, window }
.canonical_unit()
.map(super::RateLimitUnit::as_suffix)
};
assert!(projected_suffix(Duration::from_secs(2)).is_none());
assert!(projected_suffix(Duration::from_secs(86_400)).is_none());
assert!(projected_suffix(Duration::from_millis(1500)).is_none());
}
#[test]
fn rate_limit_unit_window_from_suffix_composes_from_suffix_and_window() {
let composition = |suffix: &str| -> Option<Duration> {
super::RateLimitUnit::from_suffix(suffix).map(super::RateLimitUnit::window)
};
for suffix in ["s", "m", "h"] {
let via_method = super::RateLimitUnit::window_from_suffix(suffix);
let via_composition = composition(suffix);
assert_eq!(
via_method, via_composition,
"RateLimitUnit::window_from_suffix({suffix:?}) must byte-equal \
from_suffix({suffix:?}).map(window) — the substrate-primitive \
method must delegate to the arm-table's two typed dispatches, \
not shortcut through a per-suffix match table"
);
assert!(
via_method.is_some(),
"canonical suffix {suffix:?} must resolve to Some(Duration) via \
RateLimitUnit::window_from_suffix"
);
}
for suffix in ["d", "ms", "", "seconds", "MIN", "S", "H", "/"] {
let via_method = super::RateLimitUnit::window_from_suffix(suffix);
let via_composition = composition(suffix);
assert_eq!(
via_method, via_composition,
"RateLimitUnit::window_from_suffix({suffix:?}) must byte-equal \
from_suffix({suffix:?}).map(window) on the non-arm rejection \
axis too"
);
assert!(
via_method.is_none(),
"non-arm suffix {suffix:?} must project to None via \
RateLimitUnit::window_from_suffix — a future extension that \
accepted this suffix without a corresponding arm on the enum \
would split the codec's parse-accepted set from the enum's \
arm-table"
);
}
for suffix in ["s", "m", "h"] {
let wire = format!(r#"{{"rateLimit":"100/{suffix}"}}"#);
let mp: MeshPolicy = serde_json::from_str(&wire)
.unwrap_or_else(|e| panic!("wire {wire:?} must parse: {e}"));
let parsed = mp.rate_limit().expect("rate_limit payload present");
let via_method = super::RateLimitUnit::window_from_suffix(suffix)
.unwrap_or_else(|| panic!("suffix {suffix:?} must resolve via window_from_suffix"));
assert_eq!(
parsed.window(),
via_method,
"codec parse arm on {wire:?} must resolve the window through \
RateLimitUnit::window_from_suffix, not a divergent path"
);
}
}
#[test]
fn rate_limit_unit_all_enumerates_every_arm_once() {
assert_eq!(
super::RateLimitUnit::ALL,
&[
super::RateLimitUnit::Second,
super::RateLimitUnit::Minute,
super::RateLimitUnit::Hour,
],
"RateLimitUnit::ALL must enumerate every arm exactly once, \
in canonical shortest-to-longest window order"
);
}
#[test]
fn rate_limit_unit_from_suffix_and_as_suffix_round_trip() {
for unit in super::RateLimitUnit::ALL {
let suffix = unit.as_suffix();
let parsed = super::RateLimitUnit::from_suffix(suffix).unwrap_or_else(|| {
panic!(
"RateLimitUnit::from_suffix({suffix:?}) must accept every \
RateLimitUnit::as_suffix output — got None for {unit:?}"
)
});
assert_eq!(
parsed, *unit,
"RateLimitUnit::from_suffix(RateLimitUnit::{unit:?}.as_suffix()) \
must return RateLimitUnit::{unit:?}"
);
}
}
#[test]
fn rate_limit_unit_from_window_and_window_round_trip() {
for unit in super::RateLimitUnit::ALL {
let window = unit.window();
let parsed = super::RateLimitUnit::from_window(window).unwrap_or_else(|| {
panic!(
"RateLimitUnit::from_window({window:?}) must accept every \
RateLimitUnit::window output — got None for {unit:?}"
)
});
assert_eq!(
parsed, *unit,
"RateLimitUnit::from_window(RateLimitUnit::{unit:?}.window()) \
must return RateLimitUnit::{unit:?}"
);
}
}
#[test]
fn rate_limit_unit_projections_are_pairwise_distinct() {
let all = super::RateLimitUnit::ALL;
for (i, a) in all.iter().enumerate() {
for (j, b) in all.iter().enumerate() {
if i != j {
assert_ne!(
a.as_suffix(),
b.as_suffix(),
"RateLimitUnit::{a:?}.as_suffix() and {b:?}.as_suffix() \
must be distinct — a collision silently collapses two \
arms onto one under from_suffix's linear scan"
);
assert_ne!(
a.window(),
b.window(),
"RateLimitUnit::{a:?}.window() and {b:?}.window() \
must be distinct — a collision silently collapses two \
arms onto one under from_window's linear scan"
);
}
}
}
}
#[test]
fn rate_limit_unit_display_routes_through_as_suffix() {
for unit in super::RateLimitUnit::ALL {
assert_eq!(
unit.to_string(),
unit.as_suffix(),
"RateLimitUnit::{unit:?} Display must route through \
as_suffix (single source of truth: the canonical suffix \
the codec parses and renders)"
);
}
}
#[test]
fn rate_limit_unit_from_window_rejects_non_canonical() {
assert!(super::RateLimitUnit::from_window(Duration::ZERO).is_none());
assert!(super::RateLimitUnit::from_window(Duration::from_secs(2)).is_none());
assert!(super::RateLimitUnit::from_window(Duration::from_secs(30)).is_none());
assert!(super::RateLimitUnit::from_window(Duration::from_secs(120)).is_none());
assert!(super::RateLimitUnit::from_window(Duration::from_secs(86_400)).is_none());
assert!(super::RateLimitUnit::from_window(Duration::from_millis(500)).is_none());
assert!(super::RateLimitUnit::from_window(Duration::from_millis(1500)).is_none());
}
#[test]
fn rate_limit_unit_from_suffix_rejects_unknown() {
for bad in [
"", "S", "M", "H", "sec", "min", "hour", "d", "ms", "ns", "us", "week", "1s", "s/",
" s",
] {
assert!(
super::RateLimitUnit::from_suffix(bad).is_none(),
"RateLimitUnit::from_suffix({bad:?}) must return None — the \
parser's accept-set is exactly the three RateLimitUnit::as_suffix \
outputs"
);
}
}
#[test]
fn rate_limit_canonical_unit_returns_typed_arm_on_validated_windows() {
for (window_secs, expected) in [
(1u64, super::RateLimitUnit::Second),
(60, super::RateLimitUnit::Minute),
(3600, super::RateLimitUnit::Hour),
] {
let rl = RateLimit {
rate: 100,
window: Duration::from_secs(window_secs),
};
assert_eq!(
rl.canonical_unit(),
Some(expected),
"RateLimit {{ window: {window_secs}s, .. }}.canonical_unit() \
must return Some({expected:?})"
);
}
let bad = RateLimit {
rate: 100,
window: Duration::from_secs(30),
};
assert!(
bad.canonical_unit().is_none(),
"RateLimit with a non-canonical window must return None from \
canonical_unit — the validate gate rejects the same set"
);
}
#[test]
fn rate_limit_codec_render_routes_through_canonical_unit_and_as_suffix() {
for (window_secs, unit) in [
(1u64, super::RateLimitUnit::Second),
(60, super::RateLimitUnit::Minute),
(3600, super::RateLimitUnit::Hour),
] {
let rl = RateLimit {
rate: 42,
window: Duration::from_secs(window_secs),
};
let policy = MeshPolicy {
rate_limit: Some(rl),
..Default::default()
};
let json = serde_json::to_string(&policy).unwrap();
let expected = format!("\"{}/{}\"", rl.rate(), unit.as_suffix());
assert!(
json.contains(&expected),
"rate_limit_codec::render must emit {expected} (via \
RateLimit::canonical_unit + RateLimitUnit::as_suffix) \
for a {window_secs}s window; serialized MeshPolicy was: {json}"
);
assert_eq!(
rl.canonical_unit(),
Some(unit),
"RateLimit::canonical_unit must return Some({unit:?}) for a \
{window_secs}s window; the codec render arm reads the same \
typed unit through this accessor"
);
}
}
#[test]
fn validate_politicas_rate_limit_canonical_window_gate_routes_through_canonical_unit() {
for canonical_window_secs in [1u64, 60, 3600] {
let mut s = three_member_spec();
let rl = RateLimit {
rate: 100,
window: Duration::from_secs(canonical_window_secs),
};
s.politicas.rate_limit = Some(rl);
assert!(
s.validate().is_ok(),
"canonical {canonical_window_secs}s window must pass \
validate_politicas — the validate gate now reads \
RateLimit::canonical_unit().is_none() and the accessor \
returns Some on every canonical arm"
);
assert!(
rl.canonical_unit().is_some(),
"canonical {canonical_window_secs}s window must resolve to \
Some on RateLimit::canonical_unit — the validate gate reads \
this accessor directly"
);
}
for non_canonical_window_secs in [2u64, 30, 120, 86_400] {
let mut s = three_member_spec();
let rl = RateLimit {
rate: 100,
window: Duration::from_secs(non_canonical_window_secs),
};
s.politicas.rate_limit = Some(rl);
assert_eq!(
s.validate().unwrap_err(),
AplicacaoError::PolicyRateLimitWindowNotCanonical {
window: rl.window(),
},
"non-canonical {non_canonical_window_secs}s window must be \
rejected by validate_politicas — the validate gate now \
keys off RateLimit::canonical_unit().is_none()"
);
assert!(
rl.canonical_unit().is_none(),
"non-canonical {non_canonical_window_secs}s window must \
resolve to None on RateLimit::canonical_unit — the two \
paths (the free helper the validate gate previously read \
and the substrate primitive the validate gate now reads) \
must agree on the same rejected set"
);
}
for (secs, expected) in [
(1u64, true),
(60, true),
(3600, true),
(2, false),
(30, false),
(86_400, false),
] {
let window = Duration::from_secs(secs);
let rl = RateLimit { rate: 1, window };
assert_eq!(
rl.canonical_unit().is_some(),
expected,
"RateLimit::canonical_unit().is_some() must agree with the \
codec-accepted canonical-window set on {secs}s"
);
let suffix_from_axis = super::RateLimitUnit::window_from_suffix(match secs {
1 => "s",
60 => "m",
3600 => "h",
_ => return,
})
.is_some_and(|d| d == window);
if expected {
assert!(
suffix_from_axis,
"the codec's `&str → Duration` axis \
({secs}s) must round-trip to the same Duration the \
substrate primitive's accessor returns Some on"
);
}
}
}
#[test]
fn rate_limit_unit_is_variant_predicates_partition_the_arm_set() {
let rows: [(super::RateLimitUnit, [bool; 3]); 3] = [
(super::RateLimitUnit::Second, [true, false, false]),
(super::RateLimitUnit::Minute, [false, true, false]),
(super::RateLimitUnit::Hour, [false, false, true]),
];
for (variant, expected) in rows {
let observed = [variant.is_second(), variant.is_minute(), variant.is_hour()];
assert_eq!(
observed, expected,
"RateLimitUnit::{variant:?} is_* predicates must partition \
the arm set (second, minute, hour); got {observed:?}"
);
}
}
#[test]
fn rejects_policy_timeout_sub_millisecond() {
let mut s = three_member_spec();
let timeout = Duration::from_micros(500);
s.politicas.timeout = Some(timeout);
assert_eq!(
s.validate().unwrap_err(),
AplicacaoError::PolicyTimeoutNotCanonical { timeout }
);
}
#[test]
fn rejects_policy_timeout_non_integer_millisecond() {
let mut s = three_member_spec();
let timeout = Duration::from_micros(1500);
s.politicas.timeout = Some(timeout);
assert_eq!(
s.validate().unwrap_err(),
AplicacaoError::PolicyTimeoutNotCanonical { timeout }
);
}
#[test]
fn accepts_policy_timeout_integer_millisecond_forms() {
for timeout in [
Duration::from_millis(1),
Duration::from_millis(500),
Duration::from_millis(1500),
Duration::from_secs(30),
Duration::from_secs(120),
Duration::from_secs(3600),
] {
let mut s = three_member_spec();
s.politicas.timeout = Some(timeout);
s.validate()
.expect("integer-millisecond :timeout must validate");
}
}
#[test]
fn policy_timeout_zero_takes_precedence_over_canonical() {
let mut s = three_member_spec();
s.politicas.timeout = Some(Duration::ZERO);
assert_eq!(s.validate().unwrap_err(), AplicacaoError::PolicyTimeoutZero);
}
#[test]
fn policy_timeout_canonical_diagnostic_carries_offending_duration() {
let mut s = three_member_spec();
let timeout = Duration::from_nanos(1_000_001);
s.politicas.timeout = Some(timeout);
match s.validate().unwrap_err() {
AplicacaoError::PolicyTimeoutNotCanonical { timeout: t } => {
assert_eq!(t, timeout, "diagnostic must carry the offending Duration");
}
other => panic!("expected PolicyTimeoutNotCanonical, got {other:?}"),
}
}
#[test]
fn rejects_policy_timeout_above_cap() {
let mut s = three_member_spec();
let timeout = POLICY_TIMEOUT_MAX + Duration::from_secs(1);
s.politicas.timeout = Some(timeout);
assert_eq!(
s.validate().unwrap_err(),
AplicacaoError::PolicyTimeoutExceedsCap { timeout }
);
}
#[test]
fn rejects_policy_timeout_one_millisecond_above_cap() {
let mut s = three_member_spec();
let timeout = POLICY_TIMEOUT_MAX + Duration::from_millis(1);
s.politicas.timeout = Some(timeout);
assert_eq!(
s.validate().unwrap_err(),
AplicacaoError::PolicyTimeoutExceedsCap { timeout }
);
}
#[test]
fn rejects_policy_timeout_far_above_cap() {
for timeout in [
Duration::from_secs(86_400), Duration::from_secs(604_800), Duration::from_secs(1_000_000), ] {
let mut s = three_member_spec();
s.politicas.timeout = Some(timeout);
assert_eq!(
s.validate().unwrap_err(),
AplicacaoError::PolicyTimeoutExceedsCap { timeout }
);
}
}
#[test]
fn accepts_policy_timeout_at_cap() {
let mut s = three_member_spec();
s.politicas.timeout = Some(POLICY_TIMEOUT_MAX);
s.validate()
.expect("timeout == POLICY_TIMEOUT_MAX must validate");
}
#[test]
fn accepts_policy_timeout_typical_values() {
for timeout in [
Duration::from_millis(1),
Duration::from_millis(500),
Duration::from_secs(1),
Duration::from_secs(10),
Duration::from_secs(15), Duration::from_secs(30),
Duration::from_secs(60), Duration::from_secs(300),
Duration::from_secs(900),
Duration::from_secs(1800),
Duration::from_secs(3600), ] {
let mut s = three_member_spec();
s.politicas.timeout = Some(timeout);
s.validate()
.unwrap_or_else(|e| panic!("timeout={timeout:?} must validate; got {e:?}"));
}
}
#[test]
fn policy_timeout_zero_takes_precedence_over_cap() {
let mut s = three_member_spec();
s.politicas.timeout = Some(Duration::ZERO);
assert_eq!(
s.validate().unwrap_err(),
AplicacaoError::PolicyTimeoutZero,
"Duration::ZERO must surface the zero-floor diagnostic, not the cap diagnostic"
);
}
#[test]
fn policy_timeout_canonical_takes_precedence_over_cap() {
let mut s = three_member_spec();
let timeout = POLICY_TIMEOUT_MAX + Duration::from_nanos(1);
s.politicas.timeout = Some(timeout);
assert_eq!(
s.validate().unwrap_err(),
AplicacaoError::PolicyTimeoutNotCanonical { timeout },
"sub-ms above-cap value must surface the canonical-form diagnostic, not the cap diagnostic"
);
}
#[test]
fn policy_timeout_cap_diagnostic_carries_offending_value() {
let mut s = three_member_spec();
let timeout = Duration::from_secs(7200); s.politicas.timeout = Some(timeout);
let err = s.validate().unwrap_err();
assert!(
matches!(err, AplicacaoError::PolicyTimeoutExceedsCap { timeout: t } if t == timeout),
"got {err:?}"
);
let msg = err.to_string();
assert!(
msg.contains("7200"),
":politicas :timeout cap diagnostic must carry the offending value verbatim (got: {msg})"
);
}
#[test]
fn policy_timeout_cap_pins_canonical_value() {
assert_eq!(POLICY_TIMEOUT_MAX, Duration::from_secs(3600));
assert_eq!(POLICY_TIMEOUT_MAX.as_millis(), 3_600_000);
}
#[test]
fn policy_timeout_cap_value_round_trips_through_codec() {
let policy = MeshPolicy {
timeout: Some(POLICY_TIMEOUT_MAX),
..Default::default()
};
let json = serde_json::to_string(&policy).unwrap();
assert!(
json.contains("\"1h\""),
"the POLICY_TIMEOUT_MAX value must render to the canonical \"1h\" form (got: {json})"
);
let back: MeshPolicy = serde_json::from_str(&json).unwrap();
assert_eq!(back.timeout, Some(POLICY_TIMEOUT_MAX));
}
#[test]
fn rejects_circuit_breaker_window_sub_millisecond() {
let mut s = three_member_spec();
let window = Duration::from_micros(500);
s.politicas.circuit_breaker = Some(CircuitBreaker {
max_failures: 5,
window,
});
assert_eq!(
s.validate().unwrap_err(),
AplicacaoError::PolicyBreakerWindowNotCanonical { window }
);
}
#[test]
fn rejects_circuit_breaker_window_non_integer_millisecond() {
let mut s = three_member_spec();
let window = Duration::from_micros(1500);
s.politicas.circuit_breaker = Some(CircuitBreaker {
max_failures: 5,
window,
});
assert_eq!(
s.validate().unwrap_err(),
AplicacaoError::PolicyBreakerWindowNotCanonical { window }
);
}
#[test]
fn accepts_circuit_breaker_window_integer_millisecond_forms() {
for window in [
Duration::from_millis(1),
Duration::from_millis(500),
Duration::from_millis(1500),
Duration::from_secs(30),
Duration::from_secs(60),
Duration::from_secs(3600),
] {
let mut s = three_member_spec();
s.politicas.circuit_breaker = Some(CircuitBreaker {
max_failures: 5,
window,
});
s.validate()
.expect("integer-millisecond :circuit-breaker :window must validate");
}
}
#[test]
fn circuit_breaker_zero_window_takes_precedence_over_canonical() {
let mut s = three_member_spec();
s.politicas.circuit_breaker = Some(CircuitBreaker {
max_failures: 5,
window: Duration::ZERO,
});
assert_eq!(
s.validate().unwrap_err(),
AplicacaoError::PolicyBreakerZeroWindow
);
}
#[test]
fn circuit_breaker_zero_failures_takes_precedence_over_window_canonical() {
let mut s = three_member_spec();
s.politicas.circuit_breaker = Some(CircuitBreaker {
max_failures: 0,
window: Duration::from_micros(500),
});
assert_eq!(
s.validate().unwrap_err(),
AplicacaoError::PolicyBreakerZeroFailures
);
}
#[test]
fn circuit_breaker_window_canonical_diagnostic_carries_offending_duration() {
let mut s = three_member_spec();
let window = Duration::from_nanos(60_000_000_001);
s.politicas.circuit_breaker = Some(CircuitBreaker {
max_failures: 5,
window,
});
match s.validate().unwrap_err() {
AplicacaoError::PolicyBreakerWindowNotCanonical { window: w } => {
assert_eq!(w, window, "diagnostic must carry the offending Duration");
}
other => panic!("expected PolicyBreakerWindowNotCanonical, got {other:?}"),
}
}
#[test]
fn rejects_circuit_breaker_window_above_cap() {
let mut s = three_member_spec();
let window = POLICY_BREAKER_WINDOW_MAX + Duration::from_secs(1);
s.politicas.circuit_breaker = Some(CircuitBreaker {
max_failures: 5,
window,
});
assert_eq!(
s.validate().unwrap_err(),
AplicacaoError::PolicyBreakerWindowExceedsCap { window }
);
}
#[test]
fn rejects_circuit_breaker_window_one_millisecond_above_cap() {
let mut s = three_member_spec();
let window = POLICY_BREAKER_WINDOW_MAX + Duration::from_millis(1);
s.politicas.circuit_breaker = Some(CircuitBreaker {
max_failures: 5,
window,
});
assert_eq!(
s.validate().unwrap_err(),
AplicacaoError::PolicyBreakerWindowExceedsCap { window }
);
}
#[test]
fn rejects_circuit_breaker_window_far_above_cap() {
for window in [
Duration::from_secs(86_400), Duration::from_secs(604_800), Duration::from_secs(1_000_000), ] {
let mut s = three_member_spec();
s.politicas.circuit_breaker = Some(CircuitBreaker {
max_failures: 5,
window,
});
assert_eq!(
s.validate().unwrap_err(),
AplicacaoError::PolicyBreakerWindowExceedsCap { window }
);
}
}
#[test]
fn accepts_circuit_breaker_window_at_cap() {
let mut s = three_member_spec();
s.politicas.circuit_breaker = Some(CircuitBreaker {
max_failures: 5,
window: POLICY_BREAKER_WINDOW_MAX,
});
s.validate()
.expect("window == POLICY_BREAKER_WINDOW_MAX must validate");
}
#[test]
fn accepts_circuit_breaker_window_typical_values() {
for window in [
Duration::from_millis(1),
Duration::from_millis(500),
Duration::from_secs(1),
Duration::from_secs(10), Duration::from_secs(30),
Duration::from_secs(60), Duration::from_secs(300), Duration::from_secs(900),
Duration::from_secs(1800),
Duration::from_secs(3600), ] {
let mut s = three_member_spec();
s.politicas.circuit_breaker = Some(CircuitBreaker {
max_failures: 5,
window,
});
s.validate()
.unwrap_or_else(|e| panic!("window={window:?} must validate; got {e:?}"));
}
}
#[test]
fn circuit_breaker_zero_window_takes_precedence_over_cap() {
let mut s = three_member_spec();
s.politicas.circuit_breaker = Some(CircuitBreaker {
max_failures: 5,
window: Duration::ZERO,
});
assert_eq!(
s.validate().unwrap_err(),
AplicacaoError::PolicyBreakerZeroWindow,
"Duration::ZERO must surface the zero-floor diagnostic, not the cap diagnostic"
);
}
#[test]
fn circuit_breaker_window_canonical_takes_precedence_over_cap() {
let mut s = three_member_spec();
let window = POLICY_BREAKER_WINDOW_MAX + Duration::from_nanos(1);
s.politicas.circuit_breaker = Some(CircuitBreaker {
max_failures: 5,
window,
});
assert_eq!(
s.validate().unwrap_err(),
AplicacaoError::PolicyBreakerWindowNotCanonical { window },
"sub-ms above-cap value must surface the canonical-form diagnostic, not the cap diagnostic"
);
}
#[test]
fn circuit_breaker_max_failures_cap_takes_precedence_over_window_cap() {
let mut s = three_member_spec();
let window = POLICY_BREAKER_WINDOW_MAX + Duration::from_secs(1);
s.politicas.circuit_breaker = Some(CircuitBreaker {
max_failures: POLICY_BREAKER_MAX_FAILURES_MAX + 1,
window,
});
assert_eq!(
s.validate().unwrap_err(),
AplicacaoError::PolicyBreakerMaxFailuresExceedsCap {
max_failures: POLICY_BREAKER_MAX_FAILURES_MAX + 1
},
"both-axes-above-cap must surface the max-failures cap diagnostic first (arm order)"
);
}
#[test]
fn circuit_breaker_window_cap_diagnostic_carries_offending_value() {
let mut s = three_member_spec();
let window = Duration::from_secs(7200); s.politicas.circuit_breaker = Some(CircuitBreaker {
max_failures: 5,
window,
});
let err = s.validate().unwrap_err();
assert!(
matches!(err, AplicacaoError::PolicyBreakerWindowExceedsCap { window: w } if w == window),
"got {err:?}"
);
let msg = err.to_string();
assert!(
msg.contains("7200"),
":politicas :circuit-breaker :window cap diagnostic must carry the offending value verbatim (got: {msg})"
);
}
#[test]
fn circuit_breaker_window_cap_pins_canonical_value() {
assert_eq!(POLICY_BREAKER_WINDOW_MAX, Duration::from_secs(3600));
assert_eq!(POLICY_BREAKER_WINDOW_MAX.as_millis(), 3_600_000);
assert_eq!(
POLICY_BREAKER_WINDOW_MAX, POLICY_TIMEOUT_MAX,
"the two duration-typed `:politicas` caps share the same top edge"
);
}
#[test]
fn circuit_breaker_window_cap_value_round_trips_through_codec() {
let policy = MeshPolicy {
circuit_breaker: Some(CircuitBreaker {
max_failures: 5,
window: POLICY_BREAKER_WINDOW_MAX,
}),
..Default::default()
};
let json = serde_json::to_string(&policy).unwrap();
assert!(
json.contains("\"1h\""),
"the POLICY_BREAKER_WINDOW_MAX value must render to the canonical \"1h\" form (got: {json})"
);
let back: MeshPolicy = serde_json::from_str(&json).unwrap();
assert_eq!(
back.circuit_breaker.unwrap().window,
POLICY_BREAKER_WINDOW_MAX
);
}
#[test]
fn is_integer_millisecond_duration_predicate_tracks_codec() {
use super::supervisor::duration_codec::is_integer_millisecond_duration;
assert!(is_integer_millisecond_duration(Duration::ZERO));
assert!(is_integer_millisecond_duration(Duration::from_millis(1)));
assert!(is_integer_millisecond_duration(Duration::from_millis(500)));
assert!(is_integer_millisecond_duration(Duration::from_millis(1500)));
assert!(is_integer_millisecond_duration(Duration::from_secs(30)));
assert!(is_integer_millisecond_duration(Duration::from_secs(3600)));
assert!(!is_integer_millisecond_duration(Duration::from_micros(1)));
assert!(!is_integer_millisecond_duration(Duration::from_micros(500)));
assert!(!is_integer_millisecond_duration(Duration::from_micros(
1500
)));
assert!(!is_integer_millisecond_duration(Duration::from_nanos(1)));
assert!(!is_integer_millisecond_duration(Duration::from_nanos(
999_999
)));
assert!(!is_integer_millisecond_duration(Duration::from_nanos(
1_000_001
)));
}
#[test]
fn policy_timeout_validated_value_round_trips_through_codec() {
for timeout in [
Duration::from_millis(1),
Duration::from_millis(1500),
Duration::from_secs(30),
Duration::from_secs(3600),
] {
let mut s = three_member_spec();
s.politicas.timeout = Some(timeout);
s.validate().unwrap();
let json = serde_json::to_string(&s.politicas).unwrap();
let back: MeshPolicy = serde_json::from_str(&json).unwrap();
assert_eq!(
back.timeout, s.politicas.timeout,
"every validated :timeout must round-trip losslessly through the codec"
);
}
}
#[test]
fn circuit_breaker_window_validated_value_round_trips_through_codec() {
for window in [
Duration::from_millis(1),
Duration::from_millis(1500),
Duration::from_secs(30),
Duration::from_secs(3600),
] {
let mut s = three_member_spec();
s.politicas.circuit_breaker = Some(CircuitBreaker {
max_failures: 5,
window,
});
s.validate().unwrap();
let json = serde_json::to_string(&s.politicas).unwrap();
let back: MeshPolicy = serde_json::from_str(&json).unwrap();
assert_eq!(
back.circuit_breaker.unwrap().window,
window,
"every validated :circuit-breaker :window must round-trip losslessly"
);
}
}
#[test]
fn empty_politicas_validates() {
let mut s = three_member_spec();
s.politicas = MeshPolicy::default();
s.validate().unwrap();
}
#[test]
fn typical_politicas_validates_with_every_axis_set() {
let mut s = three_member_spec();
s.politicas = MeshPolicy {
timeout: Some(Duration::from_secs(30)),
retries: Some(3),
circuit_breaker: Some(CircuitBreaker {
max_failures: 5,
window: Duration::from_secs(60),
}),
mtls_required: Some(true),
rate_limit: Some(RateLimit {
rate: 100,
window: Duration::from_secs(1),
}),
};
s.validate().unwrap();
}
#[test]
fn rejects_empty_cluster_name() {
let mut s = three_member_spec();
s.placement.clusters = vec!["rio".into(), "".into()];
assert_eq!(
s.validate().unwrap_err(),
AplicacaoError::PlacementClusterEmpty
);
}
#[test]
fn rejects_duplicate_cluster_names() {
let mut s = three_member_spec();
s.placement.clusters = vec!["rio".into(), "mar".into(), "rio".into()];
let err = s.validate().unwrap_err();
assert!(
matches!(err, AplicacaoError::PlacementClusterDuplicate { ref cluster } if cluster == "rio"),
"got {err:?}"
);
}
#[test]
fn rejects_placement_cluster_with_uppercase() {
let mut s = three_member_spec();
s.placement.clusters = vec!["Rio".into(), "mar".into()];
let err = s.validate().unwrap_err();
let AplicacaoError::PlacementClusterInvalid { cluster, reason } = err else {
panic!("expected PlacementClusterInvalid, got other variant");
};
assert_eq!(cluster, "Rio");
assert!(
reason.contains("uppercase"),
"diagnostic must name the violation as `uppercase` (got: {reason:?})"
);
assert!(
reason.contains("\"rio\""),
"diagnostic must suggest the lower-cased fix verbatim (got: {reason:?})"
);
}
#[test]
fn rejects_placement_cluster_with_underscore() {
let mut s = three_member_spec();
s.placement.clusters = vec!["my_cluster".into()];
let err = s.validate().unwrap_err();
assert!(
matches!(
err,
AplicacaoError::PlacementClusterInvalid { ref cluster, ref reason }
if cluster == "my_cluster" && reason.contains('_')
),
"got {err:?}"
);
}
#[test]
fn rejects_placement_cluster_with_dot() {
let mut s = three_member_spec();
s.placement.clusters = vec!["team.rio".into()];
let err = s.validate().unwrap_err();
assert!(
matches!(
err,
AplicacaoError::PlacementClusterInvalid { ref cluster, ref reason }
if cluster == "team.rio" && reason.contains('.')
),
"got {err:?}"
);
}
#[test]
fn rejects_placement_cluster_with_leading_hyphen() {
let mut s = three_member_spec();
s.placement.clusters = vec!["-rio".into()];
let err = s.validate().unwrap_err();
assert!(
matches!(
err,
AplicacaoError::PlacementClusterInvalid { ref cluster, ref reason }
if cluster == "-rio" && reason.contains("start and end")
),
"got {err:?}"
);
}
#[test]
fn rejects_placement_cluster_with_trailing_hyphen() {
let mut s = three_member_spec();
s.placement.clusters = vec!["rio-".into()];
let err = s.validate().unwrap_err();
assert!(
matches!(
err,
AplicacaoError::PlacementClusterInvalid { ref cluster, .. }
if cluster == "rio-"
),
"got {err:?}"
);
}
#[test]
fn rejects_placement_cluster_with_unicode() {
let mut s = three_member_spec();
s.placement.clusters = vec!["rió".into()];
let err = s.validate().unwrap_err();
assert!(
matches!(
err,
AplicacaoError::PlacementClusterInvalid { ref cluster, .. }
if cluster == "rió"
),
"got {err:?}"
);
}
#[test]
fn rejects_placement_cluster_with_whitespace() {
let mut s = three_member_spec();
s.placement.clusters = vec!["rio cluster".into()];
let err = s.validate().unwrap_err();
assert!(
matches!(
err,
AplicacaoError::PlacementClusterInvalid { ref cluster, .. }
if cluster == "rio cluster"
),
"got {err:?}"
);
}
#[test]
fn rejects_placement_cluster_too_long() {
let mut s = three_member_spec();
let too_long = "a".repeat(64);
s.placement.clusters = vec![too_long.clone()];
let err = s.validate().unwrap_err();
let AplicacaoError::PlacementClusterInvalid { cluster, reason } = err else {
panic!("expected PlacementClusterInvalid");
};
assert_eq!(cluster, too_long);
assert!(
reason.contains("63") && reason.contains("64"),
"diagnostic must name the cap (63) and the actual length (64): {reason:?}"
);
}
#[test]
fn placement_cluster_max_length_validates() {
let mut s = three_member_spec();
s.placement.clusters = vec!["a".repeat(63)];
s.validate().unwrap();
}
#[test]
fn accepts_canonical_placement_cluster_forms() {
for form in ["rio", "mar", "mar-east", "a", "p1", "3-prod", "prod-v2"] {
let mut s = three_member_spec();
s.placement.clusters = vec![form.into()];
s.validate().unwrap_or_else(|e| {
panic!("canonical cluster form {form:?} must validate, got {e:?}")
});
}
}
#[test]
fn placement_cluster_empty_takes_precedence_over_invalid() {
let mut s = three_member_spec();
s.placement.clusters = vec!["rio".into(), "".into()];
let err = s.validate().unwrap_err();
assert_eq!(err, AplicacaoError::PlacementClusterEmpty);
}
#[test]
fn placement_cluster_invalid_fires_before_duplicate_check() {
let mut s = three_member_spec();
s.placement.clusters = vec!["Rio".into(), "rio".into()];
let err = s.validate().unwrap_err();
assert!(
matches!(
err,
AplicacaoError::PlacementClusterInvalid { ref cluster, .. } if cluster == "Rio"
),
"got {err:?}"
);
}
#[test]
fn placement_cluster_invalid_diagnostic_carries_offending_cluster() {
let mut s = three_member_spec();
s.placement.clusters = vec!["BAD_CLUSTER".into()];
let err = s.validate().unwrap_err();
let AplicacaoError::PlacementClusterInvalid { cluster, reason } = err else {
panic!("expected PlacementClusterInvalid");
};
assert_eq!(cluster, "BAD_CLUSTER");
assert!(
!reason.is_empty(),
"PlacementClusterInvalid `reason` must carry a parser-shaped wording"
);
}
#[test]
fn rejects_sharded_with_empty_clusters() {
let mut s = three_member_spec();
s.placement.estrategia = PlacementStrategy::Sharded;
s.placement.shard_key = Some("$tenantId".into());
s.placement.clusters = vec![];
assert!(matches!(
s.validate().unwrap_err(),
AplicacaoError::PlacementWithoutClusters {
estrategia: PlacementStrategy::Sharded
}
));
}
#[test]
fn rejects_sharded_with_empty_shard_key() {
let mut s = three_member_spec();
s.placement.estrategia = PlacementStrategy::Sharded;
s.placement.shard_key = Some("".into());
assert_eq!(s.validate().unwrap_err(), AplicacaoError::ShardedKeyEmpty);
}
#[test]
fn rejects_shard_key_under_replicated_strategy() {
let mut s = three_member_spec();
s.placement.shard_key = Some("$tenantId".into());
let err = s.validate().unwrap_err();
let AplicacaoError::ShardKeyOnNonSharded {
estrategia,
shard_key,
} = err
else {
panic!("expected ShardKeyOnNonSharded, got {err:?}");
};
assert_eq!(estrategia, PlacementStrategy::Replicated);
assert_eq!(shard_key, "$tenantId");
}
#[test]
fn rejects_shard_key_under_singlenode_strategy() {
let mut s = three_member_spec();
s.placement.estrategia = PlacementStrategy::SingleNode;
s.placement.shard_key = Some("$tenantId".into());
let err = s.validate().unwrap_err();
let AplicacaoError::ShardKeyOnNonSharded {
estrategia,
shard_key,
} = err
else {
panic!("expected ShardKeyOnNonSharded, got {err:?}");
};
assert_eq!(estrategia, PlacementStrategy::SingleNode);
assert_eq!(shard_key, "$tenantId");
}
#[test]
fn rejects_empty_shard_key_under_replicated_strategy() {
let mut s = three_member_spec();
s.placement.shard_key = Some(String::new());
let err = s.validate().unwrap_err();
assert!(
matches!(
err,
AplicacaoError::ShardKeyOnNonSharded {
estrategia: PlacementStrategy::Replicated,
ref shard_key,
} if shard_key.is_empty()
),
"got {err:?}"
);
}
#[test]
fn replicated_without_shard_key_validates() {
let mut s = three_member_spec();
assert!(matches!(
s.placement.estrategia,
PlacementStrategy::Replicated
));
s.placement.shard_key = None;
s.validate().unwrap();
}
#[test]
fn singlenode_without_shard_key_validates() {
let mut s = three_member_spec();
s.placement.estrategia = PlacementStrategy::SingleNode;
s.placement.shard_key = None;
s.validate().unwrap();
}
fn sharded_spec_with_key(key: &str) -> AplicacaoSpec {
let mut s = three_member_spec();
s.placement.estrategia = PlacementStrategy::Sharded;
s.placement.shard_key = Some(key.into());
s
}
#[test]
fn rejects_shard_key_with_embedded_space() {
let s = sharded_spec_with_key("$tenant Id");
let err = s.validate().unwrap_err();
assert!(
matches!(
err,
AplicacaoError::ShardKeyInvalid { ref shard_key, ref reason }
if shard_key == "$tenant Id" && reason.contains("space")
),
"got {err:?}"
);
}
#[test]
fn rejects_shard_key_with_leading_space() {
let s = sharded_spec_with_key(" $tenantId");
let err = s.validate().unwrap_err();
assert!(
matches!(
err,
AplicacaoError::ShardKeyInvalid { ref shard_key, .. }
if shard_key == " $tenantId"
),
"got {err:?}"
);
}
#[test]
fn rejects_shard_key_with_trailing_newline() {
let s = sharded_spec_with_key("$tenantId\n");
let err = s.validate().unwrap_err();
assert!(
matches!(
err,
AplicacaoError::ShardKeyInvalid { ref shard_key, ref reason }
if shard_key == "$tenantId\n" && reason.contains("0x0a")
),
"got {err:?}"
);
}
#[test]
fn rejects_shard_key_with_embedded_tab() {
let s = sharded_spec_with_key("$tenant\tId");
let err = s.validate().unwrap_err();
assert!(
matches!(
err,
AplicacaoError::ShardKeyInvalid { ref shard_key, ref reason }
if shard_key == "$tenant\tId" && reason.contains("tab")
),
"got {err:?}"
);
}
#[test]
fn rejects_shard_key_with_control_character() {
let s = sharded_spec_with_key("$tenant\u{0001}Id");
let err = s.validate().unwrap_err();
assert!(
matches!(
err,
AplicacaoError::ShardKeyInvalid { ref shard_key, ref reason }
if shard_key == "$tenant\u{0001}Id" && reason.contains("control")
),
"got {err:?}"
);
}
#[test]
fn rejects_shard_key_with_non_ascii() {
let s = sharded_spec_with_key("$tenàntId");
let err = s.validate().unwrap_err();
assert!(
matches!(
err,
AplicacaoError::ShardKeyInvalid { ref shard_key, ref reason }
if shard_key == "$tenàntId" && reason.contains("non-ASCII")
),
"got {err:?}"
);
}
#[test]
fn rejects_shard_key_too_long() {
let too_long = "a".repeat(64);
let s = sharded_spec_with_key(&too_long);
let err = s.validate().unwrap_err();
let AplicacaoError::ShardKeyInvalid {
ref shard_key,
ref reason,
} = err
else {
panic!("expected ShardKeyInvalid, got {err:?}");
};
assert_eq!(shard_key, &too_long);
assert!(
reason.contains("63") && reason.contains("64"),
"diagnostic must name the cap (63) and the actual length (64): {reason:?}"
);
}
#[test]
fn shard_key_max_length_validates() {
let s = sharded_spec_with_key(&"a".repeat(63));
s.validate().unwrap();
}
#[test]
fn accepts_canonical_shard_key_forms() {
for form in [
"tenantId",
"customerId",
"$tenantId",
"metadata.tenantId",
"$.user.id",
"${tenant}",
"customer_id",
"customer-id",
"a",
"$",
] {
let s = sharded_spec_with_key(form);
s.validate().unwrap_or_else(|e| {
panic!("canonical shard-key form {form:?} must validate, got {e:?}")
});
}
}
#[test]
fn shard_key_empty_takes_precedence_over_invalid() {
let s = sharded_spec_with_key("");
let err = s.validate().unwrap_err();
assert_eq!(err, AplicacaoError::ShardedKeyEmpty);
}
#[test]
fn shard_key_invalid_diagnostic_carries_offending_value() {
let s = sharded_spec_with_key("$tenant Id");
let err = s.validate().unwrap_err();
let AplicacaoError::ShardKeyInvalid {
ref shard_key,
ref reason,
} = err
else {
panic!("expected ShardKeyInvalid, got {err:?}");
};
assert_eq!(shard_key, "$tenant Id");
assert!(
!reason.is_empty(),
"reason must name the specific violation, got empty string"
);
}
#[test]
fn shard_key_shape_fires_after_non_sharded_strategy_gate() {
let mut s = three_member_spec();
s.placement.shard_key = Some("$tenant Id".into());
let err = s.validate().unwrap_err();
assert!(
matches!(
err,
AplicacaoError::ShardKeyOnNonSharded {
estrategia: PlacementStrategy::Replicated,
..
}
),
"got {err:?}"
);
}
#[test]
fn rejects_empty_affinity_hint() {
let mut s = three_member_spec();
s.placement.affinity = Some("".into());
assert_eq!(
s.validate().unwrap_err(),
AplicacaoError::PlacementAffinityEmpty
);
}
#[test]
fn placement_without_affinity_validates() {
let mut s = three_member_spec();
s.placement.affinity = None;
s.validate().unwrap();
}
#[test]
fn rejects_placement_affinity_with_uppercase() {
let mut s = three_member_spec();
s.placement.affinity = Some("DataLocality".into());
let err = s.validate().unwrap_err();
let AplicacaoError::PlacementAffinityInvalid { affinity, reason } = err else {
panic!("expected PlacementAffinityInvalid, got other variant");
};
assert_eq!(affinity, "DataLocality");
assert!(
reason.contains("uppercase"),
"diagnostic must name the violation as `uppercase` (got: {reason:?})"
);
assert!(
reason.contains("\"datalocality\""),
"diagnostic must suggest the lower-cased fix verbatim (got: {reason:?})"
);
}
#[test]
fn rejects_placement_affinity_with_underscore() {
let mut s = three_member_spec();
s.placement.affinity = Some("data_locality".into());
let err = s.validate().unwrap_err();
assert!(
matches!(
err,
AplicacaoError::PlacementAffinityInvalid { ref affinity, ref reason }
if affinity == "data_locality" && reason.contains('_')
),
"got {err:?}"
);
}
#[test]
fn rejects_placement_affinity_with_dot() {
let mut s = three_member_spec();
s.placement.affinity = Some("data.locality".into());
let err = s.validate().unwrap_err();
assert!(
matches!(
err,
AplicacaoError::PlacementAffinityInvalid { ref affinity, ref reason }
if affinity == "data.locality" && reason.contains('.')
),
"got {err:?}"
);
}
#[test]
fn rejects_placement_affinity_with_unicode() {
let mut s = three_member_spec();
s.placement.affinity = Some("data-localité".into());
let err = s.validate().unwrap_err();
assert!(
matches!(
err,
AplicacaoError::PlacementAffinityInvalid { ref affinity, .. }
if affinity == "data-localité"
),
"got {err:?}"
);
}
#[test]
fn rejects_placement_affinity_with_leading_hyphen() {
let mut s = three_member_spec();
s.placement.affinity = Some("-data-locality".into());
let err = s.validate().unwrap_err();
assert!(
matches!(
err,
AplicacaoError::PlacementAffinityInvalid { ref affinity, ref reason }
if affinity == "-data-locality" && reason.contains("start and end")
),
"got {err:?}"
);
}
#[test]
fn rejects_placement_affinity_with_trailing_hyphen() {
let mut s = three_member_spec();
s.placement.affinity = Some("data-locality-".into());
let err = s.validate().unwrap_err();
assert!(
matches!(
err,
AplicacaoError::PlacementAffinityInvalid { ref affinity, .. }
if affinity == "data-locality-"
),
"got {err:?}"
);
}
#[test]
fn rejects_placement_affinity_with_whitespace() {
let mut s = three_member_spec();
s.placement.affinity = Some("data locality".into());
let err = s.validate().unwrap_err();
assert!(
matches!(
err,
AplicacaoError::PlacementAffinityInvalid { ref affinity, .. }
if affinity == "data locality"
),
"got {err:?}"
);
}
#[test]
fn rejects_placement_affinity_too_long() {
let mut s = three_member_spec();
let too_long = "a".repeat(64);
s.placement.affinity = Some(too_long.clone());
let err = s.validate().unwrap_err();
let AplicacaoError::PlacementAffinityInvalid { affinity, reason } = err else {
panic!("expected PlacementAffinityInvalid");
};
assert_eq!(affinity, too_long);
assert!(
reason.contains("63") && reason.contains("64"),
"diagnostic must name the cap (63) and the actual length (64): {reason:?}"
);
}
#[test]
fn placement_affinity_max_length_validates() {
let mut s = three_member_spec();
s.placement.affinity = Some("a".repeat(63));
s.validate().unwrap();
}
#[test]
fn accepts_canonical_placement_affinity_forms() {
for form in [
"data-locality",
"low-latency",
"anti-affinity",
"affinity",
"a",
"3-tier",
"locality-east",
] {
let mut s = three_member_spec();
s.placement.affinity = Some(form.into());
s.validate().unwrap_or_else(|e| {
panic!("canonical affinity form {form:?} must validate, got {e:?}")
});
}
}
#[test]
fn placement_affinity_empty_takes_precedence_over_invalid() {
let mut s = three_member_spec();
s.placement.affinity = Some(String::new());
let err = s.validate().unwrap_err();
assert_eq!(err, AplicacaoError::PlacementAffinityEmpty);
}
#[test]
fn placement_affinity_invalid_diagnostic_carries_offending_value() {
let mut s = three_member_spec();
s.placement.affinity = Some("Data_Locality".into());
let err = s.validate().unwrap_err();
let AplicacaoError::PlacementAffinityInvalid { affinity, reason } = err else {
panic!("expected PlacementAffinityInvalid");
};
assert_eq!(affinity, "Data_Locality");
assert!(
!reason.is_empty(),
"diagnostic reason must not be empty (got: {reason:?})"
);
}
#[test]
fn singlenode_with_takeover_candidates_validates() {
let mut s = three_member_spec();
s.placement.estrategia = PlacementStrategy::SingleNode;
s.placement.clusters = vec!["rio".into(), "mar".into(), "plo".into()];
s.validate().unwrap();
}
#[test]
fn mesh_policy_default_is_empty() {
assert!(MeshPolicy::default().is_empty());
}
#[test]
fn mesh_policy_with_only_timeout_is_not_empty() {
let p = MeshPolicy {
timeout: Some(Duration::from_secs(30)),
..Default::default()
};
assert!(!p.is_empty());
}
#[test]
fn mesh_policy_with_only_retries_is_not_empty() {
let p = MeshPolicy {
retries: Some(3),
..Default::default()
};
assert!(!p.is_empty());
}
#[test]
fn mesh_policy_with_only_circuit_breaker_is_not_empty() {
let p = MeshPolicy {
circuit_breaker: Some(CircuitBreaker {
max_failures: 5,
window: Duration::from_secs(60),
}),
..Default::default()
};
assert!(!p.is_empty());
}
#[test]
fn mesh_policy_with_only_mtls_required_is_not_empty() {
let p = MeshPolicy {
mtls_required: Some(false),
..Default::default()
};
assert!(!p.is_empty());
}
#[test]
fn mesh_policy_with_only_rate_limit_is_not_empty() {
let p = MeshPolicy {
rate_limit: Some(RateLimit {
rate: 100,
window: Duration::from_secs(1),
}),
..Default::default()
};
assert!(!p.is_empty());
}
#[test]
fn mesh_policy_is_empty_round_trips_through_three_member_fixture() {
assert!(!three_member_spec().politicas.is_empty());
}
#[test]
fn policy_timeout_serde_rejects_fractional_seconds() {
let payload = r#"{"timeout":"1.5s"}"#;
let err = serde_json::from_str::<MeshPolicy>(payload).unwrap_err();
let msg = err.to_string();
assert!(
msg.contains("not a non-negative integer"),
"expected integer-magnitude diagnostic in {msg:?}"
);
assert!(msg.contains("\"1.5\""), "missing magnitude in {msg:?}");
assert!(
msg.contains("\"1500ms\""),
"missing canonical-form remediation in {msg:?}"
);
}
#[test]
fn policy_timeout_serde_rejects_leading_plus_sign() {
let payload = r#"{"timeout":"+30s"}"#;
let err = serde_json::from_str::<MeshPolicy>(payload).unwrap_err();
let msg = err.to_string();
assert!(msg.contains("\"+30\""), "missing magnitude in {msg:?}");
}
#[test]
fn circuit_breaker_window_serde_rejects_fractional_minutes() {
let payload = format!(
r#"{{"{max_failures}":5,"{window}":"0.5m"}}"#,
max_failures = crate::CIRCUIT_BREAKER_KEY_MAX_FAILURES,
window = crate::CIRCUIT_BREAKER_KEY_WINDOW,
);
let err = serde_json::from_str::<CircuitBreaker>(&payload).unwrap_err();
let msg = err.to_string();
assert!(
msg.contains("not a non-negative integer"),
"expected integer-magnitude diagnostic in {msg:?}"
);
assert!(msg.contains("\"0.5\""), "missing magnitude in {msg:?}");
assert!(
msg.contains("\"30s\""),
"missing canonical-form remediation in {msg:?}"
);
}
#[test]
fn circuit_breaker_window_serde_accepts_integer_canonical_form() {
for window_lit in ["30s", "500ms", "2m", "1h"] {
let payload = format!(
r#"{{"{max_failures}":5,"{window}":"{window_lit}"}}"#,
max_failures = crate::CIRCUIT_BREAKER_KEY_MAX_FAILURES,
window = crate::CIRCUIT_BREAKER_KEY_WINDOW,
);
let cb: CircuitBreaker = serde_json::from_str(&payload).unwrap_or_else(|e| {
panic!("expected {window_lit:?} to parse cleanly through shared codec: {e}")
});
assert_eq!(cb.max_failures, 5);
}
}
#[test]
fn rate_limit_serde_rejects_fractional_rate() {
let payload = r#"{"rateLimit":"1.5/s"}"#;
let err = serde_json::from_str::<MeshPolicy>(payload).unwrap_err();
let msg = err.to_string();
assert!(
msg.contains("not a non-negative integer"),
"expected integer-magnitude diagnostic in {msg:?}"
);
assert!(msg.contains("\"1.5\""), "missing magnitude in {msg:?}");
assert!(
msg.contains("THEORY.md"),
"missing render-determinism contract citation in {msg:?}"
);
}
#[test]
fn rate_limit_serde_rejects_leading_plus_sign() {
let payload = r#"{"rateLimit":"+100/s"}"#;
let err = serde_json::from_str::<MeshPolicy>(payload).unwrap_err();
let msg = err.to_string();
assert!(
msg.contains("not a non-negative integer"),
"expected integer-magnitude diagnostic in {msg:?}"
);
assert!(msg.contains("\"+100\""), "missing magnitude in {msg:?}");
}
#[test]
fn rate_limit_serde_rejects_leading_minus_sign() {
let payload = r#"{"rateLimit":"-1/s"}"#;
let err = serde_json::from_str::<MeshPolicy>(payload).unwrap_err();
let msg = err.to_string();
assert!(
msg.contains("not a non-negative integer"),
"expected integer-magnitude diagnostic in {msg:?}"
);
assert!(msg.contains("\"-1\""), "missing magnitude in {msg:?}");
}
#[test]
fn rate_limit_serde_rejects_decimal_shaped_integer() {
let payload = r#"{"rateLimit":"100.0/s"}"#;
let err = serde_json::from_str::<MeshPolicy>(payload).unwrap_err();
let msg = err.to_string();
assert!(
msg.contains("not a non-negative integer"),
"expected integer-magnitude diagnostic in {msg:?}"
);
assert!(msg.contains("\"100.0\""), "missing magnitude in {msg:?}");
}
#[test]
fn rate_limit_serde_garbage_still_falls_through_to_not_a_u32() {
let payload = r#"{"rateLimit":"abc/s"}"#;
let err = serde_json::from_str::<MeshPolicy>(payload).unwrap_err();
let msg = err.to_string();
assert!(
msg.contains("not a u32"),
"garbage magnitude must surface the narrower `not a u32` wording, got: {msg:?}"
);
assert!(
!msg.contains("not a non-negative integer"),
"garbage magnitude must NOT surface the canonical-form arm, got: {msg:?}"
);
}
#[test]
fn rate_limit_serde_u32_overflow_surfaces_as_overflow() {
let payload = r#"{"rateLimit":"4294967296/s"}"#;
let err = serde_json::from_str::<MeshPolicy>(payload).unwrap_err();
let msg = err.to_string();
assert!(
msg.contains("overflows u32"),
"expected overflow diagnostic in {msg:?}"
);
assert!(
msg.contains("\"4294967296\""),
"missing offending magnitude in {msg:?}"
);
}
#[test]
fn rate_limit_serde_rejects_leading_zero_magnitude() {
let payload = r#"{"rateLimit":"0100/s"}"#;
let err = serde_json::from_str::<MeshPolicy>(payload).unwrap_err();
let msg = err.to_string();
assert!(
msg.contains("non-canonical leading zero"),
"expected leading-zero diagnostic in {msg:?}"
);
assert!(msg.contains("\"0100\""), "missing magnitude in {msg:?}");
assert!(
msg.contains("THEORY.md"),
"missing render-determinism contract citation in {msg:?}"
);
}
#[test]
fn rate_limit_serde_rejects_multi_digit_zero_magnitude() {
let payload = r#"{"rateLimit":"00/s"}"#;
let err = serde_json::from_str::<MeshPolicy>(payload).unwrap_err();
let msg = err.to_string();
assert!(
msg.contains("non-canonical leading zero"),
"expected leading-zero diagnostic in {msg:?}"
);
assert!(msg.contains("\"00\""), "missing magnitude in {msg:?}");
}
#[test]
fn rate_limit_serde_rejects_leading_zero_per_hour_window() {
let payload = r#"{"rateLimit":"007/h"}"#;
let err = serde_json::from_str::<MeshPolicy>(payload).unwrap_err();
let msg = err.to_string();
assert!(
msg.contains("non-canonical leading zero"),
"expected leading-zero diagnostic in {msg:?}"
);
assert!(msg.contains("\"007\""), "missing magnitude in {msg:?}");
}
#[test]
fn rate_limit_serde_rejects_leading_whitespace() {
let payload = r#"{"rateLimit":" 100/s"}"#;
let err = serde_json::from_str::<MeshPolicy>(payload).unwrap_err();
let msg = err.to_string();
assert!(
msg.contains("contains whitespace byte"),
"expected whitespace diagnostic in {msg:?}"
);
assert!(msg.contains("0x20"), "missing offending byte in {msg:?}");
assert!(
msg.contains("THEORY.md"),
"missing render-determinism contract citation in {msg:?}"
);
}
#[test]
fn rate_limit_serde_rejects_trailing_whitespace() {
let payload = r#"{"rateLimit":"100/s "}"#;
let err = serde_json::from_str::<MeshPolicy>(payload).unwrap_err();
let msg = err.to_string();
assert!(
msg.contains("contains whitespace byte"),
"expected whitespace diagnostic in {msg:?}"
);
assert!(msg.contains("0x20"), "missing offending byte in {msg:?}");
}
#[test]
fn rate_limit_serde_rejects_internal_whitespace_around_separator() {
let payload = r#"{"rateLimit":"100 / s"}"#;
let err = serde_json::from_str::<MeshPolicy>(payload).unwrap_err();
let msg = err.to_string();
assert!(
msg.contains("contains whitespace byte"),
"expected whitespace diagnostic in {msg:?}"
);
assert!(msg.contains("0x20"), "missing offending byte in {msg:?}");
}
#[test]
fn rate_limit_serde_rejects_tab_byte() {
let payload = r#"{"rateLimit":"\t100/s"}"#;
let err = serde_json::from_str::<MeshPolicy>(payload).unwrap_err();
let msg = err.to_string();
assert!(
msg.contains("contains whitespace byte"),
"expected whitespace diagnostic in {msg:?}"
);
assert!(
msg.contains("0x09"),
"missing offending tab byte in {msg:?}"
);
}
#[test]
fn rate_limit_serde_rejects_leading_nbsp() {
let payload = "{\"rateLimit\":\"\u{00A0}100/s\"}";
let err = serde_json::from_str::<MeshPolicy>(payload).unwrap_err();
let msg = err.to_string();
assert!(
msg.contains("non-ASCII Unicode whitespace character"),
"expected non-ASCII whitespace diagnostic in {msg:?}"
);
assert!(msg.contains("U+00A0"), "missing codepoint in {msg:?}");
}
#[test]
fn rate_limit_serde_rejects_internal_em_space() {
let payload = "{\"rateLimit\":\"100\u{2003}/s\"}";
let err = serde_json::from_str::<MeshPolicy>(payload).unwrap_err();
let msg = err.to_string();
assert!(
msg.contains("non-ASCII Unicode whitespace character"),
"expected non-ASCII whitespace diagnostic in {msg:?}"
);
assert!(msg.contains("U+2003"), "missing codepoint in {msg:?}");
}
#[test]
fn rate_limit_serde_accepts_ascii_only_canonical_forms_after_unicode_arm() {
for lit in [r#""100/s""#, r#""5000/m""#, r#""10000/h""#] {
let payload = format!(r#"{{"rateLimit":{lit}}}"#);
let p: MeshPolicy = serde_json::from_str(&payload)
.unwrap_or_else(|e| panic!("expected {lit} to parse; got {e}"));
assert!(p.rate_limit.is_some());
}
}
#[test]
fn rate_limit_serde_accepts_single_zero_magnitude_at_codec_layer() {
let payload = r#"{"rateLimit":"0/s"}"#;
let policy: MeshPolicy = serde_json::from_str(payload).unwrap_or_else(|e| {
panic!("`\"0/s\"` must parse cleanly through rate_limit_codec: {e}")
});
let rl = policy.rate_limit.expect("rate_limit must be Some");
assert_eq!(rl.rate, 0, "single-`0` magnitude must parse to rate=0");
assert_eq!(
rl.window,
Duration::from_secs(1),
"single-`0` magnitude with `s` unit must parse to window=1s"
);
}
#[test]
fn rate_limit_serde_accepts_canonical_magnitude_with_leading_one() {
let payload = r#"{"rateLimit":"100/s"}"#;
let policy: MeshPolicy = serde_json::from_str(payload)
.unwrap_or_else(|e| panic!("canonical `\"100/s\"` must parse cleanly: {e}"));
let rl = policy.rate_limit.expect("rate_limit must be Some");
assert_eq!(
rl.rate, 100,
"canonical-100 magnitude must parse to rate=100"
);
}
#[test]
fn rate_limit_serde_accepts_integer_canonical_forms() {
for rate_lit in ["0", "1", "100", "5000", "1000000", "4294967295"] {
for unit_lit in ["s", "m", "h"] {
let lit = format!("{rate_lit}/{unit_lit}");
let payload = format!(r#"{{"rateLimit":{lit:?}}}"#);
let policy: MeshPolicy = serde_json::from_str(&payload).unwrap_or_else(|e| {
panic!("expected {lit:?} to parse cleanly through rate_limit_codec: {e}")
});
let rl = policy.rate_limit.expect("rate_limit must be Some");
assert_eq!(
rl.rate,
rate_lit.parse::<u32>().unwrap(),
"rate mismatch for {lit:?}"
);
}
}
}
#[test]
fn rate_limit_serde_round_trip_holds_for_every_canonical_form() {
for rate in [1u32, 100, 5000, 1_000_000] {
for (window, unit) in [
(Duration::from_secs(1), "s"),
(Duration::from_secs(60), "m"),
(Duration::from_secs(3600), "h"),
] {
let policy = MeshPolicy {
rate_limit: Some(RateLimit { rate, window }),
..Default::default()
};
let json = serde_json::to_string(&policy).unwrap();
let expected = format!("\"{rate}/{unit}\"");
assert!(
json.contains(&expected),
"expected {expected:?} in {json:?}"
);
let back: MeshPolicy = serde_json::from_str(&json).unwrap();
assert_eq!(
back.rate_limit, policy.rate_limit,
"round-trip for {json:?}"
);
}
}
}
#[test]
fn validate_no_self_membership_rejects_self_named_membro() {
let membros = vec![
membro("catalog", "^0.1"),
membro("checkout", "^0.1"),
membro("cart", "^0.1"),
];
let err = validate_no_self_membership(&membros, "checkout").unwrap_err();
assert!(
matches!(err, AplicacaoError::MembroIsSelfAplicacao { ref caixa } if caixa == "checkout"),
"got {err:?}"
);
}
#[test]
fn validate_no_self_membership_accepts_distinct_membros() {
let membros = vec![membro("catalog", "^0.1"), membro("sub-aplicacao", "^0.1")];
validate_no_self_membership(&membros, "checkout").unwrap();
}
#[test]
fn validate_no_self_membership_empty_membros_is_vacuously_ok() {
validate_no_self_membership(&[], "checkout").unwrap();
}
#[test]
fn validate_no_self_membership_diagnostic_names_offending_caixa() {
let membros = vec![membro("orquestra", "^0.1")];
let err = validate_no_self_membership(&membros, "orquestra").unwrap_err();
let msg = err.to_string();
assert!(
msg.contains("orquestra"),
"diagnostic must name the offending caixa nome (got: {msg:?})"
);
assert!(
msg.contains("lists itself"),
"diagnostic must use the canonical `lists itself` framing (got: {msg:?})"
);
}
#[test]
fn default_servico_port_constant_pins_canonical_8080_literal() {
assert_eq!(
DEFAULT_SERVICO_PORT, 8080,
"canonical Servico port literal must remain `8080` verbatim — \
this is the value both the `Entrada::port` serde default and the \
caixa-mesh `CiliumNetworkPolicy` L4-fallback read from"
);
}
#[test]
fn default_port_helper_returns_canonical_servico_port_constant() {
assert_eq!(
default_port(),
DEFAULT_SERVICO_PORT,
"the serde-default helper must route through the lifted constant"
);
}
#[test]
fn entrada_serde_default_port_inherits_canonical_servico_port_constant() {
let entrada: Entrada =
serde_yaml::from_str("host: checkout.quero.cloud\npara: cart\n").expect("yaml parses");
assert_eq!(
entrada.port, DEFAULT_SERVICO_PORT,
"the serde default must materialize as the lifted canonical Servico port"
);
}
#[test]
fn servico_port_min_pins_canonical_accept_set_floor() {
assert_eq!(
SERVICO_PORT_MIN, 1,
"canonical Servico port accept-set floor must remain `1` verbatim — \
this is the value the `AplicacaoSpec::validate` gate at \
`if e.port < SERVICO_PORT_MIN` rejects `port: 0` against"
);
}
#[test]
fn default_servico_port_satisfies_lifted_servico_port_min_floor() {
assert!(
SERVICO_PORT_MIN <= DEFAULT_SERVICO_PORT,
"the substrate's canonical default port ({DEFAULT_SERVICO_PORT}) must \
satisfy its own accept-set floor (SERVICO_PORT_MIN = {SERVICO_PORT_MIN}) — \
every default-carrying `(:entrada (:host … :para …))` slot without an \
explicit `:port` inherits `DEFAULT_SERVICO_PORT` through the serde default \
hook and must pass the `AplicacaoSpec::validate` floor gate by construction"
);
}
#[test]
fn entrada_port_zero_gate_routes_through_lifted_servico_port_min_floor() {
assert_eq!(SERVICO_PORT_MIN, 1, "current floor pinned above");
let mut s = three_member_spec();
s.entrada.as_mut().unwrap().port = 0;
assert_eq!(s.validate().unwrap_err(), AplicacaoError::EntradaPortZero);
}
#[test]
fn membro_serde_keys_match_lifted_membro_key_consts() {
let m = Membro {
caixa: "catalog".into(),
versao: "^0.1".into(),
};
let json = serde_json::to_string(&m).unwrap();
for key in [crate::MEMBRO_KEY_CAIXA, crate::MEMBRO_KEY_VERSAO] {
let quoted = format!("\"{key}\"");
assert!(
json.contains("ed),
"serialized Membro must carry the lifted MEMBRO_KEY_* \
byte-sequence {quoted} verbatim in the JSON emission \
(got: {json})",
);
}
}
#[test]
fn membro_key_consts_are_pairwise_distinct() {
let all = [crate::MEMBRO_KEY_CAIXA, crate::MEMBRO_KEY_VERSAO];
for (i, a) in all.iter().enumerate() {
for b in all.iter().skip(i + 1) {
assert_ne!(
a, b,
"MEMBRO_KEY_* consts must be pairwise-distinct \
canonical byte-sequences — got `{a}` == `{b}`",
);
}
}
}
fn entrada_with_paths(paths: Vec<&str>) -> Entrada {
Entrada {
host: "example.com".into(),
para: "cart".into(),
paths: paths.into_iter().map(String::from).collect(),
port: DEFAULT_SERVICO_PORT,
}
}
#[test]
fn resolved_paths_returns_declared_paths_verbatim_when_non_empty() {
let e = entrada_with_paths(vec!["/api/cart", "/api/products"]);
assert_eq!(
e.resolved_paths(),
vec!["/api/cart", "/api/products"],
"resolved_paths must return each `:entrada :paths` entry \
verbatim when the typed slot is non-empty (got {:?})",
e.resolved_paths(),
);
}
#[test]
fn resolved_paths_falls_back_to_gateway_api_default_http_route_path_when_paths_empty() {
let e = entrada_with_paths(vec![]);
assert_eq!(
e.resolved_paths(),
vec![crate::GATEWAY_API_DEFAULT_HTTP_ROUTE_PATH],
"resolved_paths on empty `:entrada :paths` must fall back \
to the lifted GATEWAY_API_DEFAULT_HTTP_ROUTE_PATH catch-\
all — got {:?}",
e.resolved_paths(),
);
}
#[test]
fn resolved_paths_returns_single_declared_path_verbatim_when_len_one() {
let e = entrada_with_paths(vec!["/api/only"]);
assert_eq!(
e.resolved_paths(),
vec!["/api/only"],
"resolved_paths on single-entry `:entrada :paths` must \
return the declared path verbatim, NOT the catch-all \
fallback (got {:?})",
e.resolved_paths(),
);
}
#[test]
fn resolved_paths_preserves_author_declared_order() {
let e = entrada_with_paths(vec!["/z/last", "/a/first", "/m/mid"]);
assert_eq!(
e.resolved_paths(),
vec!["/z/last", "/a/first", "/m/mid"],
"resolved_paths must preserve author-declared `:entrada \
:paths` order verbatim — got {:?}",
e.resolved_paths(),
);
}
#[test]
fn paths_returns_entrada_paths_slice_byte_equal_across_permutations() {
let fixtures: Vec<Vec<String>> = vec![
Vec::new(),
vec!["/api/cart".into()],
vec!["/api/cart".into(), "/api/products".into()],
vec!["/z/last".into(), "/a/first".into(), "/m/mid".into()],
];
for paths in fixtures {
let e = Entrada {
host: "example.com".into(),
para: "cart".into(),
paths: paths.clone(),
port: DEFAULT_SERVICO_PORT,
};
assert_eq!(
e.paths(),
paths.as_slice(),
"Entrada::paths must return :entrada :paths verbatim \
(got {:?}, expected {:?})",
e.paths(),
paths.as_slice(),
);
assert_eq!(
e.paths(),
e.paths.as_slice(),
"Entrada::paths accessor and .paths.as_slice() field \
access must byte-equal — the accessor is the substrate-\
primitive typed dispatch every downstream per-`:entrada` \
raw-slot path-list consumer must route through",
);
assert_eq!(
e.paths().len(),
e.paths.len(),
"Entrada::paths().len() must byte-equal self.paths.len() \
— a length drift would silently split the paired \
pre-flight cascade-head `.is_empty()` probe input in \
the sibling [`Entrada::resolved_paths`] resolver from \
the per-entry validate loop's traversal input in \
[`AplicacaoSpec::validate`]",
);
}
}
#[test]
fn resolved_paths_reads_through_lifted_paths_accessor() {
let empty = entrada_with_paths(vec![]);
assert_eq!(
empty.resolved_paths(),
vec![crate::GATEWAY_API_DEFAULT_HTTP_ROUTE_PATH],
"resolved_paths on empty :entrada :paths must trip the \
lifted [`crate::GATEWAY_API_DEFAULT_HTTP_ROUTE_PATH`] \
catch-all fallback — routing through the lifted paths() \
accessor must not silently drop the fallback arm",
);
let declared = entrada_with_paths(vec!["/api/cart", "/api/products"]);
assert_eq!(
declared.resolved_paths(),
vec!["/api/cart", "/api/products"],
"resolved_paths on non-empty :entrada :paths must return each \
entry verbatim in the author's declared order — routing \
through the lifted paths() accessor must not silently \
reorder or drop entries",
);
let raw_projected: Vec<&str> = declared.paths().iter().map(String::as_str).collect();
assert_eq!(
declared.resolved_paths(),
raw_projected,
"resolved_paths non-empty projection must byte-equal the \
lifted paths() accessor's per-entry String::as_str projection \
— the two projections share the same input slice by \
construction, so any drift here would surface a silent \
re-ordering / dedup / normalization detour in the resolver",
);
}
#[test]
fn validate_reads_through_lifted_entrada_paths_accessor() {
let base = crate::AplicacaoSpec {
membros: vec![crate::Membro {
caixa: "cart".into(),
versao: "^0.1".into(),
}],
contratos: Vec::new(),
politicas: crate::MeshPolicy::default(),
placement: crate::Placement {
estrategia: crate::PlacementStrategy::SingleNode,
clusters: vec!["rio".into()],
shard_key: None,
affinity: None,
},
entrada: Some(Entrada {
host: "example.com".into(),
para: "cart".into(),
paths: vec!["/api/cart".into(), String::new()],
port: DEFAULT_SERVICO_PORT,
}),
};
assert_eq!(
base.validate(),
Err(crate::AplicacaoError::EntradaPathEmpty),
"validate must trip EntradaPathEmpty on the second entry of \
a two-entry cohort — routing through the lifted paths() \
accessor must not silently short-circuit the loop at the \
valid head entry",
);
let mut dup = base;
dup.entrada.as_mut().unwrap().paths = vec!["/api/cart".into(), "/api/cart".into()];
assert_eq!(
dup.validate(),
Err(crate::AplicacaoError::EntradaPathDuplicate {
path: "/api/cart".into(),
}),
"validate must trip EntradaPathDuplicate on the second entry \
of a two-entry cohort that shares a path — routing through \
the lifted paths() accessor must not silently short-circuit \
the dedup HashSet insert at the first entry",
);
}
fn entrada_with_host(host: &str) -> Entrada {
Entrada {
host: host.into(),
para: "cart".into(),
paths: Vec::new(),
port: DEFAULT_SERVICO_PORT,
}
}
#[test]
fn hostname_returns_entrada_host_byte_equal() {
let e = entrada_with_host("checkout.quero.cloud");
assert_eq!(
e.hostname(),
"checkout.quero.cloud",
"Entrada::hostname must return :entrada :host verbatim \
(got {:?})",
e.hostname(),
);
assert_eq!(
e.hostname(),
e.host.as_str(),
"Entrada::hostname must byte-equal the .host field access",
);
}
#[test]
fn hostnames_returns_singleton_of_hostname_accessor() {
let e = entrada_with_host("checkout.quero.cloud");
assert_eq!(
e.hostnames(),
vec![e.hostname()],
"Entrada::hostnames must return `vec![hostname()]` under \
the pair-invariant — got {:?} vs. singleton {:?}",
e.hostnames(),
vec![e.hostname()],
);
}
#[test]
fn hostnames_is_singleton_under_single_host_author_surface() {
let e = entrada_with_host("checkout.quero.cloud");
assert_eq!(
e.hostnames().len(),
1,
"Entrada::hostnames must be a singleton under today's \
single-hostname-per-`:entrada` author surface — got \
length {}: {:?}",
e.hostnames().len(),
e.hostnames(),
);
}
#[test]
fn destination_returns_entrada_para_byte_equal() {
for para in ["cart", "checkout", "catalog", "orders-v2"] {
let e = Entrada {
host: "checkout.quero.cloud".into(),
para: para.into(),
paths: Vec::new(),
port: DEFAULT_SERVICO_PORT,
};
assert_eq!(
e.destination(),
para,
"Entrada::destination must return :entrada :para verbatim \
(got {:?}, expected {para:?})",
e.destination(),
);
assert_eq!(
e.destination(),
e.para.as_str(),
"Entrada::destination must byte-equal the .para field access",
);
}
}
#[test]
fn destination_borrows_from_entrada_para_storage() {
let e = entrada_with_host("checkout.quero.cloud");
let dest = e.destination();
let para_slice = e.para.as_str();
assert_eq!(
dest.as_ptr(),
para_slice.as_ptr(),
"Entrada::destination must borrow from the .para String's \
backing storage — a fresh allocation here means the \
accessor no longer names the substrate-primitive typed \
dispatch and every downstream consumer would silently \
carry a detached copy",
);
assert_eq!(
dest.len(),
para_slice.len(),
"Entrada::destination and .para.as_str() must byte-equal in \
length as well as in address",
);
}
#[test]
fn port_returns_entrada_port_verbatim_across_permutations() {
for port in [
SERVICO_PORT_MIN,
DEFAULT_SERVICO_PORT,
8443u16,
9090u16,
u16::MAX,
] {
let e = Entrada {
host: "checkout.quero.cloud".into(),
para: "cart".into(),
paths: Vec::new(),
port,
};
assert_eq!(
e.port(),
port,
"Entrada::port must return :entrada :port verbatim \
(got {}, expected {port})",
e.port(),
);
assert_eq!(
e.port(),
e.port,
"Entrada::port accessor and .port field access must \
byte-equal — the accessor is the substrate-primitive \
typed dispatch every downstream L4-port consumer must \
route through",
);
}
}
#[test]
fn validate_entrada_port_floor_gate_reads_through_lifted_port_accessor() {
let mut spec = three_member_spec();
if let Some(e) = spec.entrada.as_mut() {
e.port = 0;
}
assert_eq!(
spec.validate().unwrap_err(),
AplicacaoError::EntradaPortZero,
"validate must reject `:entrada :port 0` through the lifted \
Entrada::port accessor — port zero lies below \
SERVICO_PORT_MIN and the validator routes through port() \
to name the floor",
);
for port in [SERVICO_PORT_MIN, DEFAULT_SERVICO_PORT, 8443u16] {
let mut spec = three_member_spec();
if let Some(e) = spec.entrada.as_mut() {
e.port = port;
}
spec.validate().expect(
"entrada with in-accept-set :port must validate — the \
structural-floor gate reads through Entrada::port",
);
let entrada_ref = spec.entrada.as_ref().expect(":entrada present");
assert_eq!(
spec.port_for_destination(entrada_ref.destination()),
entrada_ref.port(),
"port_for_destination(entrada.destination()) must equal \
entrada.port() — the two consumers of the per-:entrada \
L4-port axis (validator, per-destination resolver) both \
route through Entrada::port",
);
}
}
#[test]
fn wit_contract_source_returns_de_byte_equal_across_permutations() {
for de in ["cart", "checkout", "catalog", "orders-v2"] {
let c = WitContract {
de: de.into(),
para: "downstream".into(),
wit: "wasi:http/proxy".into(),
endpoint: Some("/lookup".into()),
subject: None,
slot: None,
};
assert_eq!(
c.source(),
de,
"WitContract::source must return :contratos :de verbatim \
(got {:?}, expected {de:?})",
c.source(),
);
assert_eq!(
c.source(),
c.de.as_str(),
"WitContract::source must byte-equal the .de field access",
);
}
}
#[test]
fn wit_contract_source_borrows_from_de_storage() {
let c = WitContract {
de: "cart".into(),
para: "catalog".into(),
wit: "wasi:http/proxy".into(),
endpoint: Some("/lookup".into()),
subject: None,
slot: None,
};
let src = c.source();
let de_slice = c.de.as_str();
assert_eq!(
src.as_ptr(),
de_slice.as_ptr(),
"WitContract::source must borrow from the .de String's \
backing storage — a fresh allocation here means the \
accessor no longer names the substrate-primitive typed \
dispatch and every downstream consumer would silently \
carry a detached copy",
);
assert_eq!(
src.len(),
de_slice.len(),
"WitContract::source and .de.as_str() must byte-equal in \
length as well as in address",
);
}
#[test]
fn wit_contract_destination_returns_para_byte_equal_across_permutations() {
for para in ["catalog", "payment", "orders", "inventory-v3"] {
let c = WitContract {
de: "cart".into(),
para: para.into(),
wit: "wasi:http/proxy".into(),
endpoint: Some("/lookup".into()),
subject: None,
slot: None,
};
assert_eq!(
c.destination(),
para,
"WitContract::destination must return :contratos :para \
verbatim (got {:?}, expected {para:?})",
c.destination(),
);
assert_eq!(
c.destination(),
c.para.as_str(),
"WitContract::destination must byte-equal the .para \
field access",
);
}
}
#[test]
fn wit_contract_destination_borrows_from_para_storage() {
let c = WitContract {
de: "cart".into(),
para: "catalog".into(),
wit: "wasi:http/proxy".into(),
endpoint: Some("/lookup".into()),
subject: None,
slot: None,
};
let dest = c.destination();
let para_slice = c.para.as_str();
assert_eq!(
dest.as_ptr(),
para_slice.as_ptr(),
"WitContract::destination must borrow from the .para \
String's backing storage — a fresh allocation here means \
the accessor no longer names the substrate-primitive typed \
dispatch and every downstream consumer would silently \
carry a detached copy",
);
assert_eq!(
dest.len(),
para_slice.len(),
"WitContract::destination and .para.as_str() must byte-equal \
in length as well as in address",
);
}
#[test]
fn wit_contract_world_ref_returns_wit_byte_equal_across_permutations() {
for (wit, endpoint, subject, slot) in [
("wasi:http/proxy", Some("/lookup"), None, None),
("http:proxy", Some("/health"), None, None),
("nats:pub-sub", None, Some("orders.paid"), None),
("kafka:events", None, Some("checkout-events"), None),
("wasi:keyvalue/store", None, None, Some("carts/{cart_id}")),
] {
let c = WitContract {
de: "cart".into(),
para: "downstream".into(),
wit: wit.into(),
endpoint: endpoint.map(str::to_string),
subject: subject.map(str::to_string),
slot: slot.map(str::to_string),
};
assert_eq!(
c.world_ref(),
wit,
"WitContract::world_ref must return :contratos :wit \
verbatim (got {:?}, expected {wit:?})",
c.world_ref(),
);
assert_eq!(
c.world_ref(),
c.wit.as_str(),
"WitContract::world_ref must byte-equal the .wit field \
access",
);
}
}
#[test]
fn wit_contract_world_ref_borrows_from_wit_storage() {
let c = WitContract {
de: "cart".into(),
para: "catalog".into(),
wit: "wasi:http/proxy".into(),
endpoint: Some("/lookup".into()),
subject: None,
slot: None,
};
let world = c.world_ref();
let wit_slice = c.wit.as_str();
assert_eq!(
world.as_ptr(),
wit_slice.as_ptr(),
"WitContract::world_ref must borrow from the .wit String's \
backing storage — a fresh allocation here means the \
accessor no longer names the substrate-primitive typed \
dispatch and every downstream consumer would silently carry \
a detached copy",
);
assert_eq!(
world.len(),
wit_slice.len(),
"WitContract::world_ref and .wit.as_str() must byte-equal in \
length as well as in address",
);
}
#[test]
fn wit_contract_source_destination_world_ref_project_de_para_wit_triple() {
for (de, para, wit, endpoint, subject, slot) in [
(
"cart",
"catalog",
"wasi:http/proxy",
Some("/lookup"),
None,
None,
),
(
"checkout",
"orders",
"nats:pub-sub",
None,
Some("orders.paid"),
None,
),
(
"cart",
"kv",
"wasi:keyvalue/store",
None,
None,
Some("carts/{cart_id}"),
),
(
"orders-v2",
"inventory-v3",
"http:proxy",
Some("/reserve"),
None,
None,
),
] {
let c = WitContract {
de: de.into(),
para: para.into(),
wit: wit.into(),
endpoint: endpoint.map(str::to_string),
subject: subject.map(str::to_string),
slot: slot.map(str::to_string),
};
assert_eq!(
(c.source(), c.destination(), c.world_ref()),
(c.de.as_str(), c.para.as_str(), c.wit.as_str()),
"(WitContract::source, ::destination, ::world_ref) must \
project (.de, .para, .wit) verbatim across every author-\
declared triple (got ({:?}, {:?}, {:?}), expected \
({de:?}, {para:?}, {wit:?}))",
c.source(),
c.destination(),
c.world_ref(),
);
}
}
#[test]
fn wit_contract_edge_pair_returns_source_destination_owned_pair_across_permutations() {
for (de, para, wit, endpoint, subject, slot) in [
(
"cart",
"catalog",
"wasi:http/proxy",
Some("/lookup"),
None,
None,
),
(
"checkout",
"orders",
"nats:pub-sub",
None,
Some("orders.paid"),
None,
),
(
"cart",
"kv",
"wasi:keyvalue/store",
None,
None,
Some("carts/{cart_id}"),
),
(
"orders-v2",
"inventory-v3",
"http:proxy",
Some("/reserve"),
None,
None,
),
] {
let c = WitContract {
de: de.into(),
para: para.into(),
wit: wit.into(),
endpoint: endpoint.map(str::to_string),
subject: subject.map(str::to_string),
slot: slot.map(str::to_string),
};
assert_eq!(
c.edge_pair(),
(de.to_string(), para.to_string()),
"WitContract::edge_pair must return (:contratos :de, \
:contratos :para) as an owned tuple verbatim (got {:?}, \
expected ({de:?}, {para:?}))",
c.edge_pair(),
);
}
}
#[test]
fn wit_contract_edge_pair_routes_through_source_destination_accessors() {
let c = WitContract {
de: "cart".into(),
para: "catalog".into(),
wit: "wasi:http/proxy".into(),
endpoint: Some("/lookup".into()),
subject: None,
slot: None,
};
assert_eq!(
c.edge_pair(),
(c.source().to_string(), c.destination().to_string()),
"WitContract::edge_pair must compose exactly \
(source().to_string(), destination().to_string()) — a \
bypass of either sibling accessor here would silently \
decouple the composite-projection axis from the \
substrate-primitive scalar accessors every downstream \
consumer routes through",
);
}
#[test]
fn wit_contract_edge_triple_returns_source_destination_world_ref_owned_triple_across_permutations()
{
for (de, para, wit, endpoint, subject, slot) in [
(
"cart",
"catalog",
"wasi:http/proxy",
Some("/lookup"),
None,
None,
),
(
"checkout",
"orders",
"nats:pub-sub",
None,
Some("orders.paid"),
None,
),
(
"cart",
"kv",
"wasi:keyvalue/store",
None,
None,
Some("carts/{cart_id}"),
),
(
"orders-v2",
"inventory-v3",
"http:proxy",
Some("/reserve"),
None,
None,
),
] {
let c = WitContract {
de: de.into(),
para: para.into(),
wit: wit.into(),
endpoint: endpoint.map(str::to_string),
subject: subject.map(str::to_string),
slot: slot.map(str::to_string),
};
assert_eq!(
c.edge_triple(),
(de.to_string(), para.to_string(), wit.to_string()),
"WitContract::edge_triple must return (:contratos :de, \
:contratos :para, :contratos :wit) as an owned triple \
verbatim (got {:?}, expected ({de:?}, {para:?}, {wit:?}))",
c.edge_triple(),
);
}
}
#[test]
fn wit_contract_edge_triple_routes_through_source_destination_world_ref_accessors() {
let c = WitContract {
de: "cart".into(),
para: "catalog".into(),
wit: "wasi:http/proxy".into(),
endpoint: Some("/lookup".into()),
subject: None,
slot: None,
};
assert_eq!(
c.edge_triple(),
(
c.source().to_string(),
c.destination().to_string(),
c.world_ref().to_string(),
),
"WitContract::edge_triple must compose exactly \
(source().to_string(), destination().to_string(), \
world_ref().to_string()) — a bypass of any sibling accessor \
here would silently decouple the composite-projection axis \
from the substrate-primitive scalar accessors every \
downstream consumer routes through",
);
}
#[test]
fn wit_contract_edge_triple_projects_full_typed_edge_identity_owned_triple() {
let c = WitContract {
de: "checkout".into(),
para: "orders".into(),
wit: "nats:pub-sub".into(),
endpoint: None,
subject: Some("orders.paid".into()),
slot: None,
};
let (de, para, wit) = c.edge_triple();
assert_eq!(de, "checkout");
assert_eq!(para, "orders");
assert_eq!(wit, "nats:pub-sub");
}
#[test]
fn wit_contract_identity_routes_through_source_destination_world_ref_endpoint_subject_slot_accessors()
{
for (de, para, wit, endpoint, subject, slot) in [
(
"cart",
"catalog",
"wasi:http/proxy",
Some("/lookup"),
None,
None,
),
(
"checkout",
"orders",
"nats:pub-sub",
None,
Some("orders.paid"),
None,
),
(
"cart",
"kv",
"wasi:keyvalue/store",
None,
None,
Some("carts/{cart_id}"),
),
("audit", "sink", "wasi:logging", None, None, None),
] {
let c = WitContract {
de: de.into(),
para: para.into(),
wit: wit.into(),
endpoint: endpoint.map(str::to_owned),
subject: subject.map(str::to_owned),
slot: slot.map(str::to_owned),
};
assert_eq!(
c.identity(),
(
c.source(),
c.destination(),
c.world_ref(),
c.endpoint(),
c.subject(),
c.slot(),
),
"WitContract::identity must compose exactly \
(source(), destination(), world_ref(), endpoint(), \
subject(), slot()) — a bypass of any sibling accessor \
here would silently decouple the identity-projection \
axis from the substrate-primitive scalar accessors \
every dedup-key consumer routes through",
);
}
}
#[test]
fn wit_contract_identity_projects_full_typed_edge_dedup_key_across_payload_shapes() {
let c = WitContract {
de: "cart".into(),
para: "catalog".into(),
wit: "wasi:http/proxy".into(),
endpoint: Some("/products/:id".into()),
subject: None,
slot: None,
};
let (de, para, wit, endpoint, subject, slot) = c.identity();
assert_eq!(de, "cart");
assert_eq!(para, "catalog");
assert_eq!(wit, "wasi:http/proxy");
assert_eq!(endpoint, Some("/products/:id"));
assert_eq!(subject, None);
assert_eq!(slot, None);
let c2 = c.clone();
assert_eq!(c.identity(), c2.identity());
let mut mutated = c.clone();
mutated.de = "search".into();
assert_ne!(c.identity(), mutated.identity(), "de axis must partition");
let mut mutated = c.clone();
mutated.para = "warehouse".into();
assert_ne!(c.identity(), mutated.identity(), "para axis must partition");
let mut mutated = c.clone();
mutated.wit = "http:legacy".into();
assert_ne!(c.identity(), mutated.identity(), "wit axis must partition");
let mut mutated = c.clone();
mutated.endpoint = Some("/search".into());
assert_ne!(
c.identity(),
mutated.identity(),
"endpoint axis must partition"
);
let mut mutated = c.clone();
mutated.subject = Some("orders.paid".into());
assert_ne!(
c.identity(),
mutated.identity(),
"subject axis must partition"
);
let mut mutated = c;
mutated.slot = Some("carts/{id}".into());
assert_ne!(mutated.identity().5, None, "slot axis must partition");
}
#[test]
fn wit_contract_is_self_loop_returns_true_on_matching_endpoints_across_permutations() {
for (nome, wit, endpoint, subject, slot) in [
("cart", "wasi:http/proxy", Some("/lookup"), None, None),
("checkout", "nats:pub-sub", None, Some("orders.paid"), None),
(
"kv",
"wasi:keyvalue/store",
None,
None,
Some("carts/{cart_id}"),
),
("audit", "wasi:logging", None, None, None),
] {
let c = WitContract {
de: nome.into(),
para: nome.into(),
wit: wit.into(),
endpoint: endpoint.map(str::to_string),
subject: subject.map(str::to_string),
slot: slot.map(str::to_string),
};
assert!(
c.is_self_loop(),
"WitContract::is_self_loop must return true when \
:contratos :de == :contratos :para (got false on \
{nome:?} under {wit:?})",
);
}
}
#[test]
fn wit_contract_is_self_loop_returns_false_on_distinct_endpoints_across_permutations() {
for (de, para, wit, endpoint, subject, slot) in [
(
"cart",
"catalog",
"wasi:http/proxy",
Some("/lookup"),
None,
None,
),
(
"checkout",
"orders",
"nats:pub-sub",
None,
Some("orders.paid"),
None,
),
(
"cart",
"kv",
"wasi:keyvalue/store",
None,
None,
Some("carts/{cart_id}"),
),
("audit", "sink", "wasi:logging", None, None, None),
] {
let c = WitContract {
de: de.into(),
para: para.into(),
wit: wit.into(),
endpoint: endpoint.map(str::to_string),
subject: subject.map(str::to_string),
slot: slot.map(str::to_string),
};
assert!(
!c.is_self_loop(),
"WitContract::is_self_loop must return false when \
:contratos :de differs from :contratos :para (got true \
on {de:?} → {para:?} under {wit:?})",
);
}
}
#[test]
fn wit_contract_is_self_loop_routes_through_source_destination_accessors() {
let self_edge = WitContract {
de: "cart".into(),
para: "cart".into(),
wit: "wasi:http/proxy".into(),
endpoint: Some("/lookup".into()),
subject: None,
slot: None,
};
assert_eq!(
self_edge.is_self_loop(),
self_edge.source() == self_edge.destination(),
"WitContract::is_self_loop must compose exactly \
`source() == destination()` — a bypass of either sibling \
accessor here would silently decouple the endpoint-\
equality predicate from the substrate-primitive scalar \
accessors every downstream consumer routes through",
);
let inter_edge = WitContract {
de: "cart".into(),
para: "catalog".into(),
wit: "wasi:http/proxy".into(),
endpoint: Some("/lookup".into()),
subject: None,
slot: None,
};
assert_eq!(
inter_edge.is_self_loop(),
inter_edge.source() == inter_edge.destination(),
"WitContract::is_self_loop must compose exactly \
`source() == destination()` on the complement arm too",
);
}
#[test]
fn wit_contract_endpoint_returns_endpoint_option_byte_equal_across_permutations() {
for endpoint in ["/lookup", "/api/v1/orders", "/products/:id", "/health/live"] {
let c = WitContract {
de: "cart".into(),
para: "catalog".into(),
wit: "wasi:http/proxy".into(),
endpoint: Some(endpoint.into()),
subject: None,
slot: None,
};
assert_eq!(
c.endpoint(),
Some(endpoint),
"WitContract::endpoint must return :contratos :endpoint \
verbatim (got {:?}, expected Some({endpoint:?}))",
c.endpoint(),
);
assert_eq!(
c.endpoint(),
c.endpoint.as_deref(),
"WitContract::endpoint must byte-equal the .endpoint \
field's `.as_deref()` projection",
);
}
}
#[test]
fn wit_contract_endpoint_none_when_field_is_none() {
for (wit, subject, slot) in [
("nats:pub-sub", Some("orders.paid"), None),
("wasi:keyvalue/store", None, Some("carts/{cart_id}")),
("wasi:cli/environment", None, None),
] {
let c = WitContract {
de: "cart".into(),
para: "downstream".into(),
wit: wit.into(),
endpoint: None,
subject: subject.map(str::to_string),
slot: slot.map(str::to_string),
};
assert!(
c.endpoint().is_none(),
"WitContract::endpoint must return None when the typed \
slot is absent under :wit {wit:?} (got {:?})",
c.endpoint(),
);
assert_eq!(
c.endpoint(),
c.endpoint.as_deref(),
"WitContract::endpoint must byte-equal the .endpoint \
field's `.as_deref()` projection in the absent arm",
);
}
}
#[test]
fn wit_contract_endpoint_borrows_from_endpoint_storage() {
let c = WitContract {
de: "cart".into(),
para: "catalog".into(),
wit: "wasi:http/proxy".into(),
endpoint: Some("/lookup".into()),
subject: None,
slot: None,
};
let ep = c.endpoint().expect("Some arm");
let storage_slice = c.endpoint.as_deref().expect("Some arm — storage side");
assert_eq!(
ep.as_ptr(),
storage_slice.as_ptr(),
"WitContract::endpoint must borrow from the .endpoint \
String's backing storage — a fresh allocation here means \
the accessor no longer names the substrate-primitive typed \
dispatch and every downstream consumer would silently \
carry a detached copy",
);
assert_eq!(
ep.len(),
storage_slice.len(),
"WitContract::endpoint and .endpoint.as_deref() must byte-\
equal in length as well as in address",
);
}
#[test]
fn wit_contract_subject_returns_subject_option_byte_equal_across_permutations() {
for subject in ["events", "orders.paid", "tenant-a.orders", "orders.>"] {
let c = WitContract {
de: "cart".into(),
para: "notifier".into(),
wit: "nats:pub-sub".into(),
endpoint: None,
subject: Some(subject.into()),
slot: None,
};
assert_eq!(
c.subject(),
Some(subject),
"WitContract::subject must return :contratos :subject \
verbatim (got {:?}, expected Some({subject:?}))",
c.subject(),
);
assert_eq!(
c.subject(),
c.subject.as_deref(),
"WitContract::subject must byte-equal the .subject \
field's `.as_deref()` projection",
);
}
}
#[test]
fn wit_contract_subject_none_when_field_is_none() {
for (wit, endpoint, slot) in [
("wasi:http/proxy", Some("/lookup"), None),
("wasi:keyvalue/store", None, Some("carts/{cart_id}")),
("wasi:cli/environment", None, None),
] {
let c = WitContract {
de: "cart".into(),
para: "downstream".into(),
wit: wit.into(),
endpoint: endpoint.map(str::to_string),
subject: None,
slot: slot.map(str::to_string),
};
assert!(
c.subject().is_none(),
"WitContract::subject must return None when the typed \
slot is absent under :wit {wit:?} (got {:?})",
c.subject(),
);
assert_eq!(
c.subject(),
c.subject.as_deref(),
"WitContract::subject must byte-equal the .subject \
field's `.as_deref()` projection in the absent arm",
);
}
}
#[test]
fn wit_contract_subject_borrows_from_subject_storage() {
let c = WitContract {
de: "cart".into(),
para: "notifier".into(),
wit: "nats:pub-sub".into(),
endpoint: None,
subject: Some("orders.paid".into()),
slot: None,
};
let sub = c.subject().expect("Some arm");
let storage_slice = c.subject.as_deref().expect("Some arm — storage side");
assert_eq!(
sub.as_ptr(),
storage_slice.as_ptr(),
"WitContract::subject must borrow from the .subject \
String's backing storage — a fresh allocation here means \
the accessor no longer names the substrate-primitive typed \
dispatch and every downstream consumer would silently \
carry a detached copy",
);
assert_eq!(
sub.len(),
storage_slice.len(),
"WitContract::subject and .subject.as_deref() must byte-\
equal in length as well as in address",
);
}
#[test]
fn wit_contract_slot_returns_slot_option_byte_equal_across_permutations() {
for slot in [
"sessions",
"carts/{cart_id}",
"orders/{tenant}/{order_id}",
"cache/tenant-a/orders/{id}",
] {
let c = WitContract {
de: "cart".into(),
para: "kv".into(),
wit: "wasi:keyvalue/store".into(),
endpoint: None,
subject: None,
slot: Some(slot.into()),
};
assert_eq!(
c.slot(),
Some(slot),
"WitContract::slot must return :contratos :slot \
verbatim (got {:?}, expected Some({slot:?}))",
c.slot(),
);
assert_eq!(
c.slot(),
c.slot.as_deref(),
"WitContract::slot must byte-equal the .slot field's \
`.as_deref()` projection",
);
}
}
#[test]
fn wit_contract_slot_none_when_field_is_none() {
for (wit, endpoint, subject) in [
("wasi:http/proxy", Some("/lookup"), None),
("nats:pub-sub", None, Some("orders.paid")),
("wasi:cli/environment", None, None),
] {
let c = WitContract {
de: "cart".into(),
para: "downstream".into(),
wit: wit.into(),
endpoint: endpoint.map(str::to_string),
subject: subject.map(str::to_string),
slot: None,
};
assert!(
c.slot().is_none(),
"WitContract::slot must return None when the typed \
slot is absent under :wit {wit:?} (got {:?})",
c.slot(),
);
assert_eq!(
c.slot(),
c.slot.as_deref(),
"WitContract::slot must byte-equal the .slot field's \
`.as_deref()` projection in the absent arm",
);
}
}
#[test]
fn wit_contract_slot_borrows_from_slot_storage() {
let c = WitContract {
de: "cart".into(),
para: "kv".into(),
wit: "wasi:keyvalue/store".into(),
endpoint: None,
subject: None,
slot: Some("carts/{cart_id}".into()),
};
let slot = c.slot().expect("Some arm");
let storage_slice = c.slot.as_deref().expect("Some arm — storage side");
assert_eq!(
slot.as_ptr(),
storage_slice.as_ptr(),
"WitContract::slot must borrow from the .slot String's \
backing storage — a fresh allocation here means the \
accessor no longer names the substrate-primitive typed \
dispatch and every downstream consumer would silently \
carry a detached copy",
);
assert_eq!(
slot.len(),
storage_slice.len(),
"WitContract::slot and .slot.as_deref() must byte-equal \
in length as well as in address",
);
}
#[test]
fn membro_nome_returns_caixa_byte_equal_across_permutations() {
for name in ["cart", "checkout", "catalog", "orders-v2"] {
let m = Membro {
caixa: name.into(),
versao: "^0.1".into(),
};
assert_eq!(
m.nome(),
name,
"Membro::nome must return :membros :caixa verbatim \
(got {:?}, expected {name:?})",
m.nome(),
);
assert_eq!(
m.nome(),
m.caixa.as_str(),
"Membro::nome must byte-equal the .caixa field access",
);
}
}
#[test]
fn membro_nome_borrows_from_caixa_storage() {
let m = Membro {
caixa: "checkout".into(),
versao: "^0.1".into(),
};
let name = m.nome();
let caixa_slice = m.caixa.as_str();
assert_eq!(
name.as_ptr(),
caixa_slice.as_ptr(),
"Membro::nome must borrow from the .caixa String's backing \
storage — a fresh allocation here means the accessor no \
longer names the substrate-primitive typed dispatch and \
every downstream consumer would silently carry a detached \
copy",
);
assert_eq!(
name.len(),
caixa_slice.len(),
"Membro::nome and .caixa.as_str() must byte-equal in length \
as well as in address",
);
}
#[test]
fn membro_versao_requirement_returns_versao_byte_equal_across_permutations() {
for req in ["^0.1", "~0.1.2", "0.1.0", "*", "^1"] {
let m = Membro {
caixa: "cart".into(),
versao: req.into(),
};
assert_eq!(
m.versao_requirement(),
req,
"Membro::versao_requirement must return :membros :versao \
verbatim (got {:?}, expected {req:?})",
m.versao_requirement(),
);
assert_eq!(
m.versao_requirement(),
m.versao.as_str(),
"Membro::versao_requirement must byte-equal the .versao \
field access",
);
}
}
#[test]
fn membro_versao_requirement_borrows_from_versao_storage() {
let m = Membro {
caixa: "checkout".into(),
versao: "^0.1".into(),
};
let req = m.versao_requirement();
let versao_slice = m.versao.as_str();
assert_eq!(
req.as_ptr(),
versao_slice.as_ptr(),
"Membro::versao_requirement must borrow from the .versao \
String's backing storage — a fresh allocation here means \
the accessor no longer names the substrate-primitive typed \
dispatch and every downstream consumer would silently carry \
a detached copy",
);
assert_eq!(
req.len(),
versao_slice.len(),
"Membro::versao_requirement and .versao.as_str() must byte-\
equal in length as well as in address",
);
}
#[test]
fn membro_nome_and_versao_requirement_project_caixa_and_versao_pair() {
for (caixa, versao) in [
("cart", "^0.1"),
("checkout", "~0.1.2"),
("catalog", "0.1.0"),
("orders-v2", "*"),
] {
let m = Membro {
caixa: caixa.into(),
versao: versao.into(),
};
assert_eq!(
(m.nome(), m.versao_requirement()),
(m.caixa.as_str(), m.versao.as_str()),
"(Membro::nome, Membro::versao_requirement) must project \
(.caixa, .versao) verbatim across every author-declared \
pair (got ({:?}, {:?}), expected ({caixa:?}, {versao:?}))",
m.nome(),
m.versao_requirement(),
);
}
}
#[test]
fn validate_membros_empty_gate_routes_through_nome_accessor() {
let mut s = three_member_spec();
s.membros[1].caixa = String::new();
assert!(
s.membros[1].nome().is_empty(),
"Membro::nome must byte-equal the .caixa field access — an \
accessor-side detour that no longer projects the raw field \
would silently split this drift-detection test from the \
validate() refusal arm",
);
assert_eq!(
s.membros[1].nome(),
s.membros[1].caixa.as_str(),
"Membro::nome and .caixa.as_str() must byte-equal on an \
empty-`:caixa` entry — the emptiness gate keys off the \
accessor by construction",
);
assert_eq!(
s.validate().unwrap_err(),
AplicacaoError::MembroCaixaEmpty,
"validate_membros' emptiness gate must fire MembroCaixaEmpty \
on an entry whose accessor-projected `nome()` is empty",
);
}
#[test]
fn placement_shard_key_returns_shard_key_option_byte_equal_across_permutations() {
for key in ["tenantId", "$tenantId", "metadata.tenantId", "${tenant}"] {
let p = Placement {
estrategia: PlacementStrategy::Sharded,
clusters: vec!["rio".into()],
affinity: None,
shard_key: Some(key.into()),
};
assert_eq!(
p.shard_key(),
Some(key),
"Placement::shard_key must return :placement :shard-key \
verbatim (got {:?}, expected Some({key:?}))",
p.shard_key(),
);
assert_eq!(
p.shard_key(),
p.shard_key.as_deref(),
"Placement::shard_key must byte-equal the .shard_key \
field's `.as_deref()` projection",
);
}
}
#[test]
fn placement_shard_key_none_when_field_is_none() {
for estrategia in [PlacementStrategy::Replicated, PlacementStrategy::SingleNode] {
let p = Placement {
estrategia,
clusters: vec!["rio".into()],
affinity: None,
shard_key: None,
};
assert!(
p.shard_key().is_none(),
"Placement::shard_key must return None when the typed \
slot is absent under :estrategia {estrategia:?} (got {:?})",
p.shard_key(),
);
assert_eq!(
p.shard_key(),
p.shard_key.as_deref(),
"Placement::shard_key must byte-equal the .shard_key \
field's `.as_deref()` projection in the absent arm",
);
}
}
#[test]
fn placement_shard_key_borrows_from_shard_key_storage() {
let p = Placement {
estrategia: PlacementStrategy::Sharded,
clusters: vec!["rio".into()],
affinity: None,
shard_key: Some("tenantId".into()),
};
let key = p.shard_key().expect("Some arm");
let storage_slice = p.shard_key.as_deref().expect("Some arm — storage side");
assert_eq!(
key.as_ptr(),
storage_slice.as_ptr(),
"Placement::shard_key must borrow from the .shard_key \
String's backing storage — a fresh allocation here means \
the accessor no longer names the substrate-primitive typed \
dispatch and every downstream consumer would silently \
carry a detached copy",
);
assert_eq!(
key.len(),
storage_slice.len(),
"Placement::shard_key and .shard_key.as_deref() must byte-\
equal in length as well as in address",
);
}
#[test]
fn placement_affinity_returns_affinity_option_byte_equal_across_permutations() {
for hint in [
"data-locality",
"low-latency",
"high-throughput",
"cost-optimized",
] {
let p = Placement {
estrategia: PlacementStrategy::Replicated,
clusters: vec!["rio".into()],
affinity: Some(hint.into()),
shard_key: None,
};
assert_eq!(
p.affinity(),
Some(hint),
"Placement::affinity must return :placement :affinity \
verbatim (got {:?}, expected Some({hint:?}))",
p.affinity(),
);
assert_eq!(
p.affinity(),
p.affinity.as_deref(),
"Placement::affinity must byte-equal the .affinity \
field's `.as_deref()` projection",
);
}
}
#[test]
fn placement_affinity_none_when_field_is_none() {
for (estrategia, shard_key) in [
(PlacementStrategy::SingleNode, None),
(PlacementStrategy::Replicated, None),
(PlacementStrategy::Sharded, Some("tenantId".to_string())),
] {
let p = Placement {
estrategia,
clusters: vec!["rio".into()],
affinity: None,
shard_key,
};
assert!(
p.affinity().is_none(),
"Placement::affinity must return None when the typed \
slot is absent under :estrategia {estrategia:?} (got {:?})",
p.affinity(),
);
assert_eq!(
p.affinity(),
p.affinity.as_deref(),
"Placement::affinity must byte-equal the .affinity \
field's `.as_deref()` projection in the absent arm",
);
}
}
#[test]
fn placement_affinity_borrows_from_affinity_storage() {
let p = Placement {
estrategia: PlacementStrategy::Replicated,
clusters: vec!["rio".into()],
affinity: Some("data-locality".into()),
shard_key: None,
};
let hint = p.affinity().expect("Some arm");
let storage_slice = p.affinity.as_deref().expect("Some arm — storage side");
assert_eq!(
hint.as_ptr(),
storage_slice.as_ptr(),
"Placement::affinity must borrow from the .affinity \
String's backing storage — a fresh allocation here means \
the accessor no longer names the substrate-primitive typed \
dispatch and every downstream consumer would silently \
carry a detached copy",
);
assert_eq!(
hint.len(),
storage_slice.len(),
"Placement::affinity and .affinity.as_deref() must byte-\
equal in length as well as in address",
);
}
#[test]
fn placement_estrategia_returns_estrategia_verbatim_across_permutations() {
for estrategia in [
PlacementStrategy::SingleNode,
PlacementStrategy::Replicated,
PlacementStrategy::Sharded,
] {
let shard_key = estrategia.is_sharded().then(|| "tenantId".to_string());
let p = Placement {
estrategia,
clusters: vec!["rio".into()],
affinity: None,
shard_key,
};
assert_eq!(
p.estrategia(),
estrategia,
"Placement::estrategia must return :placement :estrategia \
verbatim (got {:?}, expected {estrategia:?})",
p.estrategia(),
);
assert_eq!(
p.estrategia(),
p.estrategia,
"Placement::estrategia accessor and .estrategia field \
access must byte-equal — the accessor is the substrate-\
primitive typed dispatch every downstream distribution-\
strategy consumer must route through",
);
}
}
#[test]
fn validate_placement_reads_through_lifted_estrategia_accessor() {
for estrategia in [
PlacementStrategy::SingleNode,
PlacementStrategy::Replicated,
PlacementStrategy::Sharded,
] {
let mut spec = three_member_spec();
spec.placement.estrategia = estrategia;
spec.placement.clusters = Vec::new();
spec.placement.shard_key = estrategia.is_sharded().then(|| "tenantId".to_string());
let err = spec.validate().unwrap_err();
match err {
AplicacaoError::PlacementWithoutClusters { estrategia: e } => {
assert_eq!(
e,
spec.placement.estrategia(),
"PlacementWithoutClusters.estrategia must byte-equal \
Placement::estrategia() — the error carrier reads \
through the lifted accessor",
);
}
other => panic!(
"expected PlacementWithoutClusters, got {other:?} for \
estrategia={estrategia:?}"
),
}
}
for estrategia in [PlacementStrategy::SingleNode, PlacementStrategy::Replicated] {
let mut spec = three_member_spec();
spec.placement.estrategia = estrategia;
spec.placement.shard_key = Some("tenantId".into());
let err = spec.validate().unwrap_err();
match err {
AplicacaoError::ShardKeyOnNonSharded { estrategia: e, .. } => {
assert_eq!(
e,
spec.placement.estrategia(),
"ShardKeyOnNonSharded.estrategia must byte-equal \
Placement::estrategia() — the non-Sharded-arm \
refusal reads through the lifted accessor",
);
}
other => panic!(
"expected ShardKeyOnNonSharded, got {other:?} for \
estrategia={estrategia:?}"
),
}
}
}
#[test]
fn placement_clusters_returns_clusters_slice_byte_equal_across_permutations() {
let fixtures: Vec<Vec<String>> = vec![
Vec::new(),
vec!["rio".into()],
vec!["rio".into(), "mar".into()],
vec!["rio".into(), "mar".into(), "plo".into()],
];
for clusters in fixtures {
let p = Placement {
clusters: clusters.clone(),
..Placement::default()
};
assert_eq!(
p.clusters(),
clusters.as_slice(),
"Placement::clusters must return :placement :clusters \
verbatim (got {:?}, expected {:?})",
p.clusters(),
clusters.as_slice(),
);
assert_eq!(
p.clusters(),
p.clusters.as_slice(),
"Placement::clusters accessor and .clusters.as_slice() \
field access must byte-equal — the accessor is the \
substrate-primitive typed dispatch every downstream \
cluster-pool consumer must route through",
);
assert_eq!(
p.clusters().len(),
p.clusters.len(),
"Placement::clusters().len() must byte-equal \
self.clusters.len() — a length-drift would silently \
split the paired pre-flight `.is_empty()` refusal \
probe input from the per-cluster validate loop's \
traversal input",
);
}
}
#[test]
fn validate_placement_reads_through_lifted_clusters_accessor() {
let mut spec = three_member_spec();
spec.placement.clusters = Vec::new();
match spec.validate().unwrap_err() {
AplicacaoError::PlacementWithoutClusters { .. } => {}
other => panic!("expected PlacementWithoutClusters, got {other:?}"),
}
assert!(
spec.placement.clusters().is_empty(),
"the pre-flight refusal input must be the empty slice per \
the accessor's projection",
);
let mut spec = three_member_spec();
spec.placement.clusters = vec!["rio".into(), "BAD_CLUSTER".into()];
match spec.validate().unwrap_err() {
AplicacaoError::PlacementClusterInvalid { cluster, .. } => {
assert_eq!(
cluster, "BAD_CLUSTER",
"PlacementClusterInvalid.cluster must carry the \
tail entry the loop reached through the accessor",
);
}
other => panic!("expected PlacementClusterInvalid, got {other:?}"),
}
assert_eq!(
spec.placement.clusters().len(),
2,
"the per-cluster validate loop's traversal input must be \
a two-element slice per the accessor's projection",
);
let mut spec = three_member_spec();
spec.placement.clusters = vec!["rio".into(), "rio".into()];
match spec.validate().unwrap_err() {
AplicacaoError::PlacementClusterDuplicate { cluster } => {
assert_eq!(
cluster, "rio",
"PlacementClusterDuplicate.cluster must carry the \
shared cluster name verbatim",
);
}
other => panic!("expected PlacementClusterDuplicate, got {other:?}"),
}
assert_eq!(
spec.placement.clusters().len(),
2,
"the per-cluster validate loop's traversal input must be \
a two-element slice per the accessor's projection",
);
}
#[test]
fn aplicacao_spec_membros_returns_membros_slice_byte_equal_across_permutations() {
let fixtures: Vec<Vec<Membro>> = vec![
Vec::new(),
vec![membro("catalog", "^0.1")],
vec![membro("catalog", "^0.1"), membro("cart", "^0.1")],
vec![
membro("catalog", "^0.1"),
membro("cart", "^0.1"),
membro("payment", "^0.2"),
],
];
for membros in fixtures {
let s = AplicacaoSpec {
membros: membros.clone(),
contratos: Vec::new(),
politicas: MeshPolicy::default(),
placement: Placement::default(),
entrada: None,
};
assert_eq!(
s.membros(),
membros.as_slice(),
"AplicacaoSpec::membros must return :membros verbatim \
(got {:?}, expected {:?})",
s.membros(),
membros.as_slice(),
);
assert_eq!(
s.membros(),
s.membros.as_slice(),
"AplicacaoSpec::membros accessor and .membros.as_slice() \
field access must byte-equal — the accessor is the \
substrate-primitive typed dispatch every downstream \
member-list consumer must route through",
);
assert_eq!(
s.membros().len(),
s.membros.len(),
"AplicacaoSpec::membros().len() must byte-equal \
self.membros.len() — a length-drift would silently \
split the paired `HashSet<&str>` name-set seed's \
collect input from the pre-flight `.is_empty()` \
refusal probe input from the per-member validate \
loop's traversal input",
);
}
}
#[test]
fn validate_reads_through_lifted_membros_accessor() {
let mut spec = three_member_spec();
spec.membros = Vec::new();
assert_eq!(spec.validate().unwrap_err(), AplicacaoError::NoMembros);
assert!(
spec.membros().is_empty(),
"the pre-flight refusal input must be the empty slice per \
the accessor's projection",
);
let mut spec = three_member_spec();
spec.membros = vec![membro("catalog", "^0.1"), membro("", "^0.1")];
assert_eq!(
spec.validate().unwrap_err(),
AplicacaoError::MembroCaixaEmpty,
);
assert_eq!(
spec.membros().len(),
2,
"the per-member validate loop's traversal input must be \
a two-element slice per the accessor's projection",
);
let mut spec = three_member_spec();
spec.membros = vec![membro("catalog", "^0.1"), membro("catalog", "^0.2")];
match spec.validate().unwrap_err() {
AplicacaoError::MembroDuplicate { caixa } => {
assert_eq!(
caixa, "catalog",
"MembroDuplicate.caixa must carry the shared \
member name verbatim",
);
}
other => panic!("expected MembroDuplicate, got {other:?}"),
}
assert_eq!(
spec.membros().len(),
2,
"the per-member validate loop's traversal input must be \
a two-element slice per the accessor's projection",
);
}
#[test]
fn aplicacao_spec_contratos_returns_contratos_slice_byte_equal_across_permutations() {
let fixtures: Vec<Vec<WitContract>> = vec![
Vec::new(),
vec![contract_http("cart", "catalog", "/products/:id")],
vec![
contract_http("cart", "catalog", "/products/:id"),
contract_http("cart", "payment", "/charge"),
],
vec![
contract_http("cart", "catalog", "/products/:id"),
contract_http("cart", "payment", "/charge"),
contract_http("payment", "catalog", "/audit"),
],
];
for contratos in fixtures {
let s = AplicacaoSpec {
membros: vec![
membro("catalog", "^0.1"),
membro("cart", "^0.1"),
membro("payment", "^0.2"),
],
contratos: contratos.clone(),
politicas: MeshPolicy::default(),
placement: Placement::default(),
entrada: None,
};
assert_eq!(
s.contratos(),
contratos.as_slice(),
"AplicacaoSpec::contratos must return :contratos verbatim \
(got {:?}, expected {:?})",
s.contratos(),
contratos.as_slice(),
);
assert_eq!(
s.contratos(),
s.contratos.as_slice(),
"AplicacaoSpec::contratos accessor and \
.contratos.as_slice() field access must byte-equal — \
the accessor is the substrate-primitive typed dispatch \
every downstream contract-list consumer must route \
through",
);
assert_eq!(
s.contratos().len(),
s.contratos.len(),
"AplicacaoSpec::contratos().len() must byte-equal \
self.contratos.len() — a length-drift would silently \
split the paired per-edge validate-loop's traversal \
input from the sync-cycle adjacency-list seed's \
traversal input from the cilium_network_policies \
per-`(:de, :para)` BTreeMap grouping loop's traversal \
input from the `feira app graph` per-contract print \
traversal's input",
);
}
}
#[test]
fn validate_reads_through_lifted_contratos_accessor() {
let mut spec = three_member_spec();
spec.contratos = Vec::new();
assert!(
spec.validate().is_ok(),
"empty :contratos must validate — the per-edge loop is a \
no-op under the accessor's empty projection",
);
assert!(
spec.contratos().is_empty(),
"the per-edge validate loop's traversal input must be the \
empty slice per the accessor's projection",
);
let mut spec = three_member_spec();
spec.contratos = vec![
contract_http("cart", "catalog", "/products/:id"),
contract_http("cart", "phantom", "/x"),
];
let err = spec.validate().unwrap_err();
assert!(
matches!(
err,
AplicacaoError::ContratoMemberMissing { ref caixa }
if caixa == "phantom"
),
"expected ContratoMemberMissing{{caixa:\"phantom\"}}, got {err:?}",
);
assert_eq!(
spec.contratos().len(),
2,
"the per-edge validate loop's traversal input must be \
a two-element slice per the accessor's projection",
);
let mut spec = three_member_spec();
spec.contratos = vec![
contract_http("cart", "catalog", "/products/:id"),
contract_http("catalog", "cart", "/callback"),
];
let err = spec.validate().unwrap_err();
assert!(
matches!(err, AplicacaoError::ContratoCycle { .. }),
"expected ContratoCycle from the sync-cycle detector on a \
two-edge back-edge cohort, got {err:?}",
);
assert_eq!(
spec.contratos().len(),
2,
"the sync-cycle detector's traversal input must be a \
two-element slice per the accessor's projection",
);
}
#[test]
fn aplicacao_spec_politicas_returns_politicas_ref_byte_equal_across_permutations() {
let fixtures: Vec<MeshPolicy> = vec![
MeshPolicy::default(),
MeshPolicy {
mtls_required: Some(true),
..MeshPolicy::default()
},
MeshPolicy {
mtls_required: Some(false),
..MeshPolicy::default()
},
MeshPolicy {
timeout: Some(Duration::from_secs(30)),
..MeshPolicy::default()
},
MeshPolicy {
retries: Some(3),
..MeshPolicy::default()
},
MeshPolicy {
circuit_breaker: Some(CircuitBreaker {
max_failures: 5,
window: Duration::from_secs(30),
}),
..MeshPolicy::default()
},
MeshPolicy {
rate_limit: Some(RateLimit {
rate: 100,
window: Duration::from_secs(1),
}),
..MeshPolicy::default()
},
MeshPolicy {
timeout: Some(Duration::from_secs(30)),
retries: Some(3),
mtls_required: Some(true),
..MeshPolicy::default()
},
];
for politicas in fixtures {
let s = AplicacaoSpec {
membros: vec![membro("catalog", "^0.1"), membro("cart", "^0.1")],
contratos: Vec::new(),
politicas: politicas.clone(),
placement: Placement::default(),
entrada: None,
};
assert_eq!(
*s.politicas(),
politicas,
"AplicacaoSpec::politicas must return :politicas verbatim \
(got {:?}, expected {:?})",
s.politicas(),
politicas,
);
assert!(
std::ptr::eq(s.politicas(), &s.politicas),
"AplicacaoSpec::politicas accessor and &self.politicas \
field access must borrow the same backing storage — \
the accessor is the substrate-primitive typed dispatch \
every downstream mesh-policy composite consumer must \
route through, and a reference-identity split would \
silently break every consumer that relied on the \
borrow sharing the composite's storage",
);
assert_eq!(
s.politicas().is_empty(),
s.politicas.is_empty(),
"AplicacaoSpec::politicas().is_empty() must byte-equal \
self.politicas.is_empty() — an emptiness-drift would \
silently split the paired `validate_politicas` \
per-axis bracket-dispatch's seed from the peer \
caixa-mesh CNP mTLS-overlay emitter's key from the \
peer caixa-mesh HTTPRoute timeout+retry overlay \
emitter's key",
);
}
}
#[test]
fn validate_politicas_reads_through_lifted_politicas_accessor() {
let mut spec = three_member_spec();
spec.politicas.timeout = Some(Duration::ZERO);
spec.politicas.retries = None;
spec.politicas.circuit_breaker = None;
spec.politicas.rate_limit = None;
assert_eq!(
spec.validate().unwrap_err(),
AplicacaoError::PolicyTimeoutZero,
);
assert!(
std::ptr::eq(spec.politicas(), &spec.politicas),
"the `validate_politicas` per-axis bracket-dispatch's \
traversal input must be the same backing composite the \
accessor's reference projection borrows from",
);
let mut spec = three_member_spec();
spec.politicas.timeout = None;
spec.politicas.retries = Some(0);
spec.politicas.circuit_breaker = None;
spec.politicas.rate_limit = None;
assert_eq!(
spec.validate().unwrap_err(),
AplicacaoError::PolicyRetriesZero,
);
let mut spec = three_member_spec();
spec.politicas = MeshPolicy::default();
assert!(
spec.validate().is_ok(),
"an empty `MeshPolicy` must pass `validate_politicas` — \
every per-axis arm short-circuits on `None` under the \
outer accessor's reference projection",
);
assert!(
spec.politicas().is_empty(),
"the outer accessor's reference projection must be the \
empty composite per the `MeshPolicy::default()` fixture",
);
}
#[test]
#[allow(clippy::too_many_lines)]
fn validate_politicas_timeout_and_retries_arms_route_through_lifted_axis_accessors() {
for timeout in [
None,
Some(Duration::ZERO),
Some(Duration::from_millis(1)),
Some(POLICY_TIMEOUT_MAX),
] {
let p = MeshPolicy {
timeout,
..MeshPolicy::default()
};
assert_eq!(
p.timeout(),
p.timeout,
"MeshPolicy::timeout accessor must byte-equal the raw \
.timeout field across every accept-set boundary the \
validate_politicas :timeout arm carves out — a drift \
here would silently split the validate bracket's arm \
from the peer caixa-mesh HTTPRoute timeout-overlay \
emitter's read",
);
}
for retries in [
None,
Some(0u32),
Some(1u32),
Some(POLICY_RETRIES_MAX),
Some(POLICY_RETRIES_MAX + 1),
Some(u32::MAX),
] {
let p = MeshPolicy {
retries,
..MeshPolicy::default()
};
assert_eq!(
p.retries(),
p.retries,
"MeshPolicy::retries accessor must byte-equal the raw \
.retries field across every accept-set boundary the \
validate_politicas :retries arm carves out — a drift \
here would silently split the validate bracket's arm \
from the peer caixa-mesh HTTPRoute retry-overlay \
emitter's read",
);
}
let mut spec = three_member_spec();
spec.politicas.timeout = Some(Duration::ZERO);
spec.politicas.retries = None;
spec.politicas.circuit_breaker = None;
spec.politicas.rate_limit = None;
assert_eq!(
spec.politicas().timeout(),
Some(Duration::ZERO),
"the accessor projection must reflect the fixture's \
`Some(Duration::ZERO)` :timeout verbatim",
);
assert_eq!(
spec.validate().unwrap_err(),
AplicacaoError::PolicyTimeoutZero,
"the validate_politicas :timeout zero-floor arm must fire \
through the lifted accessor's projection — a silent \
detour to a peer-axis field would fail to refuse",
);
let mut spec = three_member_spec();
spec.politicas.timeout = None;
spec.politicas.retries = Some(0);
spec.politicas.circuit_breaker = None;
spec.politicas.rate_limit = None;
assert_eq!(
spec.politicas().retries(),
Some(0),
"the accessor projection must reflect the fixture's \
`Some(0)` :retries verbatim",
);
assert_eq!(
spec.validate().unwrap_err(),
AplicacaoError::PolicyRetriesZero,
"the validate_politicas :retries zero-floor arm must fire \
through the lifted accessor's projection — a silent \
detour to a peer-axis field would fail to refuse",
);
let mut spec = three_member_spec();
spec.politicas.timeout = Some(POLICY_TIMEOUT_MAX);
spec.politicas.retries = Some(POLICY_RETRIES_MAX);
spec.politicas.circuit_breaker = None;
spec.politicas.rate_limit = None;
assert_eq!(
spec.politicas().timeout(),
Some(POLICY_TIMEOUT_MAX),
"the accessor projection must reflect the fixture's \
at-cap :timeout verbatim",
);
assert_eq!(
spec.politicas().retries(),
Some(POLICY_RETRIES_MAX),
"the accessor projection must reflect the fixture's \
at-cap :retries verbatim",
);
assert!(
spec.validate().is_ok(),
"at-cap :timeout + :retries must pass validate under the \
accessor projection — the upper-boundary accept-arm on \
both axes routes through the lifted accessor",
);
}
#[test]
fn aplicacao_spec_placement_returns_placement_ref_byte_equal_across_permutations() {
let fixtures: Vec<Placement> = vec![
Placement::default(),
Placement {
estrategia: PlacementStrategy::SingleNode,
clusters: vec!["rio".into()],
affinity: None,
shard_key: None,
},
Placement {
estrategia: PlacementStrategy::Replicated,
clusters: vec!["rio".into(), "mar".into()],
affinity: None,
shard_key: None,
},
Placement {
estrategia: PlacementStrategy::Replicated,
clusters: vec!["rio".into(), "mar".into()],
affinity: Some("data-locality".into()),
shard_key: None,
},
Placement {
estrategia: PlacementStrategy::Sharded,
clusters: vec!["rio".into(), "mar".into()],
affinity: None,
shard_key: Some("tenantId".into()),
},
Placement {
estrategia: PlacementStrategy::Sharded,
clusters: vec!["rio".into(), "mar".into(), "sol".into()],
affinity: Some("low-latency".into()),
shard_key: Some("metadata.tenantId".into()),
},
];
for placement in fixtures {
let s = AplicacaoSpec {
membros: vec![membro("catalog", "^0.1"), membro("cart", "^0.1")],
contratos: Vec::new(),
politicas: MeshPolicy::default(),
placement: placement.clone(),
entrada: None,
};
assert_eq!(
*s.placement(),
placement,
"AplicacaoSpec::placement must return :placement verbatim \
(got {:?}, expected {:?})",
s.placement(),
placement,
);
assert!(
std::ptr::eq(s.placement(), &s.placement),
"AplicacaoSpec::placement accessor and &self.placement \
field access must borrow the same backing storage — the \
accessor is the substrate-primitive typed dispatch every \
downstream distribution-composite consumer must route \
through, and a reference-identity split would silently \
break every consumer that relied on the borrow sharing \
the composite's storage",
);
assert_eq!(
s.placement().estrategia(),
s.placement.estrategia,
"AplicacaoSpec::placement().estrategia() must byte-equal \
self.placement.estrategia — a strategy-drift would \
silently split the paired `validate_placement` \
`Sharded` ↔ non-`Sharded` partition scrutinee from the \
peer caixa-mesh programs.yaml `placement.estrategia` \
emitter's key from the peer `feira app graph` printer's \
strategy label",
);
assert_eq!(
s.placement().clusters(),
s.placement.clusters.as_slice(),
"AplicacaoSpec::placement().clusters() must byte-equal \
self.placement.clusters — a cluster-pool drift would \
silently split the paired `validate_placement` \
pre-flight `.is_empty()` refusal probe's traversal from \
the peer caixa-mesh programs.yaml `placement.clusters` \
emitter's fan-out from the peer `feira app graph` \
printer's cluster list",
);
}
}
#[test]
fn validate_placement_reads_through_lifted_placement_accessor() {
let mut spec = three_member_spec();
spec.placement.clusters = Vec::new();
assert_eq!(
spec.validate().unwrap_err(),
AplicacaoError::PlacementWithoutClusters {
estrategia: PlacementStrategy::Replicated,
},
);
assert!(
std::ptr::eq(spec.placement(), &spec.placement),
"the `validate_placement` per-axis bracket-dispatch's \
traversal input must be the same backing composite the \
accessor's reference projection borrows from",
);
let mut spec = three_member_spec();
spec.placement.estrategia = PlacementStrategy::Sharded;
spec.placement.shard_key = None;
assert_eq!(
spec.validate().unwrap_err(),
AplicacaoError::ShardedWithoutKey,
);
let mut spec = three_member_spec();
spec.placement.estrategia = PlacementStrategy::Replicated;
spec.placement.shard_key = Some("tenantId".into());
assert_eq!(
spec.validate().unwrap_err(),
AplicacaoError::ShardKeyOnNonSharded {
estrategia: PlacementStrategy::Replicated,
shard_key: "tenantId".into(),
},
);
let spec = three_member_spec();
assert!(
spec.validate().is_ok(),
"the canonical Replicated placement fixture must pass \
`validate_placement` — every per-axis arm short-circuits on \
valid input under the outer accessor's reference projection",
);
assert_eq!(
spec.placement().estrategia(),
PlacementStrategy::Replicated,
"the outer accessor's reference projection must be the \
canonical Replicated fixture's strategy",
);
assert_eq!(
spec.placement().clusters(),
&["rio", "mar"],
"the outer accessor's reference projection must be the \
canonical Replicated fixture's cluster pool",
);
}
#[test]
fn aplicacao_spec_entrada_returns_entrada_option_ref_byte_equal_across_permutations() {
let fixtures: Vec<Option<Entrada>> = vec![
None,
Some(Entrada {
host: "checkout.quero.cloud".into(),
para: "cart".into(),
paths: Vec::new(),
port: DEFAULT_SERVICO_PORT,
}),
Some(Entrada {
host: "checkout.quero.cloud".into(),
para: "cart".into(),
paths: vec!["/api".into(), "/health".into()],
port: DEFAULT_SERVICO_PORT,
}),
Some(Entrada {
host: "checkout.quero.cloud".into(),
para: "cart".into(),
paths: vec!["/api".into()],
port: 9443,
}),
];
for entrada in fixtures {
let s = AplicacaoSpec {
membros: vec![membro("catalog", "^0.1"), membro("cart", "^0.1")],
contratos: Vec::new(),
politicas: MeshPolicy::default(),
placement: Placement::default(),
entrada: entrada.clone(),
};
assert_eq!(
s.entrada(),
entrada.as_ref(),
"AplicacaoSpec::entrada must return :entrada verbatim \
(got {:?}, expected {:?})",
s.entrada(),
entrada.as_ref(),
);
match (s.entrada(), s.entrada.as_ref()) {
(Some(a), Some(b)) => assert!(
std::ptr::eq(a, b),
"AplicacaoSpec::entrada accessor and \
self.entrada.as_ref() field access must borrow \
the same backing storage — the accessor is the \
substrate-primitive typed dispatch every \
downstream external-gateway composite consumer \
must route through, and a reference-identity \
split would silently break every consumer that \
relied on the borrow sharing the composite's \
storage",
),
(None, None) => {}
_ => panic!(
"AplicacaoSpec::entrada presence bit must byte-\
equal self.entrada.is_some() — a presence-bit \
drift would silently split the paired `validate` \
per-`:entrada` shape-and-membership gate's \
traversal head from the peer \
caixa-mesh gateway_routes early-return partition \
from the peer `feira app graph` internal-only-\
mesh partition",
),
}
assert_eq!(
s.entrada().is_some(),
s.entrada.is_some(),
"AplicacaoSpec::entrada().is_some() must byte-equal \
self.entrada.is_some() — a presence-bit drift would \
silently split every downstream `Option<&Entrada>` \
consumer's partition on the internal-only-mesh arm",
);
}
}
#[test]
fn validate_reads_through_lifted_entrada_accessor() {
let mut spec = three_member_spec();
spec.entrada = None;
assert!(
spec.validate().is_ok(),
"an author-omitted `:entrada` must pass `validate` — the \
internal-only-mesh partition short-circuits past every \
per-`:entrada` refusal under the outer accessor's \
reference projection",
);
assert!(
spec.entrada().is_none(),
"the outer accessor's reference projection must name the \
internal-only-mesh partition per the `None` fixture",
);
let mut spec = three_member_spec();
if let Some(e) = spec.entrada.as_mut() {
e.para = "phantom".into();
}
assert_eq!(
spec.validate().unwrap_err(),
AplicacaoError::EntradaMemberMissing {
para: "phantom".into(),
},
);
match (spec.entrada(), spec.entrada.as_ref()) {
(Some(a), Some(b)) => assert!(
std::ptr::eq(a, b),
"the `validate` per-`:entrada` gate's traversal head \
must be the same backing composite the accessor's \
reference projection borrows from",
),
_ => panic!("fixture must carry Some(:entrada)"),
}
let spec = three_member_spec();
assert!(
spec.validate().is_ok(),
"the canonical `:entrada` fixture must pass `validate` — \
every per-axis arm short-circuits on valid input under \
the outer accessor's reference projection",
);
assert!(
spec.entrada().is_some(),
"the outer accessor's reference projection must be the \
canonical `:entrada` fixture's composite",
);
}
#[test]
fn port_for_destination_reads_through_lifted_entrada_accessor() {
let mut spec = three_member_spec();
spec.entrada = None;
assert_eq!(
spec.port_for_destination("cart"),
DEFAULT_SERVICO_PORT,
"the port-fallback resolver must fall through to \
DEFAULT_SERVICO_PORT on an author-omitted `:entrada` \
under the outer accessor's reference projection",
);
let mut spec = three_member_spec();
if let Some(e) = spec.entrada.as_mut() {
e.para = "cart".into();
e.port = 9443;
}
assert_eq!(
spec.port_for_destination("catalog"),
DEFAULT_SERVICO_PORT,
"the port-fallback resolver must fall through to \
DEFAULT_SERVICO_PORT on a non-matching destination \
under the outer accessor's reference projection",
);
let mut spec = three_member_spec();
if let Some(e) = spec.entrada.as_mut() {
e.para = "cart".into();
e.port = 9443;
}
assert_eq!(
spec.port_for_destination("cart"),
9443,
"the port-fallback resolver must return the \
`:entrada :port` value on a matching destination \
under the outer accessor's reference projection",
);
}
#[test]
fn mesh_policy_mtls_required_returns_mtls_required_option_byte_equal_across_permutations() {
for required in [None, Some(true), Some(false)] {
let p = MeshPolicy {
mtls_required: required,
..MeshPolicy::default()
};
assert_eq!(
p.mtls_required(),
required,
"MeshPolicy::mtls_required must return :politicas \
:mtls-required verbatim (got {:?}, expected {required:?})",
p.mtls_required(),
);
assert_eq!(
p.mtls_required(),
p.mtls_required,
"MeshPolicy::mtls_required must byte-equal the raw \
.mtls_required field access across every value in the \
three-way accept-set",
);
}
}
#[test]
fn mesh_policy_is_empty_mtls_required_arm_routes_through_accessor() {
let empty = MeshPolicy::default();
assert!(
empty.is_empty(),
"MeshPolicy::default() must be is_empty() — every axis \
defaults to None",
);
for required in [Some(true), Some(false)] {
let p = MeshPolicy {
mtls_required: required,
..MeshPolicy::default()
};
assert!(
!p.is_empty(),
"MeshPolicy::is_empty must return false when \
:mtls-required is {required:?} — the emptiness \
predicate reads \"any axis carries a value\", not \
\"any axis carries a truthy value\"",
);
assert_eq!(
p.mtls_required().is_none(),
p.is_empty(),
"when :mtls-required is the only set axis, \
is_empty() must equal mtls_required().is_none() — \
the accessor and the emptiness predicate must \
route through the same substrate-primitive typed \
dispatch on the :mtls-required arm",
);
}
}
#[test]
fn mesh_policy_mtls_required_projects_option_bool_by_copy() {
for required in [None, Some(true), Some(false)] {
let p = MeshPolicy {
mtls_required: required,
..MeshPolicy::default()
};
let first = p.mtls_required();
let second = p.mtls_required();
assert_eq!(
first, second,
"MeshPolicy::mtls_required must be idempotent — two \
successive calls on the same &self must return the \
same Option<bool>",
);
assert_eq!(
first, required,
"MeshPolicy::mtls_required must return :politicas \
:mtls-required verbatim by copy — got {first:?}, \
expected {required:?}",
);
}
}
#[test]
fn mesh_policy_retries_returns_retries_option_byte_equal_across_permutations() {
for retries in [None, Some(1u32), Some(POLICY_RETRIES_MAX), Some(u32::MAX)] {
let p = MeshPolicy {
retries,
..MeshPolicy::default()
};
assert_eq!(
p.retries(),
retries,
"MeshPolicy::retries must return :politicas :retries \
verbatim (got {:?}, expected {retries:?})",
p.retries(),
);
assert_eq!(
p.retries(),
p.retries,
"MeshPolicy::retries must byte-equal the raw .retries \
field access across every value in the accept-set",
);
}
}
#[test]
fn mesh_policy_is_empty_retries_arm_routes_through_accessor() {
let empty = MeshPolicy::default();
assert!(
empty.is_empty(),
"MeshPolicy::default() must be is_empty() — every axis \
defaults to None",
);
for retries in [Some(1u32), Some(POLICY_RETRIES_MAX)] {
let p = MeshPolicy {
retries,
..MeshPolicy::default()
};
assert!(
!p.is_empty(),
"MeshPolicy::is_empty must return false when \
:retries is {retries:?} — the emptiness \
predicate reads \"any axis carries a value\", not \
\"any axis carries a value the validate gate \
accepts\"",
);
assert_eq!(
p.retries().is_none(),
p.is_empty(),
"when :retries is the only set axis, is_empty() \
must equal retries().is_none() — the accessor and \
the emptiness predicate must route through the same \
substrate-primitive typed dispatch on the :retries \
arm",
);
}
}
#[test]
fn mesh_policy_retries_projects_option_u32_by_copy() {
for retries in [None, Some(1u32), Some(POLICY_RETRIES_MAX), Some(u32::MAX)] {
let p = MeshPolicy {
retries,
..MeshPolicy::default()
};
let first = p.retries();
let second = p.retries();
assert_eq!(
first, second,
"MeshPolicy::retries must be idempotent — two \
successive calls on the same &self must return the \
same Option<u32>",
);
assert_eq!(
first, retries,
"MeshPolicy::retries must return :politicas :retries \
verbatim by copy — got {first:?}, expected {retries:?}",
);
}
}
#[test]
fn mesh_policy_timeout_returns_timeout_option_byte_equal_across_permutations() {
for timeout in [
None,
Some(Duration::from_millis(1)),
Some(POLICY_TIMEOUT_MAX),
Some(Duration::ZERO),
Some(Duration::MAX),
] {
let p = MeshPolicy {
timeout,
..MeshPolicy::default()
};
assert_eq!(
p.timeout(),
timeout,
"MeshPolicy::timeout must return :politicas :timeout \
verbatim (got {:?}, expected {timeout:?})",
p.timeout(),
);
assert_eq!(
p.timeout(),
p.timeout,
"MeshPolicy::timeout must byte-equal the raw .timeout \
field access across every value in the accept-set",
);
}
}
#[test]
fn mesh_policy_is_empty_timeout_arm_routes_through_accessor() {
let empty = MeshPolicy::default();
assert!(
empty.is_empty(),
"MeshPolicy::default() must be is_empty() — every axis \
defaults to None",
);
for timeout in [Some(Duration::from_millis(1)), Some(POLICY_TIMEOUT_MAX)] {
let p = MeshPolicy {
timeout,
..MeshPolicy::default()
};
assert!(
!p.is_empty(),
"MeshPolicy::is_empty must return false when \
:timeout is {timeout:?} — the emptiness \
predicate reads \"any axis carries a value\", not \
\"any axis carries a value the validate gate \
accepts\"",
);
assert_eq!(
p.timeout().is_none(),
p.is_empty(),
"when :timeout is the only set axis, is_empty() \
must equal timeout().is_none() — the accessor and \
the emptiness predicate must route through the same \
substrate-primitive typed dispatch on the :timeout \
arm",
);
}
}
#[test]
fn mesh_policy_timeout_projects_option_duration_by_copy() {
for timeout in [
None,
Some(Duration::from_millis(1)),
Some(POLICY_TIMEOUT_MAX),
Some(Duration::ZERO),
Some(Duration::MAX),
] {
let p = MeshPolicy {
timeout,
..MeshPolicy::default()
};
let first = p.timeout();
let second = p.timeout();
assert_eq!(
first, second,
"MeshPolicy::timeout must be idempotent — two \
successive calls on the same &self must return the \
same Option<Duration>",
);
assert_eq!(
first, timeout,
"MeshPolicy::timeout must return :politicas :timeout \
verbatim by copy — got {first:?}, expected {timeout:?}",
);
}
}
#[test]
fn mesh_policy_rate_limit_returns_rate_limit_option_byte_equal_across_permutations() {
for rl in [
None,
Some(RateLimit {
rate: 1,
window: Duration::from_secs(1),
}),
Some(RateLimit {
rate: POLICY_RATE_LIMIT_MAX,
window: Duration::from_secs(3600),
}),
Some(RateLimit {
rate: 0,
window: Duration::ZERO,
}),
Some(RateLimit {
rate: u32::MAX,
window: Duration::MAX,
}),
] {
let p = MeshPolicy {
rate_limit: rl,
..MeshPolicy::default()
};
assert_eq!(
p.rate_limit(),
rl,
"MeshPolicy::rate_limit must return :politicas :rate-limit \
verbatim (got {:?}, expected {rl:?})",
p.rate_limit(),
);
assert_eq!(
p.rate_limit(),
p.rate_limit,
"MeshPolicy::rate_limit must byte-equal the raw \
.rate_limit field access across every value in the \
accept-set",
);
}
}
#[test]
fn mesh_policy_is_empty_rate_limit_arm_routes_through_accessor() {
let empty = MeshPolicy::default();
assert!(
empty.is_empty(),
"MeshPolicy::default() must be is_empty() — every axis \
defaults to None",
);
for rl in [
RateLimit {
rate: 1,
window: Duration::from_secs(1),
},
RateLimit {
rate: POLICY_RATE_LIMIT_MAX,
window: Duration::from_secs(3600),
},
] {
let p = MeshPolicy {
rate_limit: Some(rl),
..MeshPolicy::default()
};
assert!(
!p.is_empty(),
"MeshPolicy::is_empty must return false when \
:rate-limit is {rl:?} — the emptiness predicate \
reads \"any axis carries a value\", not \"any axis \
carries a value the validate gate accepts\"",
);
assert_eq!(
p.rate_limit().is_none(),
p.is_empty(),
"when :rate-limit is the only set axis, is_empty() \
must equal rate_limit().is_none() — the accessor \
and the emptiness predicate must route through the \
same substrate-primitive typed dispatch on the \
:rate-limit arm",
);
}
}
#[test]
fn validate_politicas_rate_limit_zero_rate_arm_routes_through_accessor() {
let mut spec = three_member_spec();
spec.politicas = MeshPolicy {
rate_limit: Some(RateLimit {
rate: 0,
window: Duration::from_secs(1),
}),
..MeshPolicy::default()
};
assert!(
matches!(spec.validate(), Err(AplicacaoError::PolicyRateLimitZero)),
"validate_politicas must reject rate == 0 with \
PolicyRateLimitZero — the accessor and the validate gate \
must route through the same substrate-primitive typed \
dispatch on the :rate-limit zero-floor arm",
);
spec.politicas = MeshPolicy {
rate_limit: Some(RateLimit {
rate: 1,
window: Duration::from_secs(1),
}),
..MeshPolicy::default()
};
assert!(
spec.validate().is_ok(),
"validate_politicas must accept rate == 1 (the canonical \
lower boundary of the 1..=POLICY_RATE_LIMIT_MAX accept-\
set) with a canonical 1s window",
);
}
#[test]
fn mesh_policy_circuit_breaker_returns_circuit_breaker_option_byte_equal_across_permutations() {
for cb in [
None,
Some(CircuitBreaker {
max_failures: 1,
window: Duration::from_millis(1),
}),
Some(CircuitBreaker {
max_failures: POLICY_BREAKER_MAX_FAILURES_MAX,
window: POLICY_BREAKER_WINDOW_MAX,
}),
Some(CircuitBreaker {
max_failures: 0,
window: Duration::ZERO,
}),
Some(CircuitBreaker {
max_failures: u32::MAX,
window: Duration::MAX,
}),
] {
let p = MeshPolicy {
circuit_breaker: cb,
..MeshPolicy::default()
};
assert_eq!(
p.circuit_breaker(),
cb,
"MeshPolicy::circuit_breaker must return :politicas \
:circuit-breaker verbatim (got {:?}, expected {cb:?})",
p.circuit_breaker(),
);
assert_eq!(
p.circuit_breaker(),
p.circuit_breaker,
"MeshPolicy::circuit_breaker must byte-equal the raw \
.circuit_breaker field access across every value in \
the accept-set",
);
}
}
#[test]
fn mesh_policy_is_empty_circuit_breaker_arm_routes_through_accessor() {
let empty = MeshPolicy::default();
assert!(
empty.is_empty(),
"MeshPolicy::default() must be is_empty() — every axis \
defaults to None",
);
for cb in [
CircuitBreaker {
max_failures: 1,
window: Duration::from_millis(1),
},
CircuitBreaker {
max_failures: POLICY_BREAKER_MAX_FAILURES_MAX,
window: POLICY_BREAKER_WINDOW_MAX,
},
] {
let p = MeshPolicy {
circuit_breaker: Some(cb),
..MeshPolicy::default()
};
assert!(
!p.is_empty(),
"MeshPolicy::is_empty must return false when \
:circuit-breaker is {cb:?} — the emptiness predicate \
reads \"any axis carries a value\", not \"any axis \
carries a value the validate gate accepts\"",
);
assert_eq!(
p.circuit_breaker().is_none(),
p.is_empty(),
"when :circuit-breaker is the only set axis, \
is_empty() must equal circuit_breaker().is_none() — \
the accessor and the emptiness predicate must route \
through the same substrate-primitive typed dispatch \
on the :circuit-breaker arm",
);
}
}
#[test]
fn validate_politicas_circuit_breaker_arm_routes_through_accessor() {
let mut spec = three_member_spec();
spec.politicas = MeshPolicy {
circuit_breaker: Some(CircuitBreaker {
max_failures: 0,
window: Duration::from_millis(1),
}),
..MeshPolicy::default()
};
assert!(
matches!(
spec.validate(),
Err(AplicacaoError::PolicyBreakerZeroFailures)
),
"validate_politicas must reject max_failures == 0 with \
PolicyBreakerZeroFailures — the accessor and the validate \
gate must route through the same substrate-primitive \
typed dispatch on the :circuit-breaker zero-floor arm",
);
spec.politicas = MeshPolicy {
circuit_breaker: Some(CircuitBreaker {
max_failures: 1,
window: Duration::from_millis(1),
}),
..MeshPolicy::default()
};
assert!(
spec.validate().is_ok(),
"validate_politicas must accept a CircuitBreaker at the \
canonical lower boundary (max_failures = 1, window = \
1ms) — the accessor and the validate gate must route \
through the same substrate-primitive typed dispatch on \
the :circuit-breaker arm",
);
}
#[test]
fn circuit_breaker_max_failures_returns_max_failures_u32_byte_equal_across_permutations() {
for max_failures in [1u32, POLICY_BREAKER_MAX_FAILURES_MAX, 0, u32::MAX] {
let cb = CircuitBreaker {
max_failures,
window: Duration::from_secs(60),
};
assert_eq!(
cb.max_failures(),
max_failures,
"CircuitBreaker::max_failures must return :politicas \
:circuit-breaker :max-failures verbatim (got {}, \
expected {max_failures})",
cb.max_failures(),
);
assert_eq!(
cb.max_failures(),
cb.max_failures,
"CircuitBreaker::max_failures must byte-equal the raw \
.max_failures field access across every value in the \
u32 accept-set",
);
}
}
#[test]
fn validate_politicas_max_failures_zero_floor_arm_routes_through_accessor() {
let mut spec = three_member_spec();
spec.politicas = MeshPolicy {
circuit_breaker: Some(CircuitBreaker {
max_failures: 0,
window: Duration::from_secs(60),
}),
..MeshPolicy::default()
};
assert!(
matches!(
spec.validate(),
Err(AplicacaoError::PolicyBreakerZeroFailures)
),
"validate_politicas must reject max_failures == 0 with \
PolicyBreakerZeroFailures — the accessor and the validate \
gate must route through the same substrate-primitive typed \
dispatch on the :max-failures zero-floor arm",
);
spec.politicas = MeshPolicy {
circuit_breaker: Some(CircuitBreaker {
max_failures: 1,
window: Duration::from_secs(60),
}),
..MeshPolicy::default()
};
assert!(
spec.validate().is_ok(),
"validate_politicas must accept max_failures == 1 (the \
lower boundary of the 1..=POLICY_BREAKER_MAX_FAILURES_MAX \
accept-set)",
);
}
#[test]
fn circuit_breaker_max_failures_projects_u32_by_copy() {
for max_failures in [1u32, POLICY_BREAKER_MAX_FAILURES_MAX, 0, u32::MAX] {
let cb = CircuitBreaker {
max_failures,
window: Duration::from_secs(60),
};
let first = cb.max_failures();
let second = cb.max_failures();
assert_eq!(
first, second,
"CircuitBreaker::max_failures must be idempotent — two \
successive calls on the same &self must return the \
same u32",
);
assert_eq!(
first, max_failures,
"CircuitBreaker::max_failures must return :politicas \
:circuit-breaker :max-failures verbatim by copy — \
got {first}, expected {max_failures}",
);
}
}
#[test]
fn circuit_breaker_window_returns_window_duration_byte_equal_across_permutations() {
for window in [
Duration::from_millis(1),
POLICY_BREAKER_WINDOW_MAX,
Duration::ZERO,
Duration::from_secs(86_400),
] {
let cb = CircuitBreaker {
max_failures: 5,
window,
};
assert_eq!(
cb.window(),
window,
"CircuitBreaker::window must return :politicas \
:circuit-breaker :window verbatim (got {:?}, \
expected {window:?})",
cb.window(),
);
assert_eq!(
cb.window(),
cb.window,
"CircuitBreaker::window must byte-equal the raw \
.window field access across every value in the \
Duration accept-set",
);
}
}
#[test]
fn validate_politicas_window_zero_floor_arm_routes_through_accessor() {
let mut spec = three_member_spec();
spec.politicas = MeshPolicy {
circuit_breaker: Some(CircuitBreaker {
max_failures: 5,
window: Duration::ZERO,
}),
..MeshPolicy::default()
};
assert!(
matches!(
spec.validate(),
Err(AplicacaoError::PolicyBreakerZeroWindow)
),
"validate_politicas must reject window == Duration::ZERO \
with PolicyBreakerZeroWindow — the accessor and the \
validate gate must route through the same substrate-\
primitive typed dispatch on the :window zero-floor arm",
);
spec.politicas = MeshPolicy {
circuit_breaker: Some(CircuitBreaker {
max_failures: 5,
window: Duration::from_millis(1),
}),
..MeshPolicy::default()
};
assert!(
spec.validate().is_ok(),
"validate_politicas must accept window == \
Duration::from_millis(1) (the lower boundary of the \
1ms..=POLICY_BREAKER_WINDOW_MAX accept-set)",
);
}
#[test]
fn circuit_breaker_window_projects_duration_by_copy() {
for window in [
Duration::from_millis(1),
POLICY_BREAKER_WINDOW_MAX,
Duration::ZERO,
Duration::from_secs(86_400),
] {
let cb = CircuitBreaker {
max_failures: 5,
window,
};
let first = cb.window();
let second = cb.window();
assert_eq!(
first, second,
"CircuitBreaker::window must be idempotent — two \
successive calls on the same &self must return the \
same Duration",
);
assert_eq!(
first, window,
"CircuitBreaker::window must return :politicas \
:circuit-breaker :window verbatim by copy — \
got {first:?}, expected {window:?}",
);
}
}
#[test]
fn port_for_destination_at_contract_destination_returns_entrada_port_when_para_matches() {
let mut spec = three_member_spec();
if let Some(e) = spec.entrada.as_mut() {
e.para = "cart".into();
e.port = 8443;
}
let apex_contract = WitContract {
de: "checkout".into(),
para: "cart".into(),
wit: "wasi:http/proxy".into(),
endpoint: Some("/hello".into()),
subject: None,
slot: None,
};
assert_eq!(
spec.port_for_destination(apex_contract.destination()),
8443,
"`spec.port_for_destination(c.destination())` must equal \
`entrada.port` when the contract callee names the ingress \
apex — the CNP per-edge L4 port and the HTTPRoute apex \
backendRef port share this substrate-primitive resolver.",
);
let non_apex_contract = WitContract {
de: "cart".into(),
para: "payment".into(),
wit: "wasi:http/proxy".into(),
endpoint: Some("/charge".into()),
subject: None,
slot: None,
};
assert_eq!(
spec.port_for_destination(non_apex_contract.destination()),
DEFAULT_SERVICO_PORT,
"`spec.port_for_destination(c.destination())` must fall back \
to the substrate-canonical port floor when the contract \
callee is not the ingress apex — the resolver's non-apex \
arm reaches for [`DEFAULT_SERVICO_PORT`] by construction.",
);
}
#[test]
fn membro_key_consts_are_lower_camel_case_shape() {
for key in [crate::MEMBRO_KEY_CAIXA, crate::MEMBRO_KEY_VERSAO] {
assert!(
!key.is_empty(),
"MEMBRO_KEY_* must be non-empty (got {key:?})"
);
let first = key.chars().next().unwrap();
assert!(
first.is_ascii_lowercase(),
"MEMBRO_KEY_* must lead with an ASCII-lowercase byte \
(got {key:?}, leads with {first:?})",
);
assert!(
key.chars().all(|c| c.is_ascii_alphanumeric()),
"MEMBRO_KEY_* must be ASCII-alphanumeric only \
— no `_` / `-` / `:` / `.` / whitespace (got {key:?})",
);
}
}
#[test]
fn wit_contract_serde_keys_match_lifted_contrato_key_consts() {
let c = WitContract {
de: "cart".into(),
para: "catalog".into(),
wit: "wasi:http/proxy".into(),
endpoint: Some("/lookup".into()),
subject: None,
slot: None,
};
let json = serde_json::to_string(&c).unwrap();
for key in [
crate::CONTRATO_KEY_DE,
crate::CONTRATO_KEY_PARA,
crate::CONTRATO_KEY_WIT,
WitTarget::HTTP_FIELD_NAME,
] {
let quoted = format!("\"{key}\"");
assert!(
json.contains("ed),
"serialized WitContract must carry the lifted \
CONTRATO_KEY_* / WitTarget::*_FIELD_NAME byte-sequence \
{quoted} verbatim in the JSON emission (got: {json})",
);
}
let pubsub = WitContract {
de: "cart".into(),
para: "events".into(),
wit: "nats:pub-sub".into(),
endpoint: None,
subject: Some("orders.placed".into()),
slot: None,
};
let pubsub_json = serde_json::to_string(&pubsub).unwrap();
let pubsub_quoted = format!("\"{}\"", WitTarget::PUBSUB_FIELD_NAME);
assert!(
pubsub_json.contains(&pubsub_quoted),
"serialized pub-sub WitContract must carry the lifted \
WitTarget::PUBSUB_FIELD_NAME byte-sequence {pubsub_quoted} \
verbatim in the JSON emission (got: {pubsub_json})",
);
let store = WitContract {
de: "cart".into(),
para: "sessions".into(),
wit: "wasi:keyvalue/store".into(),
endpoint: None,
subject: None,
slot: Some("cart/$id".into()),
};
let store_json = serde_json::to_string(&store).unwrap();
let store_quoted = format!("\"{}\"", WitTarget::STORE_FIELD_NAME);
assert!(
store_json.contains(&store_quoted),
"serialized store WitContract must carry the lifted \
WitTarget::STORE_FIELD_NAME byte-sequence {store_quoted} \
verbatim in the JSON emission (got: {store_json})",
);
}
#[test]
fn contrato_key_consts_are_pairwise_distinct() {
let all = [
crate::CONTRATO_KEY_DE,
crate::CONTRATO_KEY_PARA,
crate::CONTRATO_KEY_WIT,
WitTarget::HTTP_FIELD_NAME,
WitTarget::PUBSUB_FIELD_NAME,
WitTarget::STORE_FIELD_NAME,
];
for (i, a) in all.iter().enumerate() {
for b in all.iter().skip(i + 1) {
assert_ne!(
a, b,
"CONTRATO_KEY_* / WitTarget::*_FIELD_NAME consts \
must be pairwise-distinct canonical byte-sequences \
— got `{a}` == `{b}`",
);
}
}
}
#[test]
fn contrato_key_consts_are_lower_camel_case_shape() {
for key in [
crate::CONTRATO_KEY_DE,
crate::CONTRATO_KEY_PARA,
crate::CONTRATO_KEY_WIT,
WitTarget::HTTP_FIELD_NAME,
WitTarget::PUBSUB_FIELD_NAME,
WitTarget::STORE_FIELD_NAME,
] {
assert!(
!key.is_empty(),
"CONTRATO_KEY_* / WitTarget::*_FIELD_NAME must be \
non-empty (got {key:?})"
);
let first = key.chars().next().unwrap();
assert!(
first.is_ascii_lowercase(),
"CONTRATO_KEY_* / WitTarget::*_FIELD_NAME must lead \
with an ASCII-lowercase byte (got {key:?}, leads with \
{first:?})",
);
assert!(
key.chars().all(|c| c.is_ascii_alphanumeric()),
"CONTRATO_KEY_* / WitTarget::*_FIELD_NAME must be \
ASCII-alphanumeric only — no `_` / `-` / `:` / `.` / \
whitespace (got {key:?})",
);
}
}
#[test]
fn entrada_serde_keys_match_lifted_entrada_key_consts() {
let e = Entrada {
host: "checkout.quero.cloud".into(),
para: "cart".into(),
paths: vec!["/cart".into()],
port: 8080,
};
let json = serde_json::to_string(&e).unwrap();
for key in [
crate::ENTRADA_KEY_HOST,
crate::ENTRADA_KEY_PARA,
crate::ENTRADA_KEY_PATHS,
crate::ENTRADA_KEY_PORT,
] {
let quoted = format!("\"{key}\"");
assert!(
json.contains("ed),
"serialized Entrada must carry the lifted ENTRADA_KEY_* \
byte-sequence {quoted} verbatim in the JSON emission \
(got: {json})",
);
}
}
#[test]
fn entrada_key_consts_are_pairwise_distinct() {
let all = [
crate::ENTRADA_KEY_HOST,
crate::ENTRADA_KEY_PARA,
crate::ENTRADA_KEY_PATHS,
crate::ENTRADA_KEY_PORT,
];
for (i, a) in all.iter().enumerate() {
for b in all.iter().skip(i + 1) {
assert_ne!(
a, b,
"ENTRADA_KEY_* consts must be pairwise-distinct \
canonical byte-sequences — got `{a}` == `{b}`",
);
}
}
}
#[test]
fn entrada_key_consts_are_lower_camel_case_shape() {
for key in [
crate::ENTRADA_KEY_HOST,
crate::ENTRADA_KEY_PARA,
crate::ENTRADA_KEY_PATHS,
crate::ENTRADA_KEY_PORT,
] {
assert!(
!key.is_empty(),
"ENTRADA_KEY_* must be non-empty (got {key:?})"
);
let first = key.chars().next().unwrap();
assert!(
first.is_ascii_lowercase(),
"ENTRADA_KEY_* must lead with an ASCII-lowercase byte \
(got {key:?}, leads with {first:?})",
);
assert!(
key.chars().all(|c| c.is_ascii_alphanumeric()),
"ENTRADA_KEY_* must be ASCII-alphanumeric only \
— no `_` / `-` / `:` / `.` / whitespace (got {key:?})",
);
}
}
#[test]
fn mesh_policy_serde_keys_match_lifted_politicas_key_consts() {
let p = MeshPolicy {
timeout: Some(Duration::from_secs(30)),
retries: Some(3),
circuit_breaker: Some(CircuitBreaker {
max_failures: 5,
window: Duration::from_secs(60),
}),
mtls_required: Some(true),
rate_limit: Some(RateLimit {
rate: 100,
window: Duration::from_secs(1),
}),
};
let json = serde_json::to_string(&p).unwrap();
for key in [
crate::POLITICAS_KEY_TIMEOUT,
crate::POLITICAS_KEY_RETRIES,
crate::POLITICAS_KEY_CIRCUIT_BREAKER,
crate::POLITICAS_KEY_MTLS_REQUIRED,
crate::POLITICAS_KEY_RATE_LIMIT,
] {
let quoted = format!("\"{key}\"");
assert!(
json.contains("ed),
"serialized MeshPolicy must carry the lifted \
POLITICAS_KEY_* byte-sequence {quoted} verbatim in the \
JSON emission (got: {json})",
);
}
}
#[test]
fn politicas_key_consts_are_pairwise_distinct() {
let all = [
crate::POLITICAS_KEY_TIMEOUT,
crate::POLITICAS_KEY_RETRIES,
crate::POLITICAS_KEY_CIRCUIT_BREAKER,
crate::POLITICAS_KEY_MTLS_REQUIRED,
crate::POLITICAS_KEY_RATE_LIMIT,
];
for (i, a) in all.iter().enumerate() {
for b in all.iter().skip(i + 1) {
assert_ne!(
a, b,
"POLITICAS_KEY_* consts must be pairwise-distinct \
canonical byte-sequences — got `{a}` == `{b}`",
);
}
}
}
#[test]
fn politicas_key_consts_are_lower_camel_case_shape() {
for key in [
crate::POLITICAS_KEY_TIMEOUT,
crate::POLITICAS_KEY_RETRIES,
crate::POLITICAS_KEY_CIRCUIT_BREAKER,
crate::POLITICAS_KEY_MTLS_REQUIRED,
crate::POLITICAS_KEY_RATE_LIMIT,
] {
assert!(
!key.is_empty(),
"POLITICAS_KEY_* must be non-empty (got {key:?})"
);
let first = key.chars().next().unwrap();
assert!(
first.is_ascii_lowercase(),
"POLITICAS_KEY_* must lead with an ASCII-lowercase \
byte (got {key:?}, leads with {first:?})",
);
assert!(
key.chars().all(|c| c.is_ascii_alphanumeric()),
"POLITICAS_KEY_* must be ASCII-alphanumeric only — \
no `_` / `-` / `:` / `.` / whitespace (got {key:?})",
);
}
}
#[test]
fn circuit_breaker_serde_keys_match_lifted_circuit_breaker_key_consts() {
let cb = CircuitBreaker {
max_failures: 5,
window: Duration::from_secs(60),
};
let json = serde_json::to_string(&cb).unwrap();
for key in [
crate::CIRCUIT_BREAKER_KEY_MAX_FAILURES,
crate::CIRCUIT_BREAKER_KEY_WINDOW,
] {
let quoted = format!("\"{key}\"");
assert!(
json.contains("ed),
"serialized CircuitBreaker must carry the lifted \
CIRCUIT_BREAKER_KEY_* byte-sequence {quoted} verbatim \
in the JSON emission (got: {json})",
);
}
}
#[test]
fn circuit_breaker_key_consts_are_pairwise_distinct() {
let all = [
crate::CIRCUIT_BREAKER_KEY_MAX_FAILURES,
crate::CIRCUIT_BREAKER_KEY_WINDOW,
];
for (i, a) in all.iter().enumerate() {
for b in all.iter().skip(i + 1) {
assert_ne!(
a, b,
"CIRCUIT_BREAKER_KEY_* consts must be pairwise-distinct \
canonical byte-sequences — got `{a}` == `{b}`",
);
}
}
}
#[test]
fn circuit_breaker_key_consts_are_lower_camel_case_shape() {
for key in [
crate::CIRCUIT_BREAKER_KEY_MAX_FAILURES,
crate::CIRCUIT_BREAKER_KEY_WINDOW,
] {
assert!(
!key.is_empty(),
"CIRCUIT_BREAKER_KEY_* must be non-empty (got {key:?})"
);
let first = key.chars().next().unwrap();
assert!(
first.is_ascii_lowercase(),
"CIRCUIT_BREAKER_KEY_* must lead with an ASCII-lowercase \
byte (got {key:?}, leads with {first:?})",
);
assert!(
key.chars().all(|c| c.is_ascii_alphanumeric()),
"CIRCUIT_BREAKER_KEY_* must be ASCII-alphanumeric only — \
no `_` / `-` / `:` / `.` / whitespace (got {key:?})",
);
}
}
#[test]
fn placement_serde_keys_match_lifted_m3_placement_key_consts() {
let p = Placement {
estrategia: PlacementStrategy::Sharded,
clusters: vec!["rio".into(), "mar".into()],
affinity: Some("data-locality".into()),
shard_key: Some("$tenantId".into()),
};
let json = serde_json::to_string(&p).unwrap();
for key in [
crate::M3_PLACEMENT_KEY_ESTRATEGIA,
crate::M3_PLACEMENT_KEY_CLUSTERS,
crate::M3_PLACEMENT_KEY_AFFINITY,
crate::M3_PLACEMENT_KEY_SHARD_KEY,
] {
let quoted = format!("\"{key}\"");
assert!(
json.contains("ed),
"serialized Placement must carry the lifted \
M3_PLACEMENT_KEY_* byte-sequence {quoted} verbatim in \
the JSON emission (got: {json})",
);
}
}
#[test]
fn m3_placement_key_consts_are_pairwise_distinct() {
let all = [
crate::M3_PLACEMENT_KEY_ESTRATEGIA,
crate::M3_PLACEMENT_KEY_CLUSTERS,
crate::M3_PLACEMENT_KEY_AFFINITY,
crate::M3_PLACEMENT_KEY_SHARD_KEY,
];
for (i, a) in all.iter().enumerate() {
for b in all.iter().skip(i + 1) {
assert_ne!(
a, b,
"M3_PLACEMENT_KEY_* consts must be pairwise-distinct \
canonical byte-sequences — got `{a}` == `{b}`",
);
}
}
}
#[test]
fn m3_placement_key_consts_are_lower_camel_case_shape() {
for key in [
crate::M3_PLACEMENT_KEY_ESTRATEGIA,
crate::M3_PLACEMENT_KEY_CLUSTERS,
crate::M3_PLACEMENT_KEY_AFFINITY,
crate::M3_PLACEMENT_KEY_SHARD_KEY,
] {
assert!(
!key.is_empty(),
"M3_PLACEMENT_KEY_* must be non-empty (got {key:?})"
);
let first = key.chars().next().unwrap();
assert!(
first.is_ascii_lowercase(),
"M3_PLACEMENT_KEY_* must lead with an ASCII-lowercase \
byte (got {key:?}, leads with {first:?})",
);
assert!(
key.chars().all(|c| c.is_ascii_alphanumeric()),
"M3_PLACEMENT_KEY_* must be ASCII-alphanumeric only — \
no `_` / `-` / `:` / `.` / whitespace (got {key:?})",
);
}
}
#[test]
fn port_for_destination_returns_entrada_port_when_para_matches_destination() {
let mut spec = three_member_spec();
if let Some(e) = spec.entrada.as_mut() {
e.para = "cart".into();
e.port = 9090;
}
assert_eq!(
spec.port_for_destination("cart"),
9090,
"port_for_destination(entrada.para) must return entrada.port \
verbatim, not the DEFAULT_SERVICO_PORT fallback"
);
}
#[test]
fn port_for_destination_falls_back_to_default_servico_port_when_para_mismatches() {
let spec = three_member_spec();
assert_eq!(
spec.port_for_destination("payment"),
DEFAULT_SERVICO_PORT,
"port_for_destination(non-apex-destination) must route \
through the lifted DEFAULT_SERVICO_PORT canonical port floor"
);
}
#[test]
fn port_for_destination_falls_back_to_default_servico_port_when_entrada_none() {
let mut spec = three_member_spec();
spec.entrada = None;
assert_eq!(
spec.port_for_destination("cart"),
DEFAULT_SERVICO_PORT,
"port_for_destination on an internal-only Aplicacao must \
fall back to the lifted DEFAULT_SERVICO_PORT floor for \
every destination"
);
assert_eq!(
spec.port_for_destination("payment"),
DEFAULT_SERVICO_PORT,
"port_for_destination on an internal-only Aplicacao must \
fall back uniformly across every destination — the fallback \
is not entrada-shape-conditional"
);
}
#[test]
fn port_for_destination_honors_non_default_entrada_port_verbatim() {
let mut spec = three_member_spec();
if let Some(e) = spec.entrada.as_mut() {
e.para = "cart".into();
e.port = 8443;
}
assert_ne!(
8443, DEFAULT_SERVICO_PORT,
"test fixture must probe a port distinct from \
DEFAULT_SERVICO_PORT to exercise the honor-verbatim arm"
);
assert_eq!(
spec.port_for_destination("cart"),
8443,
"port_for_destination(entrada.para) must return entrada.port \
verbatim, even when the port differs from DEFAULT_SERVICO_PORT"
);
}
#[test]
fn port_for_destination_at_entrada_destination_returns_entrada_port_across_permutations() {
for (para, port) in [
("cart", DEFAULT_SERVICO_PORT),
("cart", 8443u16),
("payment", 9090u16),
("catalog", 443u16),
] {
let mut spec = three_member_spec();
if let Some(e) = spec.entrada.as_mut() {
e.para = para.into();
e.port = port;
}
let expected_port = spec
.entrada
.as_ref()
.expect("three_member_spec carries a typed `:entrada` block")
.port;
let composed_port = {
let entrada = spec.entrada.as_ref().expect("entrada present");
spec.port_for_destination(entrada.destination())
};
assert_eq!(
composed_port, expected_port,
"`spec.port_for_destination(entrada.destination())` must \
equal `entrada.port` under today's single-destination \
`:entrada` slot — this is the apex-identity contract \
every downstream ingress-apex L4 port reader relies on. \
Input :entrada :para: {para:?}, :entrada :port: {port}"
);
}
}
#[test]
fn port_for_destination_apex_arm_routes_through_destination_accessor() {
for (para, port) in [("cart", 8080u16), ("payment", 9090u16), ("catalog", 443u16)] {
let mut spec = three_member_spec();
if let Some(e) = spec.entrada.as_mut() {
e.para = para.into();
e.port = port;
}
let e = spec
.entrada
.as_ref()
.expect("three_member_spec carries a typed `:entrada` block");
assert_eq!(
e.destination(),
e.para.as_str(),
"Entrada::destination must byte-equal the .para field \
access — an accessor-side detour that no longer \
projects the raw field would silently split this \
drift-detection test from the port_for_destination \
apex-arm membership probe",
);
assert_eq!(
spec.port_for_destination(para),
port,
"port_for_destination must key off the accessor-projected \
destination and return `entrada.port` on the apex arm — \
input :entrada :para: {para:?}, :entrada :port: {port}",
);
assert_eq!(
spec.port_for_destination("ghost-destination-never-a-member"),
DEFAULT_SERVICO_PORT,
"port_for_destination must fall through to \
DEFAULT_SERVICO_PORT on a non-matching destination \
under the accessor-projected membership check — input \
:entrada :para: {para:?}, :entrada :port: {port}",
);
}
}
#[test]
fn rate_limit_rate_returns_rate_u32_byte_equal_across_permutations() {
for rate in [1u32, POLICY_RATE_LIMIT_MAX, 0, u32::MAX] {
let rl = RateLimit {
rate,
window: Duration::from_secs(1),
};
assert_eq!(
rl.rate(),
rate,
"RateLimit::rate must return :politicas :rate-limit :rate \
verbatim (got {}, expected {rate})",
rl.rate(),
);
assert_eq!(
rl.rate(),
rl.rate,
"RateLimit::rate must byte-equal the raw .rate field \
access across every value in the u32 accept-set",
);
}
}
#[test]
fn validate_politicas_rate_zero_floor_arm_routes_through_accessor() {
let mut spec = three_member_spec();
spec.politicas = MeshPolicy {
rate_limit: Some(RateLimit {
rate: 0,
window: Duration::from_secs(1),
}),
..MeshPolicy::default()
};
assert!(
matches!(spec.validate(), Err(AplicacaoError::PolicyRateLimitZero)),
"validate_politicas must reject rate == 0 with \
PolicyRateLimitZero — the accessor and the validate gate \
must route through the same substrate-primitive typed \
dispatch on the :rate zero-floor arm",
);
spec.politicas = MeshPolicy {
rate_limit: Some(RateLimit {
rate: 1,
window: Duration::from_secs(1),
}),
..MeshPolicy::default()
};
assert!(
spec.validate().is_ok(),
"validate_politicas must accept rate == 1 (the lower \
boundary of the 1..=POLICY_RATE_LIMIT_MAX accept-set)",
);
}
#[test]
fn rate_limit_rate_projects_u32_by_copy() {
for rate in [1u32, POLICY_RATE_LIMIT_MAX, 0, u32::MAX] {
let rl = RateLimit {
rate,
window: Duration::from_secs(1),
};
let first = rl.rate();
let second = rl.rate();
assert_eq!(
first, second,
"RateLimit::rate must be idempotent — two successive \
calls on the same &self must return the same u32",
);
assert_eq!(
first, rate,
"RateLimit::rate must return :politicas :rate-limit :rate \
verbatim by copy — got {first}, expected {rate}",
);
}
}
#[test]
fn rate_limit_window_returns_window_duration_byte_equal_across_permutations() {
for window in [
Duration::from_secs(1),
Duration::from_secs(60),
Duration::from_secs(3600),
Duration::ZERO,
Duration::from_millis(500),
] {
let rl = RateLimit { rate: 100, window };
assert_eq!(
rl.window(),
window,
"RateLimit::window must return :politicas :rate-limit :window \
verbatim (got {:?}, expected {window:?})",
rl.window(),
);
assert_eq!(
rl.window(),
rl.window,
"RateLimit::window must byte-equal the raw .window field \
access across every value in the Duration accept-set",
);
}
}
#[test]
fn validate_politicas_rate_limit_window_canonical_arm_routes_through_accessor() {
let mut spec = three_member_spec();
spec.politicas = MeshPolicy {
rate_limit: Some(RateLimit {
rate: 100,
window: Duration::from_millis(500),
}),
..MeshPolicy::default()
};
match spec.validate() {
Err(AplicacaoError::PolicyRateLimitWindowNotCanonical { window }) => {
assert_eq!(
window,
Duration::from_millis(500),
"PolicyRateLimitWindowNotCanonical must carry the \
offending :window magnitude verbatim through the \
accessor — got {window:?}, expected 500ms",
);
}
other => panic!(
"validate_politicas must reject non-canonical :window \
with PolicyRateLimitWindowNotCanonical — the accessor \
and the validate gate must route through the same \
substrate-primitive typed dispatch on the :window \
canonical-set arm; got {other:?}",
),
}
spec.politicas = MeshPolicy {
rate_limit: Some(RateLimit {
rate: 100,
window: Duration::from_secs(1),
}),
..MeshPolicy::default()
};
assert!(
spec.validate().is_ok(),
"validate_politicas must accept window == Duration::from_secs(1) \
(the lower row of the RATE_LIMIT_UNIT_TABLE accept-set)",
);
}
#[test]
fn rate_limit_window_projects_duration_by_copy() {
for window in [
Duration::from_secs(1),
Duration::from_secs(60),
Duration::from_secs(3600),
Duration::ZERO,
Duration::from_millis(500),
] {
let rl = RateLimit { rate: 100, window };
let first = rl.window();
let second = rl.window();
assert_eq!(
first, second,
"RateLimit::window must be idempotent — two successive \
calls on the same &self must return the same Duration",
);
assert_eq!(
first, window,
"RateLimit::window must return :politicas :rate-limit :window \
verbatim by copy — got {first:?}, expected {window:?}",
);
}
}
}