2022-11-19 23:24:28 +00:00
|
|
|
//! Verify that tasks get polled by the virtualdom properly, and that we escape wait_for_work safely
|
2022-11-06 08:48:34 +00:00
|
|
|
|
2024-01-28 09:30:33 +00:00
|
|
|
use std::{sync::atomic::AtomicUsize, time::Duration};
|
|
|
|
|
|
|
|
use dioxus::prelude::*;
|
|
|
|
|
|
|
|
async fn run_vdom(app: fn() -> Element) {
|
|
|
|
let mut dom = VirtualDom::new(app);
|
|
|
|
|
|
|
|
dom.rebuild(&mut dioxus_core::NoOpMutations);
|
|
|
|
|
|
|
|
tokio::select! {
|
|
|
|
_ = dom.wait_for_work() => {}
|
|
|
|
_ = tokio::time::sleep(Duration::from_millis(500)) => {}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2022-11-06 08:48:34 +00:00
|
|
|
#[tokio::test]
|
2024-02-05 20:24:50 +00:00
|
|
|
async fn running_async() {
|
2023-12-17 22:46:32 +00:00
|
|
|
static POLL_COUNT: AtomicUsize = AtomicUsize::new(0);
|
|
|
|
|
2024-01-11 16:48:04 +00:00
|
|
|
fn app() -> Element {
|
2024-01-15 15:05:46 +00:00
|
|
|
use_hook(|| {
|
2024-01-11 21:18:11 +00:00
|
|
|
spawn(async {
|
2023-12-17 22:46:32 +00:00
|
|
|
for x in 0..10 {
|
|
|
|
tokio::time::sleep(Duration::from_micros(50)).await;
|
|
|
|
POLL_COUNT.fetch_add(x, std::sync::atomic::Ordering::Relaxed);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2024-01-11 21:18:11 +00:00
|
|
|
spawn(async {
|
2023-12-17 22:46:32 +00:00
|
|
|
for x in 0..10 {
|
|
|
|
tokio::time::sleep(Duration::from_micros(25)).await;
|
|
|
|
POLL_COUNT.fetch_add(x * 2, std::sync::atomic::Ordering::Relaxed);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2024-02-05 07:03:52 +00:00
|
|
|
rsx!({})
|
2023-12-17 22:46:32 +00:00
|
|
|
}
|
|
|
|
|
2024-01-28 09:30:33 +00:00
|
|
|
run_vdom(app).await;
|
|
|
|
|
|
|
|
// By the time the tasks are finished, we should've accumulated ticks from two tasks
|
|
|
|
// Be warned that by setting the delay to too short, tokio might not schedule in the tasks
|
|
|
|
assert_eq!(
|
|
|
|
POLL_COUNT.fetch_add(0, std::sync::atomic::Ordering::Relaxed),
|
|
|
|
135
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Prove that yield_now doesn't cause a deadlock
|
|
|
|
#[tokio::test]
|
|
|
|
async fn yield_now_works() {
|
|
|
|
thread_local! {
|
|
|
|
static SEQUENCE: std::cell::RefCell<Vec<usize>> = std::cell::RefCell::new(Vec::new());
|
|
|
|
}
|
|
|
|
|
|
|
|
fn app() -> Element {
|
|
|
|
// these two tasks should yield to eachother
|
|
|
|
use_hook(|| {
|
|
|
|
spawn(async move {
|
2024-01-31 01:33:14 +00:00
|
|
|
for _ in 0..10 {
|
2024-01-28 09:30:33 +00:00
|
|
|
tokio::task::yield_now().await;
|
|
|
|
SEQUENCE.with(|s| s.borrow_mut().push(1));
|
|
|
|
}
|
|
|
|
})
|
|
|
|
});
|
|
|
|
|
|
|
|
use_hook(|| {
|
|
|
|
spawn(async move {
|
2024-01-31 01:33:14 +00:00
|
|
|
for _ in 0..10 {
|
2024-01-28 09:30:33 +00:00
|
|
|
tokio::task::yield_now().await;
|
|
|
|
SEQUENCE.with(|s| s.borrow_mut().push(2));
|
|
|
|
}
|
|
|
|
})
|
|
|
|
});
|
|
|
|
|
2024-02-05 07:03:52 +00:00
|
|
|
rsx!({})
|
2024-01-28 09:30:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
run_vdom(app).await;
|
|
|
|
|
|
|
|
SEQUENCE.with(|s| assert_eq!(s.borrow().len(), 20));
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Ensure that calling wait_for_flush waits for dioxus to finish its syncrhonous work
|
|
|
|
#[tokio::test]
|
|
|
|
async fn flushing() {
|
|
|
|
thread_local! {
|
|
|
|
static SEQUENCE: std::cell::RefCell<Vec<usize>> = std::cell::RefCell::new(Vec::new());
|
2024-02-29 17:43:07 +00:00
|
|
|
static BROADCAST: (tokio::sync::broadcast::Sender<()>, tokio::sync::broadcast::Receiver<()>) = tokio::sync::broadcast::channel(1);
|
2024-01-28 09:30:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn app() -> Element {
|
2024-02-29 17:43:07 +00:00
|
|
|
if generation() > 0 {
|
2024-03-04 18:04:09 +00:00
|
|
|
println!("App");
|
2024-02-29 17:43:07 +00:00
|
|
|
SEQUENCE.with(|s| s.borrow_mut().push(0));
|
|
|
|
}
|
2024-03-04 18:04:09 +00:00
|
|
|
use_hook(|| {
|
|
|
|
spawn(async move {
|
|
|
|
needs_update();
|
|
|
|
});
|
|
|
|
});
|
2024-01-28 09:30:33 +00:00
|
|
|
use_hook(|| {
|
|
|
|
spawn(async move {
|
2024-01-31 02:17:45 +00:00
|
|
|
for _ in 0..10 {
|
2024-03-04 18:04:09 +00:00
|
|
|
BROADCAST.with(|b| b.1.resubscribe()).recv().await.unwrap();
|
|
|
|
println!("Task 1 recved");
|
2024-01-28 09:30:33 +00:00
|
|
|
flush_sync().await;
|
2024-03-04 18:04:09 +00:00
|
|
|
println!("Task 1");
|
2024-01-28 09:30:33 +00:00
|
|
|
SEQUENCE.with(|s| s.borrow_mut().push(1));
|
|
|
|
}
|
|
|
|
})
|
|
|
|
});
|
|
|
|
|
|
|
|
use_hook(|| {
|
|
|
|
spawn(async move {
|
2024-01-31 02:17:45 +00:00
|
|
|
for _ in 0..10 {
|
2024-03-04 18:04:09 +00:00
|
|
|
BROADCAST.with(|b| b.1.resubscribe()).recv().await.unwrap();
|
|
|
|
println!("Task 2 recved");
|
2024-01-28 09:30:33 +00:00
|
|
|
flush_sync().await;
|
2024-03-04 18:04:09 +00:00
|
|
|
println!("Task 2");
|
2024-01-28 09:30:33 +00:00
|
|
|
SEQUENCE.with(|s| s.borrow_mut().push(2));
|
|
|
|
}
|
|
|
|
})
|
|
|
|
});
|
|
|
|
|
2024-02-29 17:43:07 +00:00
|
|
|
rsx! {}
|
2024-01-28 09:30:33 +00:00
|
|
|
}
|
|
|
|
|
2022-11-06 08:48:34 +00:00
|
|
|
let mut dom = VirtualDom::new(app);
|
|
|
|
|
2024-01-15 17:06:27 +00:00
|
|
|
dom.rebuild(&mut dioxus_core::NoOpMutations);
|
2022-11-06 08:48:34 +00:00
|
|
|
|
2024-01-28 09:30:33 +00:00
|
|
|
let fut = async {
|
|
|
|
// Trigger the flush by waiting for work
|
2024-03-01 18:46:07 +00:00
|
|
|
for _ in 0..30 {
|
2024-02-29 17:43:07 +00:00
|
|
|
BROADCAST.with(|b| b.0.send(()).unwrap());
|
2024-03-04 18:04:09 +00:00
|
|
|
dom.mark_dirty(ScopeId(0));
|
|
|
|
tokio::select! {
|
|
|
|
_ = dom.wait_for_work() => {}
|
|
|
|
_ = tokio::time::sleep(Duration::from_millis(10)) => {}
|
|
|
|
}
|
2024-02-29 17:43:07 +00:00
|
|
|
dom.render_immediate(&mut dioxus_core::NoOpMutations);
|
2024-03-04 18:04:09 +00:00
|
|
|
println!("Flushed");
|
2024-01-28 09:30:33 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2022-11-12 02:29:27 +00:00
|
|
|
tokio::select! {
|
2024-01-28 09:30:33 +00:00
|
|
|
_ = fut => {}
|
2024-03-04 18:04:09 +00:00
|
|
|
_ = tokio::time::sleep(Duration::from_millis(500)) => {
|
|
|
|
println!("Aborting due to timeout");
|
|
|
|
}
|
2022-11-12 02:29:27 +00:00
|
|
|
};
|
2022-11-24 07:15:01 +00:00
|
|
|
|
2024-02-29 17:43:07 +00:00
|
|
|
SEQUENCE.with(|s| {
|
|
|
|
let s = s.borrow();
|
|
|
|
println!("{:?}", s);
|
|
|
|
assert_eq!(s.len(), 30);
|
|
|
|
// We need to check if every three elements look like [0, 1, 2] or [0, 2, 1]
|
|
|
|
let mut has_seen_1 = false;
|
|
|
|
for (i, &x) in s.iter().enumerate() {
|
|
|
|
let stage = i % 3;
|
|
|
|
if stage == 0 {
|
|
|
|
assert_eq!(x, 0);
|
|
|
|
} else if stage == 1 {
|
|
|
|
assert!(x == 1 || x == 2);
|
|
|
|
has_seen_1 = x == 1;
|
|
|
|
} else if stage == 2 {
|
|
|
|
if has_seen_1 {
|
|
|
|
assert_eq!(x, 2);
|
|
|
|
} else {
|
|
|
|
assert_eq!(x, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
2022-11-06 08:48:34 +00:00
|
|
|
}
|