use any_spawner::Executor;
use reactive_graph::{
computed::ArcAsyncDerived, owner::Owner, transition::AsyncTransition,
};
use std::sync::{
Arc,
atomic::{AtomicBool, Ordering},
};
use tokio::sync::Barrier;
#[tokio::test]
async fn transition_waits_for_resource_created_inside() {
_ = Executor::init_tokio();
let owner = Owner::new();
owner.set();
let resolved = Arc::new(AtomicBool::new(false));
let flag = resolved.clone();
let derived = AsyncTransition::run(move || async move {
ArcAsyncDerived::new(move || {
let flag = flag.clone();
async move {
Executor::tick().await;
Executor::tick().await;
flag.store(true, Ordering::SeqCst);
42_u32
}
})
})
.await;
assert!(
resolved.load(Ordering::SeqCst),
"transition returned before its resource resolved"
);
assert_eq!(derived.await, 42);
}
#[tokio::test(flavor = "multi_thread", worker_threads = 4)]
async fn overlapping_transitions_are_isolated() {
_ = Executor::init_tokio();
fn run_one(barrier: Arc<Barrier>) -> tokio::task::JoinHandle<()> {
tokio::spawn(async move {
let owner = Owner::new();
owner.set();
let resolved = Arc::new(AtomicBool::new(false));
let flag = resolved.clone();
AsyncTransition::run(move || async move {
barrier.wait().await;
let derived = ArcAsyncDerived::new(move || {
let flag = flag.clone();
async move {
Executor::tick().await;
Executor::tick().await;
flag.store(true, Ordering::SeqCst);
7_u32
}
});
let v = derived.await;
assert_eq!(v, 7);
})
.await;
assert!(
resolved.load(Ordering::SeqCst),
"transition returned before its own resource resolved"
);
})
}
let barrier = Arc::new(Barrier::new(2));
let t1 = run_one(barrier.clone());
let t2 = run_one(barrier.clone());
t1.await.unwrap();
t2.await.unwrap();
}