177 lines
5.4 KiB
Rust
177 lines
5.4 KiB
Rust
use dever_runtime::{
|
|
channel::{Channel, Error},
|
|
task::{Limits, Runtime},
|
|
};
|
|
use std::{
|
|
future::{Future, poll_fn},
|
|
sync::{
|
|
Arc,
|
|
atomic::{AtomicUsize, Ordering},
|
|
},
|
|
task::Poll,
|
|
};
|
|
|
|
fn runtime() -> Runtime {
|
|
Runtime::new(Limits {
|
|
threads: 2,
|
|
workers: 1,
|
|
tasks: 8,
|
|
})
|
|
.unwrap()
|
|
}
|
|
|
|
async fn pending(future: std::pin::Pin<&mut impl Future>) {
|
|
let mut future = future;
|
|
poll_fn(|context| {
|
|
assert!(future.as_mut().poll(context).is_pending());
|
|
Poll::Ready(())
|
|
})
|
|
.await;
|
|
}
|
|
|
|
#[test]
|
|
fn capacity_is_bounded() {
|
|
for capacity in [-1, 0, 65537] {
|
|
assert!(matches!(
|
|
Channel::<i64>::new(capacity),
|
|
Err(Error::Capacity)
|
|
));
|
|
}
|
|
Channel::<i64>::new(1).unwrap();
|
|
Channel::<i64>::new(65536).unwrap();
|
|
}
|
|
|
|
#[test]
|
|
fn backpressure_preserves_fifo_and_nullable_items() {
|
|
runtime()
|
|
.run(async |_| {
|
|
let channel = Channel::new(1).unwrap();
|
|
channel.send(Some(1)).await.unwrap();
|
|
let mut sent = std::pin::pin!(channel.send(None));
|
|
pending(sent.as_mut()).await;
|
|
assert_eq!(channel.receive().await, Ok(Some(Some(1))));
|
|
sent.await.unwrap();
|
|
let alias = channel.clone();
|
|
alias.close().await.unwrap();
|
|
channel.close().await.unwrap();
|
|
assert_eq!(channel.receive().await, Ok(Some(None)));
|
|
assert_eq!(alias.receive().await, Ok(None));
|
|
})
|
|
.unwrap();
|
|
}
|
|
|
|
#[test]
|
|
fn close_wakes_senders_and_all_receivers_without_discarding_queued_values() {
|
|
runtime()
|
|
.run(async |_| {
|
|
let channel = Channel::new(1).unwrap();
|
|
channel.send(1).await.unwrap();
|
|
let mut sent = std::pin::pin!(channel.send(2));
|
|
pending(sent.as_mut()).await;
|
|
channel.close().await.unwrap();
|
|
assert_eq!(sent.await, Err(Error::Closed));
|
|
assert_eq!(channel.receive().await, Ok(Some(1)));
|
|
assert_eq!(channel.receive().await, Ok(None));
|
|
let empty = Channel::<i64>::new(1).unwrap();
|
|
let mut first = std::pin::pin!(empty.receive());
|
|
let mut second = std::pin::pin!(empty.receive());
|
|
pending(first.as_mut()).await;
|
|
pending(second.as_mut()).await;
|
|
empty.close().await.unwrap();
|
|
assert_eq!(first.await, Ok(None));
|
|
assert_eq!(second.await, Ok(None));
|
|
})
|
|
.unwrap();
|
|
}
|
|
|
|
#[test]
|
|
fn cancelling_waiters_returns_reserved_capacity_and_items() {
|
|
runtime()
|
|
.run(async |_| {
|
|
let channel = Channel::new(1).unwrap();
|
|
channel.send(1).await.unwrap();
|
|
{
|
|
let mut sent = std::pin::pin!(channel.send(2));
|
|
pending(sent.as_mut()).await;
|
|
assert_eq!(channel.receive().await, Ok(Some(1)));
|
|
}
|
|
channel.send(3).await.unwrap();
|
|
assert_eq!(channel.receive().await, Ok(Some(3)));
|
|
{
|
|
let mut received = std::pin::pin!(channel.receive());
|
|
pending(received.as_mut()).await;
|
|
channel.send(4).await.unwrap();
|
|
}
|
|
assert_eq!(channel.receive().await, Ok(Some(4)));
|
|
})
|
|
.unwrap();
|
|
}
|
|
|
|
#[test]
|
|
fn producers_and_consumers_transfer_every_item_once() {
|
|
runtime()
|
|
.run(async |scope| {
|
|
let channel = Channel::new(4).unwrap();
|
|
let mut producers = Vec::new();
|
|
let mut consumers = Vec::new();
|
|
for start in [0, 64] {
|
|
let sender = channel.clone();
|
|
producers.push(
|
|
scope
|
|
.spawn_leaf(move || async move {
|
|
for value in start..start + 64 {
|
|
sender.send(value).await.unwrap();
|
|
}
|
|
})
|
|
.unwrap(),
|
|
);
|
|
let channel = channel.clone();
|
|
consumers.push(
|
|
scope
|
|
.spawn_leaf(move || async move {
|
|
let mut values = Vec::new();
|
|
while let Some(value) = channel.receive().await.unwrap() {
|
|
values.push(value);
|
|
}
|
|
values
|
|
})
|
|
.unwrap(),
|
|
);
|
|
}
|
|
for task in producers {
|
|
task.wait().await.unwrap();
|
|
}
|
|
channel.close().await.unwrap();
|
|
let mut received = Vec::new();
|
|
for task in consumers {
|
|
received.extend(task.wait().await.unwrap());
|
|
}
|
|
received.sort();
|
|
assert_eq!(received, (0..128).collect::<Vec<_>>());
|
|
})
|
|
.unwrap();
|
|
}
|
|
|
|
struct Notice(Arc<AtomicUsize>);
|
|
impl Drop for Notice {
|
|
fn drop(&mut self) {
|
|
self.0.fetch_add(1, Ordering::SeqCst);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn last_alias_releases_nonclone_messages_once() {
|
|
let drops = Arc::new(AtomicUsize::new(0));
|
|
runtime()
|
|
.run(async |_| {
|
|
let channel = Channel::new(1).unwrap();
|
|
channel.send(Notice(drops.clone())).await.unwrap();
|
|
let alias = channel.clone();
|
|
drop(channel);
|
|
assert_eq!(drops.load(Ordering::SeqCst), 0);
|
|
drop(alias);
|
|
assert_eq!(drops.load(Ordering::SeqCst), 1);
|
|
})
|
|
.unwrap();
|
|
}
|