//! `wai.live.recording` (extensions/live-recording.md): the committed corpus //! `live-conformance/recordings/vectors.json` regenerates byte for byte from its fixed seeds, //! every recording and clip in it gets the outcome it states, every reason the extension //! adds appears in it, every take it says it reuses is capture binding's take byte for byte, //! and the extension's §9 lists exactly the reasons the reference reports. #![cfg(feature = "live_record")] use std::collections::BTreeSet; use std::path::PathBuf; use wai::live_record::{corpus, Reason}; fn wai_dir() -> PathBuf { PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("..") } fn read(p: &str) -> String { std::fs::read_to_string(wai_dir().join(p)).unwrap_or_else(|e| panic!("{p}: {e}")) } fn committed() -> String { read("live-conformance/recordings/vectors.json") } #[test] fn the_committed_corpus_regenerates_from_its_seeds() { assert!(committed() == corpus::generate(), "live-conformance/recordings/vectors.json differs from `wai_live_record_vectors gen`"); } #[test] fn every_vector_gets_its_stated_outcome() { let fails = corpus::verify(&committed()); assert!(fails.is_empty(), "{}", fails.join("\n")); } /// Every reason this extension adds is a recording's refusal, a clip's refusal or a /// recording's verdict; the good recordings stand; the good clips §10 names are accepted, /// the aligned one with twice the jitter as its bound. #[test] fn the_corpus_covers_every_reason_and_clip() { let doc: serde_json::Value = serde_json::from_str(&committed()).unwrap(); let recordings = doc["recordings"].as_array().unwrap(); let clips = doc["clips"].as_array().unwrap(); let mut seen: BTreeSet = BTreeSet::new(); for v in recordings.iter().chain(clips) { if let Some(r) = v["reason"].as_str() { seen.insert(r.into()); } if let Some(r) = v["complete"].as_str() { seen.insert(r.into()); } } for r in Reason::ALL { assert!(seen.contains(r.code()), "nothing in the corpus gives {r}"); } for name in ["lesson_session", "signed_by_director", "with_composite", "late_recorder_span"] { let v = recordings.iter().find(|v| v["name"] == name).unwrap_or_else(|| panic!("no recording {name}")); assert_eq!(v["stands"], true, "{name}"); assert_eq!(v["complete"], "holds", "{name}"); } for name in ["single_chunk", "byte_range", "whole_take", "first_chunk", "last_chunk", "two_takes_aligned", "live_head"] { let v = clips.iter().find(|v| v["name"] == name).unwrap_or_else(|| panic!("no clip {name}")); assert_eq!(v["outcome"], "accept", "{name}"); } let aligned = clips.iter().find(|v| v["name"] == "two_takes_aligned").unwrap(); assert_eq!(aligned["facts"].as_array().unwrap().len(), 2); assert_eq!(aligned["bound_us"], 1_000_000); let missing = recordings.iter().find(|v| v["name"] == "missing_chunk").unwrap(); assert_eq!(missing["complete"], "chunk_missing"); } /// The takes the corpus says it reuses are capture binding's, byte for byte: a recording's /// take component holds that corpus's manifest, parts, receipts and consents; and a clip's /// part names that corpus's vector only when every commitment it gives is a record of that /// vector's chains and every chunk it gives is one of its parts. #[test] fn the_reused_takes_are_capture_bindings() { let doc: serde_json::Value = serde_json::from_str(&committed()).unwrap(); let takes: serde_json::Value = serde_json::from_str(&read("live-conformance/takes/vectors.json")).unwrap(); let vector = |name: &str| takes["vectors"].as_array().unwrap().iter().find(|v| v["name"] == name).unwrap_or_else(|| panic!("no take vector {name}")).clone(); let mut reused = 0; for v in doc["recordings"].as_array().unwrap() { for r in v["reuses"].as_array().unwrap() { let t = vector(r["vector"].as_str().unwrap()); let dir = format!("takes/{}/", r["take"].as_str().unwrap()); let files = v["files"].as_object().unwrap(); assert_eq!(t["take"], r["take"], "{}", v["name"]); assert_eq!(files[&format!("{dir}manifest.wtm")], t["manifest"], "{}", v["name"]); let mut parts: Vec<(u64, &serde_json::Value)> = files .iter() .filter_map(|(p, b)| Some((p.strip_prefix(&format!("{dir}chunk-"))?.strip_suffix(".bin")?.parse().ok()?, b))) .collect(); parts.sort_by_key(|p| p.0); let want: Vec<(u64, &serde_json::Value)> = t["parts"].as_array().unwrap().iter().map(|p| (p["index"].as_u64().unwrap(), &p["bytes"])).collect(); assert_eq!(parts, want, "{}", v["name"]); let of = |pre: &str| files.iter().filter(|(p, _)| p.starts_with(&format!("{dir}{pre}"))).map(|(_, b)| b.clone()).collect::>(); assert_eq!(serde_json::Value::Array(of("receipt-")), t["receipts"], "{}", v["name"]); assert_eq!(serde_json::Value::Array(of("consent-")), t["consents"], "{}", v["name"]); reused += 1; } } for c in doc["clips"].as_array().unwrap() { for p in c["parts"].as_array().unwrap() { let Some(name) = p["take_vector"].as_str() else { continue }; let t = vector(name); let records: BTreeSet<&str> = t["chains"].as_array().unwrap().iter().flat_map(|ch| ch.as_array().unwrap().iter().map(|r| r.as_str().unwrap())).collect(); let parts: BTreeSet<&str> = t["parts"].as_array().unwrap().iter().map(|p| p["bytes"].as_str().unwrap()).collect(); for r in p["commits"].as_array().unwrap() { assert!(records.contains(r.as_str().unwrap()), "clip {}: a commitment not in {name}", c["name"]); } for b in p["bytes"].as_array().unwrap().iter().filter_map(|b| b.as_str()) { assert!(parts.contains(b), "clip {}: a chunk not in {name}", c["name"]); } reused += 1; } } assert!(reused > 0); } /// §9 of the extension lists exactly the codes `Reason::ALL` has, each once, in order. #[test] fn the_extension_lists_the_reasons() { let text = read("extensions/live-recording.md"); let at = text.find("\n## 9. Reasons").expect("a §9"); let end = text[at + 1..].find("\n## ").map_or(text.len(), |e| at + 1 + e); let listed: Vec = text[at..end].lines().filter(|l| l.starts_with("| `")).filter_map(|l| l.split('`').nth(1).map(String::from)).collect(); let want: Vec = Reason::ALL.iter().map(|r| r.code().to_string()).collect(); assert_eq!(listed, want, "§9's table and Reason::ALL differ"); }