#![cfg(feature = "revocation-view")]
#![allow(clippy::unwrap_used, clippy::expect_used)]
use std::sync::Arc;
use std::thread;
use chio_kernel_core::{RevocationSnapshot, RevocationView, RevocationViewSubject};
fn snapshot(epoch: u64, revoked: &[&str]) -> RevocationSnapshot {
let revoked_set = revoked
.iter()
.copied()
.map(RevocationViewSubject::from)
.collect();
RevocationSnapshot {
epoch,
root_hash: [(epoch as u8); 32],
issued_at_unix_ms: 1_700_000_000_000 + epoch,
revoked: revoked_set,
}
}
#[test]
fn concurrent_readers_observe_consistent_snapshot() {
let view = Arc::new(RevocationView::new());
view.install_if_newer(snapshot(1, &["s-1"])).unwrap();
let writer_view = Arc::clone(&view);
let writer = thread::spawn(move || {
for epoch in 2..=200 {
let label = format!("s-{}", epoch);
let leaked: &'static str = Box::leak(label.into_boxed_str());
writer_view
.install_if_newer(snapshot(epoch, &[leaked]))
.unwrap();
}
});
let mut reader_handles = Vec::new();
for _ in 0..4 {
let reader_view = Arc::clone(&view);
reader_handles.push(thread::spawn(move || {
for _ in 0..1_000 {
let snap = reader_view.load();
if snap.epoch == 0 {
continue;
}
let expected = format!("s-{}", snap.epoch);
let subject = RevocationViewSubject::from(expected.as_str());
assert!(
snap.is_revoked(&subject),
"snapshot at epoch {} missing self-consistent label",
snap.epoch
);
}
}));
}
writer.join().unwrap();
for handle in reader_handles {
handle.join().unwrap();
}
assert_eq!(view.current_epoch(), 200);
}