openpencil/crates/op-host-web/tests/save_payload_contract.rs

116 lines
4.9 KiB
Rust

//! Source-level guardrails for the browser-only Save routing.
//!
//! DOM/XHR behavior still needs browser smoke. These checks keep the large
//! payload lifetime contract visible in native CI.
fn source(name: &str) -> String {
std::fs::read_to_string(format!("{}/src/{name}", env!("CARGO_MANIFEST_DIR")))
.unwrap_or_else(|error| panic!("read {name}: {error}"))
}
#[test]
fn each_save_destination_builds_only_its_own_payload() {
let io = source("dom_io/document_io.rs");
let dispatcher = io
.split("pub(super) fn save_document")
.nth(1)
.and_then(|tail| tail.split("fn save_to_daemon").next())
.expect("save dispatcher");
assert!(dispatcher.contains("if daemon_first"));
assert!(!dispatcher.contains("serialize_save_payload"));
let daemon = io
.split("fn save_to_daemon")
.nth(1)
.and_then(|tail| tail.split("fn enqueue_daemon_save").next())
.expect("daemon save enqueue");
assert!(!daemon.contains("serialize_save_payload"));
assert!(daemon.contains("requested_epoch"));
assert!(daemon.contains("requested_generation"));
assert!(daemon.contains("enqueue_daemon_save"));
let active_daemon = io
.split("fn start_daemon_save")
.nth(1)
.and_then(|tail| tail.split("fn save_to_browser_if_snapshot_current").next())
.expect("active daemon save body");
assert_eq!(active_daemon.matches("serialize_save_payload").count(), 1);
assert!(active_daemon.contains("SavePayloadTarget::Daemon"));
assert!(!active_daemon.contains("SavePayloadTarget::BrowserDownload"));
assert!(!active_daemon.contains("json.clone()"));
assert!(active_daemon.contains("save_to_browser_if_snapshot_current"));
assert!(active_daemon.contains("finish_daemon_save()"));
let release = active_daemon
.find("drop(body)")
.expect("release rejected daemon body");
let sync_fallback = active_daemon
.rfind("save_to_browser_if_snapshot_current(inner")
.expect("synchronous browser fallback");
assert!(release < sync_fallback);
let browser = io
.split("fn save_to_browser<C:")
.nth(1)
.and_then(|tail| tail.split("fn download_saved_document").next())
.expect("browser save body");
assert_eq!(browser.matches("serialize_save_payload").count(), 1);
assert!(browser.contains("SavePayloadTarget::BrowserDownload"));
assert!(!browser.contains("SavePayloadTarget::Daemon"));
}
#[test]
fn daemon_saves_are_single_flight_latest_wins_and_fallback_is_snapshot_scoped() {
let io = source("dom_io/document_io.rs");
let queue = source("file_actions/save_queue.rs");
assert!(io.contains("LatestSaveQueue<DaemonSaveLaunch>"));
assert!(io.contains("queue.borrow_mut().enqueue(launch)"));
assert!(io.contains("queue.borrow_mut().finish()"));
assert!(queue.contains("self.pending = Some(launch)"));
assert!(queue.contains("match self.pending.take()"));
let fallback = io
.split("fn save_to_browser_if_snapshot_current")
.nth(1)
.and_then(|tail| tail.split("fn save_to_browser").next())
.expect("snapshot-scoped browser fallback");
assert!(fallback.contains("save_snapshot_matches_document"));
assert!(fallback.contains("state.document_revision()"));
assert!(fallback.contains("snapshot_epoch"));
assert!(fallback.contains("snapshot_generation"));
assert!(fallback.contains("snapshot_revision"));
assert!(fallback.contains("if current"));
assert!(fallback.contains("save_to_browser(inner)"));
let payload = source("file_actions/save_payload.rs");
let exact_match = payload
.split("pub fn save_snapshot_matches_document")
.nth(1)
.and_then(|tail| tail.split("/// Serialize exactly").next())
.expect("exact fallback identity helper");
assert!(exact_match.contains("save_ack_matches_document"));
assert!(exact_match.contains("live_document_revision == snapshot_document_revision"));
}
#[test]
fn both_payloads_stream_the_borrowed_document_without_an_intermediate_value() {
let payload = source("file_actions/save_payload.rs");
let daemon = payload
.split("fn serialize_daemon_request")
.nth(1)
.and_then(|tail| tail.split("#[derive(Debug)]").next())
.expect("daemon serializer");
let download = payload
.split("fn serialize_download_document")
.nth(1)
.and_then(|tail| tail.split("fn serialize_daemon_request").next())
.expect("download serializer");
assert!(payload.contains("image_table::write_document_with_extension"));
assert!(daemon.contains("write_canonical_document(&mut out, state)"));
assert!(download.contains("write_canonical_document(&mut out, state)"));
assert!(!daemon.contains("serde_json::json!({"));
assert!(!daemon.contains("serde_json::to_value"));
assert!(!download.contains("serde_json::to_value"));
}