105 lines
5 KiB
Rust
105 lines
5 KiB
Rust
//! `wai.live.steering` (extensions/energy-steering.md): the committed corpus
|
|
//! `live-conformance/steering/vectors.json` regenerates byte for byte from its fixed seeds,
|
|
//! every request and vector in it gets the outcome it states, every reason the extension
|
|
//! adds refuses a vector, the accepted vectors are the cases §11 names with the reasons they
|
|
//! were written for, and the extension's §10 lists exactly the reasons the reference reports.
|
|
#![cfg(feature = "energy_steering")]
|
|
|
|
use std::collections::BTreeSet;
|
|
use std::path::PathBuf;
|
|
use wai::energy_steering::{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/steering/vectors.json")
|
|
}
|
|
|
|
#[test]
|
|
fn the_committed_corpus_regenerates_from_its_seeds() {
|
|
assert!(committed() == corpus::generate(), "live-conformance/steering/vectors.json differs from `wai_energy_steering_vectors gen`");
|
|
}
|
|
|
|
#[test]
|
|
fn every_request_and_vector_gets_its_stated_outcome() {
|
|
let fails = corpus::verify(&committed());
|
|
assert!(fails.is_empty(), "{}", fails.join("\n"));
|
|
}
|
|
|
|
/// Every reason this extension adds refuses a vector; the accepted vectors are §11's, each
|
|
/// first for the reason it was written for; a pathway with no figure is last wherever a
|
|
/// figure decides; and HLS and DASH content descriptions are written for every policy that
|
|
/// reads.
|
|
#[test]
|
|
fn the_corpus_covers_every_reason_and_case() {
|
|
let doc: serde_json::Value = serde_json::from_str(&committed()).unwrap();
|
|
let vectors = doc["vectors"].as_array().unwrap();
|
|
let seen: BTreeSet<&str> = vectors.iter().filter_map(|v| v["reason"].as_str()).collect();
|
|
for r in Reason::ALL {
|
|
assert!(seen.contains(r.code()), "nothing in the corpus is refused {r}");
|
|
}
|
|
for r in ["classes_summed", "hop_not_authorised", "hop_revoked", "record_missing", "signer_not_authorised", "signer_revoked", "bad_signature"] {
|
|
assert!(seen.contains(r), "nothing in the corpus is refused {r}");
|
|
}
|
|
let get = |n: &str| vectors.iter().find(|v| v["name"] == n).unwrap_or_else(|| panic!("no vector {n}"));
|
|
let first = |n: &str| get(n)["priority"][0].as_str().unwrap().to_string();
|
|
let last = |n: &str| get(n)["priority"].as_array().unwrap().last().unwrap().as_str().unwrap().to_string();
|
|
for (n, why) in [
|
|
("three_metered", "rank"),
|
|
("mixed_classes", "rank"),
|
|
("one_unmetered", "rank"),
|
|
("mixed_hops", "rank"),
|
|
("stale", "rank"),
|
|
("floor_client", "floor"),
|
|
("buffer_guard", "buffer"),
|
|
("hysteresis_hold", "hold"),
|
|
("hysteresis_switch", "rank"),
|
|
("clones", "rank"),
|
|
("share", "share"),
|
|
("share_outside", "rank"),
|
|
("capacity", "rank"),
|
|
("latency", "rank"),
|
|
("per_second", "rank"),
|
|
("dash", "rank"),
|
|
("none_within", "none"),
|
|
] {
|
|
assert_eq!(get(n)["outcome"], "accept", "{n}");
|
|
assert_eq!(get(n)["why"], why, "{n}");
|
|
}
|
|
assert_eq!(first("three_metered"), "tree");
|
|
assert_eq!(get("mixed_classes")["priority"], serde_json::json!(["edge-a", "edge-b", "tree"]), "ordered by class, not by figure");
|
|
for (n, unknown) in [("one_unmetered", "edge-b"), ("mixed_hops", "edge-a"), ("stale", "tree"), ("share_outside", "origin")] {
|
|
assert_eq!(last(n), unknown, "{n}: the pathway with no figure is last");
|
|
}
|
|
assert_eq!(first("share"), "origin", "a minimum share places the unmetered origin path whatever its evidence");
|
|
assert_eq!((first("hysteresis_hold"), first("hysteresis_switch")), ("edge-a".into(), "tree".into()));
|
|
assert_eq!(first("clones"), "edge-a2");
|
|
assert!(get("clones")["steering_manifest"].as_str().unwrap().contains("\"PATHWAY-CLONES\":[{\"BASE-ID\":\"edge-a\",\"ID\":\"edge-a2\""));
|
|
assert_eq!(get("per_second")["priority"], serde_json::json!(["edge-a", "edge-b", "tree"]));
|
|
assert_eq!(get("dash")["inputs"]["protocol"], "dash");
|
|
for n in ["floor_client", "buffer_guard", "none_within"] {
|
|
assert_eq!(get(n)["ttl"], 30, "{n}: the short TTL");
|
|
}
|
|
for (n, p) in doc["policies"].as_object().unwrap() {
|
|
let reads = !["shares_over", "clone_later"].contains(&n.as_str());
|
|
assert_eq!(p["hls_tag"].is_string(), reads, "{n}");
|
|
assert_eq!(p["dash_element"].is_string(), reads, "{n}");
|
|
}
|
|
}
|
|
|
|
/// §10 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/energy-steering.md");
|
|
let at = text.find("\n## 10. Reasons").expect("a §10");
|
|
let end = text[at + 1..].find("\n## ").map_or(text.len(), |e| at + 1 + e);
|
|
let listed: Vec<String> = text[at..end].lines().filter(|l| l.starts_with("| `")).filter_map(|l| l.split('`').nth(1).map(String::from)).collect();
|
|
let want: Vec<String> = Reason::ALL.iter().map(|r| r.code().to_string()).collect();
|
|
assert_eq!(listed, want, "§10's table and Reason::ALL differ");
|
|
}
|