use std::cell::Cell;
use std::future::pending;
use std::rc::Rc;
use std::sync::Arc;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::Ordering::Relaxed;
use std::task::Poll;
use std::{collections::HashMap, sync::atomic::AtomicUsize, time::Duration};
use futures::future::poll_fn;
use futures_intrusive::channel::LocalOneshotChannel;
use refault::NodeId;
use refault::executor::{AbortHandle, TaskHandle, spawn};
use refault::id::Id;
use refault::simulator::{Simulator, SimulatorHandle, add_simulator};
use refault::{sim_builder::SimBuilder, time::sleep};
use scopeguard::defer;
#[test]
fn node_task_runs() {
SimBuilder::new_test()
.run(|| async move {
let flag = Arc::new(AtomicBool::new(false));
let flag2 = flag.clone();
NodeId::create_node().spawn(async move {
flag2.store(true, Relaxed);
});
sleep(Duration::from_millis(1)).await;
assert!(flag.load(Relaxed));
})
.unwrap();
}
async fn wake_self() {
poll_fn(|cx| {
cx.waker().wake_by_ref();
Poll::Ready(())
})
.await
}
#[test]
fn wake_and_abort() {
SimBuilder::new_test()
.run(|| async move {
let channel = Rc::new(LocalOneshotChannel::new());
let channel2 = channel.clone();
let task = spawn(async move {
let self_handle: AbortHandle = channel2.receive().await.unwrap();
wake_self().await;
self_handle.abort();
});
channel.send(task.abort_handle()).ok().unwrap();
task.await.unwrap();
})
.unwrap();
}
#[test]
fn abort_and_wake() {
SimBuilder::new_test()
.run(|| async move {
let channel = Rc::new(LocalOneshotChannel::new());
let channel2 = channel.clone();
let task = spawn(async move {
let self_handle: AbortHandle = channel2.receive().await.unwrap();
self_handle.abort();
wake_self().await;
});
channel.send(task.abort_handle()).ok().unwrap();
task.await.unwrap();
})
.unwrap();
}
#[test]
fn elapsed_sim_time() {
let duration = Duration::from_secs(1);
let output = SimBuilder::new_test().run(|| async move { sleep(duration).await });
assert_eq!(output.time_elapsed, duration);
output.unwrap();
}
#[test]
fn id_hashmap() {
SimBuilder::new_test()
.run(|| async {
let map: HashMap<_, _> = (0..10).map(|i| (Id::new(), i)).collect();
for &x in map.values() {
sleep(Duration::from_secs(x)).await;
}
})
.unwrap();
}
#[test]
#[should_panic]
fn global_state() {
static COUNTER: AtomicUsize = AtomicUsize::new(0);
SimBuilder::new_test()
.run(|| async {
sleep(Duration::from_secs(
1 + COUNTER.fetch_add(1, Relaxed) as u64,
))
.await;
})
.unwrap();
}
#[test]
#[should_panic]
fn spawn_on_drop() {
SimBuilder::new_test()
.run(|| async {
defer! {
spawn(async move{panic!()}).detach();
}
pending::<()>().await;
})
.unwrap();
}
struct Sim;
impl Simulator for Sim {}
#[test]
fn simulator_on_drop() {
SimBuilder::new_test()
.run(|| async {
add_simulator(Sim);
defer! {
SimulatorHandle::<Sim>::get().with(|_|{})
}
})
.unwrap();
}
#[test]
#[should_panic]
fn simulator_after_node() {
SimBuilder::new_test()
.run(|| async {
NodeId::create_node();
add_simulator(Sim);
})
.unwrap();
}
#[test]
#[should_panic]
fn simulator_after_stop() {
SimBuilder::new_test()
.run(|| async {
defer! {
add_simulator(Sim);
}
pending::<()>().await
})
.unwrap();
}
#[test]
fn kill_node() {
SimBuilder::new_test()
.run(|| async {
let rc = Rc::new(Cell::new(0));
let spawn_on_new_node = || {
let rc2 = rc.clone();
let node = NodeId::create_node();
node.spawn(async move {
sleep(Duration::from_millis(10)).await;
rc2.set(1);
sleep(Duration::from_millis(10)).await;
});
node
};
let n1 = spawn_on_new_node();
let n2 = spawn_on_new_node();
assert!(Rc::strong_count(&rc) == 3);
n1.stop();
assert!(Rc::strong_count(&rc) == 2);
sleep(Duration::from_millis(15)).await;
n2.stop();
assert!(Rc::strong_count(&rc) == 1);
assert!(rc.get() == 1);
})
.unwrap();
}
#[test]
fn abort_self() {
SimBuilder::new_test()
.run(|| async {
let handle = Rc::new(Cell::new(Option::<TaskHandle<()>>::None));
let h2 = handle.clone();
let task = spawn(async move {
sleep(Duration::from_millis(1)).await;
h2.take().unwrap().abort();
pending::<()>().await;
});
handle.set(Some(task));
sleep(Duration::from_millis(2)).await;
assert!(Rc::strong_count(&handle) == 1);
})
.unwrap();
}