use r#continue::continuation;
use exfiltrate_internal::command::{Command, Response};
use exfiltrate_internal::snapshot::{SnapshotRow, SnapshotSet, SnapshotValue};
fn ask(args: &[&str]) -> SnapshotSet {
r#continue::exfiltrate_provider::install();
let response = exfiltrate::provider::Snapshot
.execute(args.iter().map(|arg| arg.to_string()).collect())
.expect("snapshot should not fail");
match response {
Response::Bytes(bytes) => rmp_serde::from_slice(&bytes).expect("decode"),
other => panic!("expected a structured response, got {other:?}"),
}
}
fn newest() -> SnapshotRow {
let set = ask(&["--subsystem", "continuations"]);
set.snapshots[0]
.rows
.last()
.cloned()
.expect("at least one continuation")
}
fn row_for(id: u64) -> SnapshotRow {
let set = ask(&["--subsystem", "continuations", "--id", &id.to_string()]);
assert_eq!(set.snapshots[0].returned, 1, "{:?}", set.snapshots[0]);
set.snapshots[0].rows[0].clone()
}
fn u64_of(row: &SnapshotRow, name: &str) -> u64 {
match row.get(name).unwrap().value {
Some(SnapshotValue::U64(value)) => value,
ref other => panic!("{name} was {other:?}"),
}
}
fn str_of(row: &SnapshotRow, name: &str) -> String {
match row.get(name).unwrap().value {
Some(SnapshotValue::String(ref value)) => value.clone(),
ref other => panic!("{name} was {other:?}"),
}
}
#[wasm_lite::wasm_lite_test]
fn the_registry_reports_what_happened_to_each_continuation() {
let (sender, future) = continuation::<u32>();
let row = newest();
let outstanding_id = u64_of(&row, "id");
assert_eq!(str_of(&row, "outcome"), "outstanding");
assert!(
str_of(&row, "created_at_file").ends_with("registry.rs"),
"the creation site should be this file, not inside the crate: {:?}",
str_of(&row, "created_at_file")
);
assert!(u64_of(&row, "created_at_line") > 0);
assert_eq!(
row.get("polled").unwrap().value,
Some(SnapshotValue::Bool(false)),
"nobody is awaiting it yet, which is a different bug from a signal that never came"
);
assert!(row.get("context").is_some());
sender.send(7);
assert_eq!(wasm_lite_std::block_on(future), 7);
let row = row_for(outstanding_id);
assert_eq!(
row.get("polled").unwrap().value,
Some(SnapshotValue::Bool(true))
);
assert_eq!(str_of(&row, "outcome"), "sent");
let (sender, future) = continuation::<u32>();
let second_id = u64_of(&newest(), "id");
assert_ne!(second_id, outstanding_id);
drop(future);
assert_eq!(str_of(&row_for(second_id), "outcome"), "future-hung-up");
sender.send(1);
#[cfg(not(target_arch = "wasm32"))]
{
let (sender, _future) = continuation::<u32>();
let id = u64_of(&newest(), "id");
let previous = std::panic::take_hook();
std::panic::set_hook(Box::new(|_| {}));
let caught = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| drop(sender)));
std::panic::set_hook(previous);
assert!(caught.is_err(), "dropping a sender unsent should panic");
assert_eq!(str_of(&row_for(id), "outcome"), "sender-dropped-unsent");
}
}