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

+311
View File
@@ -0,0 +1,311 @@
use super::*;
use std::sync::atomic::{AtomicUsize, Ordering};
use tokio::sync::Notify;
struct Running(Arc<AtomicUsize>);
impl Drop for Running {
fn drop(&mut self) {
self.0.fetch_sub(1, Ordering::SeqCst);
}
}
#[test]
fn timeout_and_stop_drain_handler_descendants() {
runtime()
.run(async |scope| {
for cancel in [false, true] {
let listener = net::listen("127.0.0.1", 0, scope).await.unwrap();
let port = listener.port().unwrap();
let incoming = listener.clone();
let running = Arc::new(AtomicUsize::new(0));
let live = running.clone();
let started = Arc::new(Notify::new());
let ready = started.clone();
let server = scope
.spawn(move |child| async move {
let limits = Limits {
timeout_ms: if cancel { 5000 } else { 100 },
..Limits::default()
};
http::serve::<_, _, true>(
&incoming,
&limits,
&child,
move |request, scope| {
let live = live.clone();
let ready = ready.clone();
async move {
let pending = scope
.spawn_leaf(move || async move {
live.fetch_add(1, Ordering::SeqCst);
let _running = Running(live);
ready.notify_one();
std::future::pending::<()>().await;
})
.unwrap();
pending.wait().await.unwrap();
route(request, scope).await
}
},
)
.await
})
.unwrap();
let client = scope
.spawn_leaf(move || async move {
http::send("127.0.0.1", port, request("/", b""), &Limits::default()).await
})
.unwrap();
tokio::time::timeout(Duration::from_secs(3), started.notified())
.await
.unwrap();
assert_eq!(running.load(Ordering::SeqCst), 1);
if cancel {
server.stop().await.unwrap();
assert!(client.wait().await.unwrap().is_err());
listener.close().unwrap();
} else {
assert_eq!(client.wait().await.unwrap().unwrap().status, 504);
listener.close().unwrap();
server.wait().await.unwrap().unwrap();
}
assert_eq!(running.load(Ordering::SeqCst), 0);
}
})
.unwrap();
}
#[test]
fn closing_listener_drains_an_inflight_response() {
runtime()
.run(async |scope| {
let listener = net::listen("127.0.0.1", 0, scope).await.unwrap();
let port = listener.port().unwrap();
let incoming = listener.clone();
let started = Arc::new(Notify::new());
let ready = started.clone();
let release = Arc::new(Notify::new());
let released = release.clone();
let server = scope
.spawn(move |child| async move {
http::serve::<_, _, false>(
&incoming,
&Limits::default(),
&child,
move |request, scope| {
let ready = ready.clone();
let released = released.clone();
async move {
ready.notify_one();
released.notified().await;
route(request, scope).await
}
},
)
.await
})
.unwrap();
let client = scope
.spawn_leaf(move || async move {
http::send(
"127.0.0.1",
port,
request("/", b"drained"),
&Limits::default(),
)
.await
})
.unwrap();
tokio::time::timeout(Duration::from_secs(3), started.notified())
.await
.unwrap();
listener.close().unwrap();
release.notify_one();
assert_eq!(
client.wait().await.unwrap().unwrap().body.as_ref(),
b"drained"
);
tokio::time::timeout(Duration::from_secs(3), server.wait())
.await
.unwrap()
.unwrap()
.unwrap();
})
.unwrap();
}
#[test]
fn client_deadline_drops_its_connection_driver() {
runtime()
.run(async |scope| {
let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap();
let port = i64::from(listener.local_addr().unwrap().port());
let peer = scope
.spawn(move |child| async move {
let (stream, _) = listener.accept().await.unwrap();
let mut stream = stream.into_std().unwrap();
stream.set_nonblocking(false).unwrap();
stream
.set_read_timeout(Some(Duration::from_secs(3)))
.unwrap();
child
.blocking(move || {
let mut data = Vec::new();
stream.read_to_end(&mut data).unwrap();
assert!(data.starts_with(b"POST / HTTP/1.1"));
})
.await
.unwrap();
})
.unwrap();
let limits = Limits {
timeout_ms: 100,
..Limits::default()
};
let error = http::send("127.0.0.1", port, request("/", b""), &limits)
.await
.unwrap_err();
assert_eq!(error, "HTTP request timed out");
peer.wait().await.unwrap();
})
.unwrap();
}
#[test]
fn invalid_service_configuration_keeps_listener_available() {
runtime()
.run(async |scope| {
let listener = net::listen("127.0.0.1", 0, scope).await.unwrap();
let limits = Limits {
connections: 0,
..Limits::default()
};
assert_eq!(
http::serve::<_, _, false>(&listener, &limits, scope, route).await,
Err(http::ServeError::Limits)
);
assert!(listener.port().unwrap() > 0);
listener.close().unwrap();
assert_eq!(
http::serve::<_, _, false>(&listener, &Limits::default(), scope, route).await,
Err(http::ServeError::Listener)
);
})
.unwrap();
}
#[test]
fn exhausted_task_pool_preserves_connections_and_resumes_accepting() {
capacity_recovery(CapacityAction::Resume);
}
#[test]
fn closing_listener_interrupts_waiting_for_task_capacity() {
capacity_recovery(CapacityAction::Close);
}
#[test]
fn cancelling_server_interrupts_waiting_for_task_capacity() {
capacity_recovery(CapacityAction::Cancel);
}
enum CapacityAction {
Resume,
Close,
Cancel,
}
fn capacity_recovery(action: CapacityAction) {
use http_body_util::{BodyExt, Empty};
use hyper_util::rt::TokioIo;
Runtime::new(dever_runtime::task::Limits {
threads: 2,
workers: 1,
tasks: 3,
})
.unwrap()
.run(async |scope| {
let listener = net::listen("127.0.0.1", 0, scope).await.unwrap();
let port = listener.port().unwrap() as u16;
let incoming = listener.clone();
let server = scope
.spawn(move |child| async move {
http::serve::<_, _, false>(&incoming, &Limits::default(), &child, route).await
})
.unwrap();
let mut clients = Vec::new();
let mut drivers = Vec::new();
for _ in 0..3 {
let socket = tokio::net::TcpStream::connect(("127.0.0.1", port))
.await
.unwrap();
let (sender, connection) = hyper::client::conn::http1::handshake(TokioIo::new(socket))
.await
.unwrap();
clients.push(sender);
drivers.push(tokio::spawn(connection));
}
let request = || {
hyper::Request::builder()
.uri("/echo")
.header("host", "fixture.test")
.body(Empty::<bytes::Bytes>::new())
.unwrap()
};
for client in &mut clients[..2] {
let response = client.send_request(request()).await.unwrap();
assert_eq!(response.status(), 200);
response.into_body().collect().await.unwrap();
}
let mut waiting = Box::pin(clients[2].send_request(request()));
assert!(
tokio::time::timeout(Duration::from_millis(100), &mut waiting)
.await
.is_err()
);
if matches!(action, CapacityAction::Resume) {
let response = clients[0].send_request(request()).await.unwrap();
assert_eq!(response.status(), 200);
response.into_body().collect().await.unwrap();
drivers[0].abort();
let response = tokio::time::timeout(Duration::from_secs(3), &mut waiting)
.await
.unwrap()
.unwrap();
assert_eq!(response.status(), 200);
response.into_body().collect().await.unwrap();
}
if matches!(action, CapacityAction::Cancel) {
tokio::time::timeout(Duration::from_secs(3), server.stop())
.await
.unwrap()
.unwrap();
listener.close().unwrap();
} else {
listener.close().unwrap();
tokio::time::timeout(Duration::from_secs(3), server.wait())
.await
.unwrap()
.unwrap()
.unwrap();
}
drop(waiting);
drop(clients);
for driver in drivers {
driver.abort();
let _ = driver.await;
}
assert_eq!(
scope
.spawn_leaf(|| async { 42 })
.unwrap()
.wait()
.await
.unwrap(),
42
);
})
.unwrap();
}