Initial Dever 0.0.1

This commit is contained in:
Codex committed 2026-11-03 03:32:07 +00:00
commit 81233d098c
1479 files changed
+163782

No files matched your search

+159
View File
@@ -0,0 +1,159 @@
use super::{DropNotice, runtime};
use dever_runtime::task::{Error, Timed};
use std::{
future::{Future, poll_fn},
sync::{
Arc,
atomic::{AtomicBool, Ordering},
},
task::Poll,
time::Duration,
};
#[test]
fn dropped_stop_wait_keeps_started_work_tracked() {
let finished = Arc::new(AtomicBool::new(false));
let observed = finished.clone();
let runtime = runtime();
runtime
.run(async |scope| {
let (started, ready) = tokio::sync::oneshot::channel();
let (release, blocked) = std::sync::mpsc::channel();
let task = scope
.spawn_sync(move || {
started.send(()).unwrap();
blocked.recv_timeout(Duration::from_secs(2)).unwrap();
finished.store(true, Ordering::SeqCst);
})
.unwrap();
ready.await.unwrap();
{
let mut stopped = std::pin::pin!(task.stop());
poll_fn(|context| {
assert!(stopped.as_mut().poll(context).is_pending());
Poll::Ready(())
})
.await;
}
assert!(!observed.load(Ordering::SeqCst));
release.send(()).unwrap();
})
.unwrap();
assert!(observed.load(Ordering::SeqCst));
}
#[test]
fn nullable_and_unit_results_are_completions_not_expirations() {
runtime()
.run(async |scope| {
let nullable = scope.spawn_leaf(|| async { None::<i64> }).unwrap();
assert!(matches!(
nullable.timeout(10000).await.unwrap(),
Timed::Ready(None)
));
let unit = scope.spawn_leaf(|| async {}).unwrap();
assert!(matches!(
unit.timeout(10000).await.unwrap(),
Timed::Ready(())
));
let failed = scope
.spawn_leaf(|| async { Err::<i64, _>("original") })
.unwrap();
assert!(matches!(
failed.timeout(10000).await.unwrap(),
Timed::Ready(Err("original"))
));
})
.unwrap();
}
#[test]
fn expiration_and_invalid_duration_wait_for_captured_resources() {
for duration in [-1, 0, 1] {
let dropped = Arc::new(AtomicBool::new(false));
let observed = dropped.clone();
runtime()
.run(async |scope| {
let (started, ready) = tokio::sync::oneshot::channel();
let owner = DropNotice(dropped);
let pending = scope
.spawn_leaf(move || async move {
let _owner = owner;
started.send(()).unwrap();
std::future::pending::<()>().await;
})
.unwrap();
ready.await.unwrap();
let result = pending.timeout(duration).await;
if duration > 0 {
assert!(matches!(result, Ok(Timed::Expired(None))));
} else {
assert!(matches!(result, Err(Error::InvalidTimeout)));
}
assert!(observed.load(Ordering::SeqCst));
})
.unwrap();
}
}
#[test]
fn expiration_preserves_a_late_failure_from_started_blocking_work() {
runtime()
.run(async |scope| {
let (started, ready) = tokio::sync::oneshot::channel();
let (release, blocked) = std::sync::mpsc::channel();
let pending = scope
.spawn_sync(move || {
started.send(()).unwrap();
blocked.recv_timeout(Duration::from_secs(2)).unwrap();
Err::<i64, _>("late failure")
})
.unwrap();
ready.await.unwrap();
let mut timed = std::pin::pin!(pending.timeout(1));
poll_fn(|context| {
assert!(timed.as_mut().poll(context).is_pending());
Poll::Ready(())
})
.await;
tokio::time::sleep(Duration::from_millis(10)).await;
poll_fn(|context| {
assert!(timed.as_mut().poll(context).is_pending());
Poll::Ready(())
})
.await;
release.send(()).unwrap();
assert!(matches!(
timed.await.unwrap(),
Timed::Expired(Some(Err("late failure")))
));
})
.unwrap();
}
#[test]
fn cancelling_a_timeout_wait_drains_the_nested_task() {
let dropped = Arc::new(AtomicBool::new(false));
let observed = dropped.clone();
let (started, ready) = tokio::sync::oneshot::channel();
runtime()
.run(async |scope| {
let parent = scope
.spawn(move |child| async move {
let owner = DropNotice(dropped);
let pending = child
.spawn_leaf(move || async move {
let _owner = owner;
started.send(()).unwrap();
std::future::pending::<()>().await;
})
.unwrap();
pending.timeout(60000).await.unwrap();
})
.unwrap();
ready.await.unwrap();
assert!(parent.stop().await.unwrap().is_none());
assert!(observed.load(Ordering::SeqCst));
})
.unwrap();
}