use super::*;
use crate::{BoxFuture, CordisError, Effect, Plugin};
use std::time::Duration;
struct Noop;
impl Plugin for Noop {
fn name(&self) -> &str {
"noop"
}
fn apply<'a>(&'a self, _ctx: &'a Ctx) -> BoxFuture<'a, Result<Effect, CordisError>> {
Box::pin(async { Ok(Effect::Done) })
}
}
#[tokio::test]
async fn churn_mount_records_release_from_root() {
let ctx = Ctx::root().expect("runtime in scope");
let root = ctx.weak_fiber().upgrade().expect("root alive");
for _ in 0..25 {
let view = ctx.plugin(Noop);
view.dispose().await.unwrap();
drop(view);
}
for _ in 0..500 {
if root.effects.lock().unwrap().is_empty() {
break;
}
tokio::time::sleep(Duration::from_millis(2)).await;
}
assert!(
root.effects.lock().unwrap().is_empty(),
"mount records must not accumulate on a long-lived root"
);
}
#[tokio::test]
async fn churn_root_provides_release_accounting() {
let ctx = Ctx::root().expect("runtime in scope");
let root = ctx.weak_fiber().upgrade().expect("root alive");
for i in 0..25 {
let key = TypeKey::keyed_dynamic::<u32>(format!("svc/{i}"));
let disposer = ctx.provide_as::<u32>(key, Arc::new(i)).unwrap();
disposer.dispose().await.unwrap();
}
assert!(
root.provided.lock().unwrap().is_empty(),
"provided accounting must shrink per released binding"
);
assert!(
root.effects.lock().unwrap().is_empty(),
"evict cleanups must self-remove after drain"
);
}