use serde_json::json;
use zenkey_fleet::report::*;
use zenkey_fleet::{Coverage, CoverageRow};
use zenkey_report_fixtures as fx;
#[test]
fn a_false_deprecated_flag_is_absent_while_a_false_open_ended_flag_is_not() {
let plain = fx::topic_row();
assert_eq!(
serde_json::to_value(&plain).unwrap(),
json!({
"producer": "sysinfo",
"registry_version": "1.0",
"class": "telemetry",
"path": "disk/{mount}/used",
"type_name": "TelemetryPoint",
"open_ended": false,
}),
"a false `deprecated` is absent, a false `open_ended` is present"
);
let retired = fx::topic_row_retired();
assert_eq!(
serde_json::to_value(&retired).unwrap(),
json!({
"producer": "sysinfo",
"registry_version": "1.0",
"class": "telemetry",
"path": "disk/{mount}/used",
"type_name": "TelemetryPoint",
"open_ended": true,
"since": "1.0",
"deprecated": true,
"deprecated_since": "2.0",
"replaced_by": "disk/{mount}/bytes_used",
})
);
}
#[test]
fn the_topic_verdict_vocabulary_is_snake_case_and_partial_reports_omit() {
for (verdict, wire) in [
(TopicVerdict::Registered, "registered"),
(TopicVerdict::Unregistered, "unregistered"),
(TopicVerdict::NoSliceForProducer, "no_slice_for_producer"),
(TopicVerdict::NotADataClass, "not_a_data_class"),
(TopicVerdict::NotV1, "not_v1"),
(TopicVerdict::NotUnderBase, "not_under_base"),
(TopicVerdict::RegistryNotLoaded, "registry_not_loaded"),
] {
assert_eq!(serde_json::to_value(verdict).unwrap(), json!(wire));
}
let stopped = TopicInfo {
key: "demo/example/foo".into(),
verdict: TopicVerdict::NotUnderBase,
note: "not under this base".into(),
origin: None,
producer: None,
class: None,
subject: None,
variables: Default::default(),
payload_type: None,
unit: None,
qos: None,
ttl_s: None,
rate: None,
cardinality: None,
encoding: None,
since: None,
description: None,
};
assert_eq!(
serde_json::to_value(&stopped).unwrap(),
json!({
"key": "demo/example/foo",
"verdict": "not_under_base",
"note": "not under this base",
}),
"fields below the failure point are absent, never defaulted"
);
}
#[test]
fn no_topic_info_field_is_dead_the_constructor_reaches_them_all() {
let toml = r#"
[registry]
version = "1.0"
app = "t"
convention = 1
[producer]
name = "sysinfo"
[[subject]]
path = "disk/{mount}/used"
class = "telemetry"
type = "TelemetryPoint"
unit = "bytes"
qos = "sampled"
ttl_s = 120
rate = "low"
cardinality = 16
encoding = "application/cbor"
since = "1.0"
description = "bytes used per mount"
"#;
let slices =
zenkey_fleet::SliceSet::from_slices(vec![zenkey::parse_slice(toml).expect("slice parses")]);
let described = zenkey_fleet::model::facts::describe_key(
"",
&format!("v1/{}/telemetry/sysinfo/disk/var-log/used", fx::ORIGIN),
Some(&slices),
);
let built = serde_json::to_value(TopicInfo::from_description(&described)).unwrap();
let full = serde_json::to_value(fx::topic_info_full()).unwrap();
for key in full.as_object().unwrap().keys() {
assert!(
built.get(key).is_some(),
"TopicInfo.{key} is dead: the fixture serializes it, but the \
constructor path never fills it"
);
}
assert_eq!(
built, full,
"the constructor's document IS the every-field fixture — no field \
reachable only by literal construction"
);
}
#[test]
fn a_node_list_says_whether_the_slice_join_was_even_attempted() {
let unasked = fx::node_list_unjoined();
let asked = fx::node_list();
assert_eq!(
serde_json::to_value(&unasked).unwrap(),
json!({
"nodes": [{"origin": "h-3fa9c2d41b7e", "producer": "sysinfo"}],
"slices_joined": false,
})
);
assert_eq!(
serde_json::to_value(&asked).unwrap()["slices_joined"],
json!(true),
"a row with no app means two different things, and only the flag says which"
);
}
#[test]
fn blob_origins_distinguish_not_asked_from_nobody_answered() {
let base = BlobTierRow {
producer: "artifacts".into(),
registry_version: "1.0".into(),
tier: "artifact".into(),
known_tier: true,
endpoints: vec!["manifest".into(), "slice".into()],
algo: None,
reference: Some("BlobRef".into()),
encoding: None,
since: None,
description: None,
origins: Asked::NotAsked,
};
let not_asked = serde_json::to_value(&base).unwrap();
assert_eq!(
not_asked,
json!({
"producer": "artifacts",
"registry_version": "1.0",
"tier": "artifact",
"known_tier": true,
"endpoints": ["manifest", "slice"],
"reference": "BlobRef",
}),
"roster not asked: the key is absent"
);
let asked_silent = BlobTierRow {
origins: Asked::Asked(vec![]),
..base.clone()
};
assert_eq!(
serde_json::to_value(&asked_silent).unwrap()["origins"],
json!([]),
"asked, nobody answered: an empty list, which is not absence"
);
let alive = BlobTierRow {
origins: Asked::Asked(vec!["h-3fa9c2d41b7e".into()]),
..base
};
assert_eq!(
serde_json::to_value(&alive).unwrap()["origins"],
json!(["h-3fa9c2d41b7e"])
);
}
#[test]
fn coverage_flattens_into_its_row_with_snake_case_tags() {
let covered = CoverageRow {
producer: "sysinfo".into(),
path: "health".into(),
ttl_s: Some(30),
coverage: Coverage::Covered("main@abc".into()),
};
assert_eq!(
serde_json::to_value(&covered).unwrap(),
json!({
"producer": "sysinfo",
"path": "health",
"ttl_s": 30,
"coverage": "covered",
"storage": "main@abc",
})
);
let uncovered = CoverageRow {
producer: "sysinfo".into(),
path: "health".into(),
ttl_s: None,
coverage: Coverage::Uncovered,
};
assert_eq!(
serde_json::to_value(&uncovered).unwrap(),
json!({"producer": "sysinfo", "path": "health", "coverage": "uncovered"}),
"no storage key at all when nothing covers it, and no ttl when none \
is declared"
);
assert_eq!(
serde_json::to_value(Coverage::Partial("main@abc".into())).unwrap(),
json!({"coverage": "partial", "storage": "main@abc"})
);
}
#[test]
fn a_call_answer_omits_every_part_the_wire_did_not_carry() {
let bare = CallAnswer {
origin: "h-3fa9c2d41b7e".into(),
outcome: CallOutcome::Ok {
value: None,
text: None,
},
attachment: None,
attachment_bytes: None,
};
assert_eq!(
serde_json::to_value(&bare).unwrap(),
json!({"origin": "h-3fa9c2d41b7e", "ok": true})
);
let failed = CallAnswer {
outcome: CallOutcome::Err(CallError {
name: "unsupported".into(),
message: "not built with that feature".into(),
}),
..bare
};
assert_eq!(
serde_json::to_value(&failed).unwrap(),
json!({
"origin": "h-3fa9c2d41b7e",
"ok": false,
"error": {"name": "unsupported", "message": "not built with that feature"},
})
);
let rich = CallAnswer {
origin: "h-3fa9c2d41b7e".into(),
outcome: CallOutcome::Ok {
value: Some(json!({"count": 214})),
text: None,
},
attachment: Some(json!({"trace": "abc123"})),
attachment_bytes: Some(18),
};
assert_eq!(
serde_json::to_string(&rich).unwrap(),
r#"{"origin":"h-3fa9c2d41b7e","ok":true,"value":{"count":214},"attachment":{"trace":"abc123"},"attachment_bytes":18}"#
);
let silent = CallReport {
key: "v1/*/@rpc/sysinfo/introspect".into(),
timeout_s: 5.0,
answers: vec![],
};
assert_eq!(silent.exit_code(), 2);
assert_eq!(
serde_json::to_value(&silent).unwrap(),
json!({
"key": "v1/*/@rpc/sysinfo/introspect",
"timeout_s": 5.0,
"answers": [],
})
);
assert_eq!(
CallReport {
answers: vec![failed],
..silent
}
.exit_code(),
1
);
}
#[test]
fn a_rate_row_keeps_its_latency_populations_apart() {
let quiet = RateRow {
key: "v1/h-a/telemetry/p/m".into(),
count: 12,
bytes: 480,
sn_gaps: Asked::Asked(0),
latency: None,
unstamped: Asked::Asked(12),
};
assert_eq!(
serde_json::to_value(&quiet).unwrap(),
json!({
"key": "v1/h-a/telemetry/p/m",
"count": 12,
"bytes": 480,
"sn_gaps": 0,
"unstamped": 12,
}),
"nothing stamped: the latency key is absent, which is not zero latency"
);
let unasked = RateRow {
sn_gaps: Asked::NotAsked,
unstamped: Asked::NotAsked,
..quiet.clone()
};
assert_eq!(
serde_json::to_value(&unasked).unwrap(),
json!({
"key": "v1/h-a/telemetry/p/m",
"count": 12,
"bytes": 480,
}),
"no --loss and no --latency: both counters are absent (O4), never zero"
);
let dist = zenkey_fleet::LatencySummary {
min_us: -200,
median_us: 900,
p95_us: 1500,
max_us: 5000,
samples: 4,
};
let stamped = RateRow {
latency: Some(zenkey_fleet::LatencyReport {
self_stamped: Some(dist),
foreign: None,
unattributable: None,
stampers: vec![],
stampers_dropped: 0,
}),
unstamped: Asked::Asked(1),
..quiet
};
assert_eq!(
serde_json::to_value(&stamped).unwrap()["latency"],
json!({
"self_stamped": {
"min_us": -200, "median_us": 900, "p95_us": 1500,
"max_us": 5000, "samples": 4,
},
}),
"one population, and the empty stamper bookkeeping stays out of the way"
);
}
#[test]
fn the_three_state_verdicts_keep_their_third_state() {
for (v, wire) in [
(CutoverVerdict::Pass, "pass"),
(CutoverVerdict::OldStillSpeaks, "old_still_speaks"),
(CutoverVerdict::Unproven, "unproven"),
] {
assert_eq!(serde_json::to_value(v).unwrap(), json!(wire));
}
for (v, wire) in [
(ExpectVerdict::Met, "met"),
(ExpectVerdict::NotMet, "not_met"),
(ExpectVerdict::Impaired, "impaired"),
] {
assert_eq!(serde_json::to_value(v).unwrap(), json!(wire));
}
let clean = ExpectReport {
selector: "v1/**".into(),
window_s: 5.0,
ended_early: false,
samples: 0,
keys_seen: 0,
dropped: 0,
rate_hz: None,
violations: vec![],
violations_total: 0,
unmet: vec!["saw 0 sample(s), wanted at least 1".into()],
verdict: ExpectVerdict::NotMet,
};
assert_eq!(
serde_json::to_value(&clean).unwrap(),
json!({
"selector": "v1/**",
"window_s": 5.0,
"ended_early": false,
"samples": 0,
"keys_seen": 0,
"dropped": 0,
"violations_total": 0,
"unmet": ["saw 0 sample(s), wanted at least 1"],
"verdict": "not_met",
}),
"an empty violation list is absent, and `rate_hz: None` means not asked"
);
}
#[test]
fn a_blob_probe_reports_what_it_asked_and_what_answered() {
let empty = BlobProbeReport {
target: "01hq9k".into(),
tier: "artifact".into(),
asked: vec!["v1/*/@blob/artifact/01hq9k/manifest".into()],
not_probed: None,
holders: vec![],
answered: 0,
roots: vec![],
declared_by: vec!["artifacts".into()],
slices_considered: 3,
};
assert_eq!(
serde_json::to_value(&empty).unwrap(),
json!({
"target": "01hq9k",
"tier": "artifact",
"asked": ["v1/*/@blob/artifact/01hq9k/manifest"],
"holders": [],
"answered": 0,
"roots": [],
"declared_by": ["artifacts"],
"slices_considered": 3,
}),
"asked but unanswered: the selector is on record, so silence is \
visibly a non-verdict rather than an absent question"
);
let no_registry = BlobProbeReport {
declared_by: vec![],
slices_considered: 0,
..empty
};
let v = serde_json::to_value(&no_registry).unwrap();
assert!(
v.get("declared_by").is_none(),
"an empty capability list stays absent"
);
assert_eq!(
v["slices_considered"], 0,
"…and the zero slice count is what says it was never a verdict (R7)"
);
let holder = BlobHolder {
origin: "h-3fa9c2d41b7e".into(),
key: "v1/h-3fa9c2d41b7e/@blob/artifact/01hq9k/manifest".into(),
availability: None,
manifest: None,
note: Some("answered, said nothing readable".into()),
unreadable: None,
error: None,
};
assert_eq!(
serde_json::to_value(&holder).unwrap(),
json!({
"origin": "h-3fa9c2d41b7e",
"key": "v1/h-3fa9c2d41b7e/@blob/artifact/01hq9k/manifest",
"note": "answered, said nothing readable",
})
);
assert_eq!(
serde_json::to_value(BlobListSource::RegistryDirs).unwrap(),
json!("registry-dirs"),
"kebab here, snake elsewhere — pinned as it is (see #202's note)"
);
}
#[test]
fn doctor_severities_are_the_stable_lowercase_vocabulary() {
for (s, wire) in [
(DoctorSeverity::Error, "error"),
(DoctorSeverity::Warning, "warning"),
(DoctorSeverity::Info, "info"),
] {
assert_eq!(serde_json::to_value(s).unwrap(), json!(wire));
}
let finding = DoctorFinding {
severity: DoctorSeverity::Info,
check: zenkey_fleet::report::CheckId::TimestampStampedElsewhere,
subject: "fleet".into(),
evidence: "stamped by 1 node that is not the publisher".into(),
citation: None,
};
assert_eq!(
serde_json::to_value(&finding).unwrap(),
json!({
"severity": "info",
"check": "timestamp-stamped-elsewhere",
"subject": "fleet",
"evidence": "stamped by 1 node that is not the publisher",
}),
"an uncited finding omits the key rather than nulling it"
);
}
#[test]
fn a_retired_entry_omits_every_fact_that_was_never_asked() {
let entry = RetiredEntry {
producer: "logs".into(),
path: "logs/errors_total".into(),
since: None,
replaced_by: None,
selector: "v1/*/*/logs/logs/errors_total".into(),
wire_samples: Asked::NotAsked,
still_declared: None,
subscribers: None,
replacement_samples: Asked::NotAsked,
verdict: CutoverVerdict::Unproven,
};
assert_eq!(
serde_json::to_value(&entry).unwrap(),
json!({
"producer": "logs",
"path": "logs/errors_total",
"selector": "v1/*/*/logs/logs/errors_total",
"verdict": "unproven",
}),
"an unasked fact is absent, not zero and not null"
);
let report = RetiredReport {
registries: vec!["registry".into()],
entries: vec![],
window_s: Asked::NotAsked,
plane_samples: Asked::NotAsked,
dropped: Asked::NotAsked,
introspect_answered: 0,
admin_entities: None,
verdict: CutoverVerdict::Pass,
};
assert_eq!(
serde_json::to_value(&report).unwrap(),
json!({
"registries": ["registry"],
"entries": [],
"introspect_answered": 0,
"verdict": "pass",
}),
"no window: every wire fact — dropped included — stays absent; the \
registries always state themselves"
);
let full = serde_json::to_value(fx::retired_report()).unwrap();
assert_eq!(full["window_s"], 30.0);
assert_eq!(full["dropped"], 5, "a listened run carries its drop count");
assert_eq!(full["entries"][0]["still_declared"], true);
assert_eq!(full["entries"][2]["verdict"], "unproven");
}
#[test]
fn every_enum_in_the_surface_names_its_wire_vocabulary() {
fn topic(v: &TopicVerdict) -> &'static str {
match v {
TopicVerdict::Registered => "registered",
TopicVerdict::Unregistered => "unregistered",
TopicVerdict::NoSliceForProducer => "no_slice_for_producer",
TopicVerdict::NotADataClass => "not_a_data_class",
TopicVerdict::NotV1 => "not_v1",
TopicVerdict::NotUnderBase => "not_under_base",
TopicVerdict::RegistryNotLoaded => "registry_not_loaded",
}
}
fn severity(v: &DoctorSeverity) -> &'static str {
match v {
DoctorSeverity::Error => "error",
DoctorSeverity::Warning => "warning",
DoctorSeverity::Info => "info",
}
}
fn cutover(v: &CutoverVerdict) -> &'static str {
match v {
CutoverVerdict::Pass => "pass",
CutoverVerdict::OldStillSpeaks => "old_still_speaks",
CutoverVerdict::Unproven => "unproven",
}
}
fn expect(v: &ExpectVerdict) -> &'static str {
match v {
ExpectVerdict::Met => "met",
ExpectVerdict::NotMet => "not_met",
ExpectVerdict::Impaired => "impaired",
}
}
fn coverage(v: &Coverage) -> &'static str {
match v {
Coverage::Covered(_) => "covered",
Coverage::Partial(_) => "partial",
Coverage::Uncovered => "uncovered",
}
}
fn blob_source(v: &BlobListSource) -> &'static str {
match v {
BlobListSource::Bus => "bus",
BlobListSource::RegistryDirs => "registry-dirs",
BlobListSource::Union => "union",
}
}
fn blob_progress(v: &BlobProgress) -> &'static str {
match v {
BlobProgress::Started { .. } => "started",
BlobProgress::Resumed { .. } => "resumed",
BlobProgress::Chunk { .. } => "chunk",
BlobProgress::Verifying => "verifying",
BlobProgress::Completed { .. } => "completed",
BlobProgress::Cancelled { .. } => "cancelled",
BlobProgress::Failed { .. } => "failed",
}
}
fn wire<T: serde::Serialize>(v: &T, tag: &str) -> String {
match serde_json::to_value(v).unwrap() {
serde_json::Value::String(s) => s,
serde_json::Value::Object(o) => o
.get(tag)
.and_then(|v| v.as_str())
.unwrap_or_else(|| panic!("no `{tag}` tag on {o:?}"))
.to_string(),
other => panic!("not a vocabulary: {other}"),
}
}
for v in [
TopicVerdict::Registered,
TopicVerdict::Unregistered,
TopicVerdict::NoSliceForProducer,
TopicVerdict::NotADataClass,
TopicVerdict::NotV1,
TopicVerdict::NotUnderBase,
TopicVerdict::RegistryNotLoaded,
] {
assert_eq!(wire(&v, ""), topic(&v));
}
for v in [
DoctorSeverity::Error,
DoctorSeverity::Warning,
DoctorSeverity::Info,
] {
assert_eq!(wire(&v, ""), severity(&v));
}
for v in [
CutoverVerdict::Pass,
CutoverVerdict::OldStillSpeaks,
CutoverVerdict::Unproven,
] {
assert_eq!(wire(&v, ""), cutover(&v));
}
for v in [
ExpectVerdict::Met,
ExpectVerdict::NotMet,
ExpectVerdict::Impaired,
] {
assert_eq!(wire(&v, ""), expect(&v));
}
for v in [
Coverage::Covered("s".into()),
Coverage::Partial("s".into()),
Coverage::Uncovered,
] {
assert_eq!(wire(&v, "coverage"), coverage(&v));
}
for v in [
BlobListSource::Bus,
BlobListSource::RegistryDirs,
BlobListSource::Union,
] {
assert_eq!(wire(&v, ""), blob_source(&v));
}
for v in [
BlobProgress::Started {
total_len: 1,
chunk_count: 1,
},
BlobProgress::Resumed {
received: 1,
total: 2,
},
BlobProgress::Chunk {
index: 0,
received: 1,
total: 2,
bytes_received: 3,
},
BlobProgress::Verifying,
BlobProgress::Completed { path: "p".into() },
BlobProgress::Cancelled {
received: 1,
total: 2,
},
BlobProgress::Failed { error: "e".into() },
] {
assert_eq!(wire(&v, "event"), blob_progress(&v));
}
}
#[test]
fn a_why_rung_keeps_not_asked_distinct_on_the_wire() {
let v = serde_json::to_value(fx::why_report()).unwrap();
assert_eq!(v["verdict"], "healthy");
assert!(
v.get("impairments").is_none(),
"no impairments is absence, not an empty list"
);
assert!(
v.get("listened_s").is_none(),
"not listened is absence (O4), never null"
);
let ids: Vec<&str> = v["rungs"]
.as_array()
.unwrap()
.iter()
.map(|r| r["id"].as_str().unwrap())
.collect();
assert_eq!(
ids,
zenkey_fleet::report::RungId::ALL.map(zenkey_fleet::report::RungId::as_str),
"one rung per id, in order"
);
let established = &v["rungs"][0];
assert_eq!(established["answer"], "established");
assert!(established.get("reason").is_none());
let lazy = &v["rungs"][4];
assert_eq!(lazy["id"], "publisher-declared");
assert_eq!(lazy["answer"], "not_established");
assert!(
lazy["reason"]
.as_str()
.unwrap()
.contains("publishers declare lazily"),
"the RFC 08 §6.1 wording rides the wire: {lazy}"
);
assert!(
lazy.get("evidence").is_none(),
"empty evidence is absent, not []"
);
let not_asked = &v["rungs"][9];
assert_eq!(not_asked["id"], "wire-heard");
assert_eq!(not_asked["answer"], "not_asked");
assert!(
not_asked.get("reason").is_none(),
"not_asked has no negative answer to spell"
);
}