Files
improvise/crates/improvise-incremental/tests/sched_drop.rs
T

88 lines
2.4 KiB
Rust

//! A unit that panics again when it is dropped must not cost the pool a worker.
//! Evidence: `context/test-evidence/improvise-incremental.md`.
mod support;
use improvise_incremental::sched::{Executor, Pool, Turn, Unit};
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
use support::watchdog::within;
/// A unit that panics in its turn and again when it is dropped by the unwind's aftermath.
struct BoomTwice;
impl Unit for BoomTwice {
fn turn(&mut self, _: usize) -> Turn {
panic!("boom in the turn");
}
fn neighbours(&self) -> &[usize] {
&[]
}
}
impl Drop for BoomTwice {
fn drop(&mut self) {
if !std::thread::panicking() {
panic!("boom in the drop");
}
}
}
struct Count(Arc<AtomicUsize>);
impl Unit for Count {
fn turn(&mut self, _: usize) -> Turn {
self.0.fetch_add(1, Ordering::SeqCst);
Turn {
progress: false,
more: false,
}
}
fn neighbours(&self) -> &[usize] {
&[]
}
}
#[test]
fn a_unit_whose_drop_panics_does_not_hang_or_shrink_the_pool() {
let turns = Arc::new(AtomicUsize::new(0));
let t = turns.clone();
let (err, workers) = within(5, "a pool with a unit that panics in its drop", move || {
let units: Vec<Box<dyn Unit>> = vec![Box::new(BoomTwice), Box::new(Count(t))];
let exec = Arc::new(Executor::new(units, 1));
let pool = Pool::start(exec.clone(), 1);
exec.kick(0);
exec.kick(1);
let idle = exec.wait_idle();
let workers = exec.workers();
let _ = pool.finish();
(idle.err(), workers)
});
assert_eq!(
workers, 1,
"[drop] the only worker survived the dead unit's drop"
);
assert_eq!(err.map(|e| e.unit), Some(0));
assert_eq!(
turns.load(Ordering::SeqCst),
1,
"[drop] the other unit still ran"
);
}
#[test]
fn dropping_a_pool_while_unwinding_does_not_abort() {
within(5, "unwinding past a pool", || {
let exec = Arc::new(Executor::new(vec![Box::new(BoomTwice)], 1));
let r = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
let _pool = Pool::start(exec.clone(), 1);
exec.kick(0);
let _ = exec.wait_idle();
panic!("the host fails with a pool alive");
}));
assert!(r.is_err());
});
}