sync: move into tokio crate (#1705)

A step towards collapsing Tokio sub crates into a single `tokio`
crate (#1318).

The sync implementation is now provided by the main `tokio` crate.
Functionality can be opted out of by using the various net related
feature flags.
This commit is contained in:
Carl Lerche
2019-10-29 15:11:31 -07:00
committed by GitHub
parent c62ef2d232
commit 2b909d6805
58 changed files with 574 additions and 1195 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
use tokio_sync::oneshot;
use tokio::sync::oneshot;
use std::cell::RefCell;
use std::collections::VecDeque;
+38
View File
@@ -0,0 +1,38 @@
#![warn(rust_2018_idioms)]
use tokio::sync::AtomicWaker;
use tokio_test::task::MockTask;
use std::task::Waker;
trait AssertSend: Send {}
trait AssertSync: Send {}
impl AssertSend for AtomicWaker {}
impl AssertSync for AtomicWaker {}
impl AssertSend for Waker {}
impl AssertSync for Waker {}
#[test]
fn basic_usage() {
let waker = AtomicWaker::new();
let mut task = MockTask::new();
task.enter(|cx| waker.register_by_ref(cx.waker()));
waker.wake();
assert!(task.is_woken());
}
#[test]
fn wake_without_register() {
let waker = AtomicWaker::new();
waker.wake();
// Registering should not result in a notification
let mut task = MockTask::new();
task.enter(|cx| waker.register_by_ref(cx.waker()));
assert!(!task.is_woken());
}
+94
View File
@@ -0,0 +1,94 @@
#![warn(rust_2018_idioms)]
use tokio::sync::Barrier;
use tokio_test::task::spawn;
use tokio_test::{assert_pending, assert_ready};
struct IsSend<T: Send>(T);
#[test]
fn barrier_future_is_send() {
let b = Barrier::new(0);
IsSend(b.wait());
}
#[test]
fn zero_does_not_block() {
let b = Barrier::new(0);
{
let mut w = spawn(b.wait());
let wr = assert_ready!(w.poll());
assert!(wr.is_leader());
}
{
let mut w = spawn(b.wait());
let wr = assert_ready!(w.poll());
assert!(wr.is_leader());
}
}
#[test]
fn single() {
let b = Barrier::new(1);
{
let mut w = spawn(b.wait());
let wr = assert_ready!(w.poll());
assert!(wr.is_leader());
}
{
let mut w = spawn(b.wait());
let wr = assert_ready!(w.poll());
assert!(wr.is_leader());
}
{
let mut w = spawn(b.wait());
let wr = assert_ready!(w.poll());
assert!(wr.is_leader());
}
}
#[test]
fn tango() {
let b = Barrier::new(2);
let mut w1 = spawn(b.wait());
assert_pending!(w1.poll());
let mut w2 = spawn(b.wait());
let wr2 = assert_ready!(w2.poll());
let wr1 = assert_ready!(w1.poll());
assert!(wr1.is_leader() || wr2.is_leader());
assert!(!(wr1.is_leader() && wr2.is_leader()));
}
#[test]
fn lots() {
let b = Barrier::new(100);
for _ in 0..10 {
let mut wait = Vec::new();
for _ in 0..99 {
let mut w = spawn(b.wait());
assert_pending!(w.poll());
wait.push(w);
}
for w in &mut wait {
assert_pending!(w.poll());
}
// pass the barrier
let mut w = spawn(b.wait());
let mut found_leader = assert_ready!(w.poll()).is_leader();
for mut w in wait {
let wr = assert_ready!(w.poll());
if wr.is_leader() {
assert!(!found_leader);
found_leader = true;
}
}
assert!(found_leader);
}
}
+29
View File
@@ -0,0 +1,29 @@
#![warn(rust_2018_idioms)]
fn is_error<T: ::std::error::Error + Send + Sync>() {}
#[test]
fn mpsc_error_bound() {
use tokio::sync::mpsc::error;
is_error::<error::SendError>();
is_error::<error::TrySendError<()>>();
is_error::<error::UnboundedRecvError>();
is_error::<error::UnboundedSendError>();
is_error::<error::UnboundedTrySendError<()>>();
}
#[test]
fn oneshot_error_bound() {
use tokio::sync::oneshot::error;
is_error::<error::RecvError>();
is_error::<error::TryRecvError>();
}
#[test]
fn watch_error_bound() {
use tokio::sync::watch::error;
is_error::<error::SendError<()>>();
}
+451
View File
@@ -0,0 +1,451 @@
#![warn(rust_2018_idioms)]
use tokio::sync::mpsc;
use tokio_test::task::MockTask;
use tokio_test::{
assert_err, assert_ok, assert_pending, assert_ready, assert_ready_err, assert_ready_ok,
};
use std::sync::Arc;
trait AssertSend: Send {}
impl AssertSend for mpsc::Sender<i32> {}
impl AssertSend for mpsc::Receiver<i32> {}
#[test]
fn send_recv_with_buffer() {
let mut t1 = MockTask::new();
let mut t2 = MockTask::new();
let (mut tx, mut rx) = mpsc::channel::<i32>(16);
// Using poll_ready / try_send
assert_ready_ok!(t1.enter(|cx| tx.poll_ready(cx)));
tx.try_send(1).unwrap();
// Without poll_ready
tx.try_send(2).unwrap();
drop(tx);
let val = assert_ready!(t2.enter(|cx| rx.poll_recv(cx)));
assert_eq!(val, Some(1));
let val = assert_ready!(t2.enter(|cx| rx.poll_recv(cx)));
assert_eq!(val, Some(2));
let val = assert_ready!(t2.enter(|cx| rx.poll_recv(cx)));
assert!(val.is_none());
}
#[tokio::test]
async fn async_send_recv_with_buffer() {
let (mut tx, mut rx) = mpsc::channel(16);
tokio::spawn(async move {
assert_ok!(tx.send(1).await);
assert_ok!(tx.send(2).await);
});
assert_eq!(Some(1), rx.recv().await);
assert_eq!(Some(2), rx.recv().await);
assert_eq!(None, rx.recv().await);
}
#[test]
fn send_sink_recv_with_buffer() {
use futures_core::Stream;
use futures_sink::Sink;
use futures_util::pin_mut;
let mut t1 = MockTask::new();
let (tx, rx) = mpsc::channel::<i32>(16);
t1.enter(|cx| {
pin_mut!(tx);
assert_ready_ok!(tx.as_mut().poll_ready(cx));
assert_ok!(tx.as_mut().start_send(1));
assert_ready_ok!(tx.as_mut().poll_ready(cx));
assert_ok!(tx.as_mut().start_send(2));
assert_ready_ok!(tx.as_mut().poll_flush(cx));
assert_ready_ok!(tx.as_mut().poll_close(cx));
});
t1.enter(|cx| {
pin_mut!(rx);
let val = assert_ready!(rx.as_mut().poll_next(cx));
assert_eq!(val, Some(1));
let val = assert_ready!(rx.as_mut().poll_next(cx));
assert_eq!(val, Some(2));
let val = assert_ready!(rx.as_mut().poll_next(cx));
assert!(val.is_none());
});
}
#[test]
fn start_send_past_cap() {
let mut t1 = MockTask::new();
let mut t2 = MockTask::new();
let mut t3 = MockTask::new();
let (mut tx1, mut rx) = mpsc::channel(1);
let mut tx2 = tx1.clone();
assert_ok!(tx1.try_send(()));
t1.enter(|cx| {
assert_pending!(tx1.poll_ready(cx));
});
t2.enter(|cx| {
assert_pending!(tx2.poll_ready(cx));
});
drop(tx1);
let val = t3.enter(|cx| assert_ready!(rx.poll_recv(cx)));
assert!(val.is_some());
assert!(t2.is_woken());
assert!(!t1.is_woken());
drop(tx2);
let val = t3.enter(|cx| assert_ready!(rx.poll_recv(cx)));
assert!(val.is_none());
}
#[test]
#[should_panic]
fn buffer_gteq_one() {
mpsc::channel::<i32>(0);
}
#[test]
fn send_recv_unbounded() {
let mut t1 = MockTask::new();
let (mut tx, mut rx) = mpsc::unbounded_channel::<i32>();
// Using `try_send`
assert_ok!(tx.try_send(1));
assert_ok!(tx.try_send(2));
let val = assert_ready!(t1.enter(|cx| rx.poll_recv(cx)));
assert_eq!(val, Some(1));
let val = assert_ready!(t1.enter(|cx| rx.poll_recv(cx)));
assert_eq!(val, Some(2));
drop(tx);
let val = assert_ready!(t1.enter(|cx| rx.poll_recv(cx)));
assert!(val.is_none());
}
#[tokio::test]
async fn async_send_recv_unbounded() {
let (mut tx, mut rx) = mpsc::unbounded_channel();
tokio::spawn(async move {
assert_ok!(tx.try_send(1));
assert_ok!(tx.try_send(2));
});
assert_eq!(Some(1), rx.recv().await);
assert_eq!(Some(2), rx.recv().await);
assert_eq!(None, rx.recv().await);
}
#[test]
fn sink_send_recv_unbounded() {
use futures_core::Stream;
use futures_sink::Sink;
use futures_util::pin_mut;
let mut t1 = MockTask::new();
let (tx, rx) = mpsc::unbounded_channel::<i32>();
t1.enter(|cx| {
pin_mut!(tx);
assert_ready_ok!(tx.as_mut().poll_ready(cx));
assert_ok!(tx.as_mut().start_send(1));
assert_ready_ok!(tx.as_mut().poll_ready(cx));
assert_ok!(tx.as_mut().start_send(2));
assert_ready_ok!(tx.as_mut().poll_flush(cx));
assert_ready_ok!(tx.as_mut().poll_close(cx));
});
t1.enter(|cx| {
pin_mut!(rx);
let val = assert_ready!(rx.as_mut().poll_next(cx));
assert_eq!(val, Some(1));
let val = assert_ready!(rx.as_mut().poll_next(cx));
assert_eq!(val, Some(2));
let val = assert_ready!(rx.as_mut().poll_next(cx));
assert!(val.is_none());
});
}
#[test]
fn no_t_bounds_buffer() {
struct NoImpls;
let mut t1 = MockTask::new();
let (tx, mut rx) = mpsc::channel(100);
// sender should be Debug even though T isn't Debug
println!("{:?}", tx);
// same with Receiver
println!("{:?}", rx);
// and sender should be Clone even though T isn't Clone
assert!(tx.clone().try_send(NoImpls).is_ok());
let val = assert_ready!(t1.enter(|cx| rx.poll_recv(cx)));
assert!(val.is_some());
}
#[test]
fn no_t_bounds_unbounded() {
struct NoImpls;
let mut t1 = MockTask::new();
let (tx, mut rx) = mpsc::unbounded_channel();
// sender should be Debug even though T isn't Debug
println!("{:?}", tx);
// same with Receiver
println!("{:?}", rx);
// and sender should be Clone even though T isn't Clone
assert!(tx.clone().try_send(NoImpls).is_ok());
let val = assert_ready!(t1.enter(|cx| rx.poll_recv(cx)));
assert!(val.is_some());
}
#[test]
fn send_recv_buffer_limited() {
let mut t1 = MockTask::new();
let mut t2 = MockTask::new();
let (mut tx, mut rx) = mpsc::channel::<i32>(1);
// Run on a task context
t1.enter(|cx| {
assert_ready_ok!(tx.poll_ready(cx));
// Send first message
assert_ok!(tx.try_send(1));
// Not ready
assert_pending!(tx.poll_ready(cx));
// Send second message
assert_err!(tx.try_send(1337));
});
t2.enter(|cx| {
// Take the value
let val = assert_ready!(rx.poll_recv(cx));
assert_eq!(Some(1), val);
});
assert!(t1.is_woken());
t1.enter(|cx| {
assert_ready_ok!(tx.poll_ready(cx));
assert_ok!(tx.try_send(2));
// Not ready
assert_pending!(tx.poll_ready(cx));
});
t2.enter(|cx| {
// Take the value
let val = assert_ready!(rx.poll_recv(cx));
assert_eq!(Some(2), val);
});
t1.enter(|cx| {
assert_ready_ok!(tx.poll_ready(cx));
});
}
#[test]
fn recv_close_gets_none_idle() {
let mut t1 = MockTask::new();
let (mut tx, mut rx) = mpsc::channel::<i32>(10);
rx.close();
t1.enter(|cx| {
let val = assert_ready!(rx.poll_recv(cx));
assert!(val.is_none());
assert_ready_err!(tx.poll_ready(cx));
});
}
#[test]
fn recv_close_gets_none_reserved() {
let mut t1 = MockTask::new();
let mut t2 = MockTask::new();
let mut t3 = MockTask::new();
let (mut tx1, mut rx) = mpsc::channel::<i32>(1);
let mut tx2 = tx1.clone();
assert_ready_ok!(t1.enter(|cx| tx1.poll_ready(cx)));
t2.enter(|cx| {
assert_pending!(tx2.poll_ready(cx));
});
rx.close();
assert!(t2.is_woken());
t2.enter(|cx| {
assert_ready_err!(tx2.poll_ready(cx));
});
t3.enter(|cx| assert_pending!(rx.poll_recv(cx)));
assert!(!t1.is_woken());
assert!(!t2.is_woken());
assert_ok!(tx1.try_send(123));
assert!(t3.is_woken());
t3.enter(|cx| {
let v = assert_ready!(rx.poll_recv(cx));
assert_eq!(v, Some(123));
let v = assert_ready!(rx.poll_recv(cx));
assert!(v.is_none());
});
}
#[test]
fn tx_close_gets_none() {
let mut t1 = MockTask::new();
let (_, mut rx) = mpsc::channel::<i32>(10);
// Run on a task context
t1.enter(|cx| {
let v = assert_ready!(rx.poll_recv(cx));
assert!(v.is_none());
});
}
#[test]
fn try_send_fail() {
let mut t1 = MockTask::new();
let (mut tx, mut rx) = mpsc::channel(1);
tx.try_send("hello").unwrap();
// This should fail
let err = assert_err!(tx.try_send("fail"));
assert!(err.is_full());
let val = assert_ready!(t1.enter(|cx| rx.poll_recv(cx)));
assert_eq!(val, Some("hello"));
assert_ok!(tx.try_send("goodbye"));
drop(tx);
let val = assert_ready!(t1.enter(|cx| rx.poll_recv(cx)));
assert_eq!(val, Some("goodbye"));
let val = assert_ready!(t1.enter(|cx| rx.poll_recv(cx)));
assert!(val.is_none());
}
#[test]
fn drop_tx_with_permit_releases_permit() {
let mut t1 = MockTask::new();
let mut t2 = MockTask::new();
// poll_ready reserves capacity, ensure that the capacity is released if tx
// is dropped w/o sending a value.
let (mut tx1, _rx) = mpsc::channel::<i32>(1);
let mut tx2 = tx1.clone();
assert_ready_ok!(t1.enter(|cx| tx1.poll_ready(cx)));
t2.enter(|cx| {
assert_pending!(tx2.poll_ready(cx));
});
drop(tx1);
assert!(t2.is_woken());
assert_ready_ok!(t2.enter(|cx| tx2.poll_ready(cx)));
}
#[test]
fn dropping_rx_closes_channel() {
let mut t1 = MockTask::new();
let (mut tx, rx) = mpsc::channel(100);
let msg = Arc::new(());
assert_ok!(tx.try_send(msg.clone()));
drop(rx);
assert_ready_err!(t1.enter(|cx| tx.poll_ready(cx)));
assert_eq!(1, Arc::strong_count(&msg));
}
#[test]
fn dropping_rx_closes_channel_for_try() {
let (mut tx, rx) = mpsc::channel(100);
let msg = Arc::new(());
tx.try_send(msg.clone()).unwrap();
drop(rx);
{
let err = assert_err!(tx.try_send(msg.clone()));
assert!(err.is_closed());
}
assert_eq!(1, Arc::strong_count(&msg));
}
#[test]
fn unconsumed_messages_are_dropped() {
let msg = Arc::new(());
let (mut tx, rx) = mpsc::channel(100);
tx.try_send(msg.clone()).unwrap();
assert_eq!(2, Arc::strong_count(&msg));
drop((tx, rx));
assert_eq!(1, Arc::strong_count(&msg));
}
+80
View File
@@ -0,0 +1,80 @@
#![warn(rust_2018_idioms)]
use tokio::sync::Mutex;
use tokio_test::task::spawn;
use tokio_test::{assert_pending, assert_ready};
use std::sync::Arc;
#[test]
fn straight_execution() {
let l = Mutex::new(100);
{
let mut t = spawn(l.lock());
let mut g = assert_ready!(t.poll());
assert_eq!(&*g, &100);
*g = 99;
}
{
let mut t = spawn(l.lock());
let mut g = assert_ready!(t.poll());
assert_eq!(&*g, &99);
*g = 98;
}
{
let mut t = spawn(l.lock());
let g = assert_ready!(t.poll());
assert_eq!(&*g, &98);
}
}
#[test]
fn readiness() {
let l1 = Arc::new(Mutex::new(100));
let l2 = Arc::clone(&l1);
let mut t1 = spawn(l1.lock());
let mut t2 = spawn(l2.lock());
let g = assert_ready!(t1.poll());
// We can't now acquire the lease since it's already held in g
assert_pending!(t2.poll());
// But once g unlocks, we can acquire it
drop(g);
assert!(t2.is_woken());
assert_ready!(t2.poll());
}
/*
#[test]
#[ignore]
fn lock() {
let mut lock = Mutex::new(false);
let mut lock2 = lock.clone();
std::thread::spawn(move || {
let l = lock2.lock();
pin_mut!(l);
let mut task = MockTask::new();
let mut g = assert_ready!(task.poll(&mut l));
std::thread::sleep(std::time::Duration::from_millis(500));
*g = true;
drop(g);
});
std::thread::sleep(std::time::Duration::from_millis(50));
let mut task = MockTask::new();
let l = lock.lock();
pin_mut!(l);
assert_pending!(task.poll(&mut l));
std::thread::sleep(std::time::Duration::from_millis(500));
assert!(task.is_woken());
let result = assert_ready!(task.poll(&mut l));
assert!(*result);
}
*/
+228
View File
@@ -0,0 +1,228 @@
#![warn(rust_2018_idioms)]
use tokio::sync::oneshot;
use tokio_test::task::MockTask;
use tokio_test::*;
trait AssertSend: Send {}
impl AssertSend for oneshot::Sender<i32> {}
impl AssertSend for oneshot::Receiver<i32> {}
#[test]
fn send_recv() {
let (tx, mut rx) = oneshot::channel();
let mut task = MockTask::new();
assert_pending!(task.poll(&mut rx));
assert_ok!(tx.send(1));
assert!(task.is_woken());
let val = assert_ready_ok!(task.poll(&mut rx));
assert_eq!(val, 1);
}
#[tokio::test]
async fn async_send_recv() {
let (tx, rx) = oneshot::channel();
assert_ok!(tx.send(1));
assert_eq!(1, assert_ok!(rx.await));
}
#[test]
fn close_tx() {
let (tx, mut rx) = oneshot::channel::<i32>();
let mut task = MockTask::new();
assert_pending!(task.poll(&mut rx));
drop(tx);
assert!(task.is_woken());
assert_ready_err!(task.poll(&mut rx));
}
#[test]
fn close_rx() {
// First, without checking poll_closed()
//
let (tx, _) = oneshot::channel();
assert_err!(tx.send(1));
// Second, via poll_closed();
let (mut tx, rx) = oneshot::channel();
let mut task = MockTask::new();
assert_pending!(task.enter(|cx| tx.poll_closed(cx)));
drop(rx);
assert!(task.is_woken());
assert!(tx.is_closed());
assert_ready!(task.enter(|cx| tx.poll_closed(cx)));
assert_err!(tx.send(1));
}
#[tokio::test]
async fn async_rx_closed() {
let (mut tx, rx) = oneshot::channel::<()>();
tokio::spawn(async move {
drop(rx);
});
tx.closed().await;
}
#[test]
fn explicit_close_poll() {
// First, with message sent
let (tx, mut rx) = oneshot::channel();
let mut task = MockTask::new();
assert_ok!(tx.send(1));
rx.close();
let value = assert_ready_ok!(task.poll(&mut rx));
assert_eq!(value, 1);
// Second, without the message sent
let (mut tx, mut rx) = oneshot::channel::<i32>();
assert_pending!(task.enter(|cx| tx.poll_closed(cx)));
rx.close();
assert!(task.is_woken());
assert!(tx.is_closed());
assert_ready!(task.enter(|cx| tx.poll_closed(cx)));
assert_err!(tx.send(1));
assert_ready_err!(task.poll(&mut rx));
// Again, but without sending the value this time
let (mut tx, mut rx) = oneshot::channel::<i32>();
let mut task = MockTask::new();
assert_pending!(task.enter(|cx| tx.poll_closed(cx)));
rx.close();
assert!(task.is_woken());
assert!(tx.is_closed());
assert_ready!(task.enter(|cx| tx.poll_closed(cx)));
assert_ready_err!(task.poll(&mut rx));
}
#[test]
fn explicit_close_try_recv() {
// First, with message sent
let (tx, mut rx) = oneshot::channel();
assert_ok!(tx.send(1));
rx.close();
let val = assert_ok!(rx.try_recv());
assert_eq!(1, val);
// Second, without the message sent
let (mut tx, mut rx) = oneshot::channel::<i32>();
let mut task = MockTask::new();
assert_pending!(task.enter(|cx| tx.poll_closed(cx)));
rx.close();
assert!(task.is_woken());
assert!(tx.is_closed());
assert_ready!(task.enter(|cx| tx.poll_closed(cx)));
assert_err!(rx.try_recv());
}
#[test]
#[should_panic]
fn close_try_recv_poll() {
let (_tx, mut rx) = oneshot::channel::<i32>();
let mut task = MockTask::new();
rx.close();
assert_err!(rx.try_recv());
let _ = task.poll(&mut rx);
}
#[test]
fn drops_tasks() {
let (mut tx, mut rx) = oneshot::channel::<i32>();
let mut tx_task = MockTask::new();
let mut rx_task = MockTask::new();
assert_pending!(tx_task.enter(|cx| tx.poll_closed(cx)));
assert_pending!(rx_task.poll(&mut rx));
drop(tx);
drop(rx);
assert_eq!(1, tx_task.waker_ref_count());
assert_eq!(1, rx_task.waker_ref_count());
}
#[test]
fn receiver_changes_task() {
let (tx, mut rx) = oneshot::channel();
let mut task1 = MockTask::new();
let mut task2 = MockTask::new();
assert_pending!(task1.poll(&mut rx));
assert_eq!(2, task1.waker_ref_count());
assert_eq!(1, task2.waker_ref_count());
assert_pending!(task2.poll(&mut rx));
assert_eq!(1, task1.waker_ref_count());
assert_eq!(2, task2.waker_ref_count());
assert_ok!(tx.send(1));
assert!(!task1.is_woken());
assert!(task2.is_woken());
assert_ready_ok!(task2.poll(&mut rx));
}
#[test]
fn sender_changes_task() {
let (mut tx, rx) = oneshot::channel::<i32>();
let mut task1 = MockTask::new();
let mut task2 = MockTask::new();
assert_pending!(task1.enter(|cx| tx.poll_closed(cx)));
assert_eq!(2, task1.waker_ref_count());
assert_eq!(1, task2.waker_ref_count());
assert_pending!(task2.enter(|cx| tx.poll_closed(cx)));
assert_eq!(1, task1.waker_ref_count());
assert_eq!(2, task2.waker_ref_count());
drop(rx);
assert!(!task1.is_woken());
assert!(task2.is_woken());
assert_ready!(task2.enter(|cx| tx.poll_closed(cx)));
}
+153
View File
@@ -0,0 +1,153 @@
#![warn(rust_2018_idioms)]
use tokio::sync::semaphore::{Permit, Semaphore};
use tokio_test::task::MockTask;
use tokio_test::{assert_pending, assert_ready_err, assert_ready_ok};
#[test]
fn available_permits() {
let mut t1 = MockTask::new();
let s = Semaphore::new(100);
assert_eq!(s.available_permits(), 100);
// Polling for a permit succeeds immediately
let mut permit = Permit::new();
assert!(!permit.is_acquired());
assert_ready_ok!(t1.enter(|cx| permit.poll_acquire(cx, &s)));
assert_eq!(s.available_permits(), 99);
assert!(permit.is_acquired());
// Polling again on the same waiter does not claim a new permit
assert_ready_ok!(t1.enter(|cx| permit.poll_acquire(cx, &s)));
assert_eq!(s.available_permits(), 99);
assert!(permit.is_acquired());
}
#[test]
fn unavailable_permits() {
let mut t1 = MockTask::new();
let mut t2 = MockTask::new();
let s = Semaphore::new(1);
let mut permit_1 = Permit::new();
let mut permit_2 = Permit::new();
// Acquire the first permit
assert_ready_ok!(t1.enter(|cx| permit_1.poll_acquire(cx, &s)));
assert_eq!(s.available_permits(), 0);
t2.enter(|cx| {
// Try to acquire the second permit
assert_pending!(permit_2.poll_acquire(cx, &s));
});
permit_1.release(&s);
assert_eq!(s.available_permits(), 0);
assert!(t2.is_woken());
assert_ready_ok!(t2.enter(|cx| permit_2.poll_acquire(cx, &s)));
permit_2.release(&s);
assert_eq!(s.available_permits(), 1);
}
#[test]
fn zero_permits() {
let mut t1 = MockTask::new();
let s = Semaphore::new(0);
assert_eq!(s.available_permits(), 0);
let mut permit = Permit::new();
// Try to acquire the permit
t1.enter(|cx| {
assert_pending!(permit.poll_acquire(cx, &s));
});
s.add_permits(1);
assert!(t1.is_woken());
assert_ready_ok!(t1.enter(|cx| permit.poll_acquire(cx, &s)));
}
#[test]
#[should_panic]
fn validates_max_permits() {
use std::usize;
Semaphore::new((usize::MAX >> 2) + 1);
}
#[test]
fn close_semaphore_prevents_acquire() {
let mut t1 = MockTask::new();
let s = Semaphore::new(1);
s.close();
assert_eq!(1, s.available_permits());
let mut permit = Permit::new();
assert_ready_err!(t1.enter(|cx| permit.poll_acquire(cx, &s)));
assert_eq!(1, s.available_permits());
}
#[test]
fn close_semaphore_notifies_permit1() {
let mut t1 = MockTask::new();
let s = Semaphore::new(0);
let mut permit = Permit::new();
assert_pending!(t1.enter(|cx| permit.poll_acquire(cx, &s)));
s.close();
assert!(t1.is_woken());
assert_ready_err!(t1.enter(|cx| permit.poll_acquire(cx, &s)));
}
#[test]
fn close_semaphore_notifies_permit2() {
let mut t1 = MockTask::new();
let mut t2 = MockTask::new();
let mut t3 = MockTask::new();
let mut t4 = MockTask::new();
let s = Semaphore::new(2);
let mut permit1 = Permit::new();
let mut permit2 = Permit::new();
let mut permit3 = Permit::new();
let mut permit4 = Permit::new();
// Acquire a couple of permits
assert_ready_ok!(t1.enter(|cx| permit1.poll_acquire(cx, &s)));
assert_ready_ok!(t2.enter(|cx| permit2.poll_acquire(cx, &s)));
assert_pending!(t3.enter(|cx| permit3.poll_acquire(cx, &s)));
assert_pending!(t4.enter(|cx| permit4.poll_acquire(cx, &s)));
s.close();
assert!(t3.is_woken());
assert!(t4.is_woken());
assert_ready_err!(t3.enter(|cx| permit3.poll_acquire(cx, &s)));
assert_ready_err!(t4.enter(|cx| permit4.poll_acquire(cx, &s)));
assert_eq!(0, s.available_permits());
permit1.release(&s);
assert_eq!(1, s.available_permits());
assert_ready_err!(t1.enter(|cx| permit1.poll_acquire(cx, &s)));
permit2.release(&s);
assert_eq!(2, s.available_permits());
}
+264
View File
@@ -0,0 +1,264 @@
#![warn(rust_2018_idioms)]
use tokio::sync::watch;
use tokio_test::task::spawn;
use tokio_test::{assert_pending, assert_ready};
#[test]
fn single_rx_recv_ref() {
let (tx, mut rx) = watch::channel("one");
{
let mut t = spawn(rx.recv_ref());
let v = assert_ready!(t.poll()).unwrap();
assert_eq!(*v, "one");
}
{
let mut t = spawn(rx.recv_ref());
assert_pending!(t.poll());
tx.broadcast("two").unwrap();
assert!(t.is_woken());
let v = assert_ready!(t.poll()).unwrap();
assert_eq!(*v, "two");
}
{
let mut t = spawn(rx.recv_ref());
assert_pending!(t.poll());
drop(tx);
let res = assert_ready!(t.poll());
assert!(res.is_none());
}
}
#[test]
fn single_rx_recv() {
let (tx, mut rx) = watch::channel("one");
{
let mut t = spawn(rx.recv());
let v = assert_ready!(t.poll()).unwrap();
assert_eq!(v, "one");
}
{
let mut t = spawn(rx.recv());
assert_pending!(t.poll());
tx.broadcast("two").unwrap();
assert!(t.is_woken());
let v = assert_ready!(t.poll()).unwrap();
assert_eq!(v, "two");
}
{
let mut t = spawn(rx.recv());
assert_pending!(t.poll());
drop(tx);
let res = assert_ready!(t.poll());
assert!(res.is_none());
}
}
#[test]
fn stream_impl() {
use tokio::prelude::*;
let (tx, mut rx) = watch::channel("one");
{
let mut t = spawn(rx.next());
let v = assert_ready!(t.poll()).unwrap();
assert_eq!(v, "one");
}
{
let mut t = spawn(rx.next());
assert_pending!(t.poll());
tx.broadcast("two").unwrap();
assert!(t.is_woken());
let v = assert_ready!(t.poll()).unwrap();
assert_eq!(v, "two");
}
{
let mut t = spawn(rx.next());
assert_pending!(t.poll());
drop(tx);
let res = assert_ready!(t.poll());
assert!(res.is_none());
}
}
#[test]
fn multi_rx() {
let (tx, mut rx1) = watch::channel("one");
let mut rx2 = rx1.clone();
{
let mut t1 = spawn(rx1.recv_ref());
let mut t2 = spawn(rx2.recv_ref());
let res = assert_ready!(t1.poll());
assert_eq!(*res.unwrap(), "one");
let res = assert_ready!(t2.poll());
assert_eq!(*res.unwrap(), "one");
}
let mut t2 = spawn(rx2.recv_ref());
{
let mut t1 = spawn(rx1.recv_ref());
assert_pending!(t1.poll());
assert_pending!(t2.poll());
tx.broadcast("two").unwrap();
assert!(t1.is_woken());
assert!(t2.is_woken());
let res = assert_ready!(t1.poll());
assert_eq!(*res.unwrap(), "two");
}
{
let mut t1 = spawn(rx1.recv_ref());
assert_pending!(t1.poll());
tx.broadcast("three").unwrap();
assert!(t1.is_woken());
assert!(t2.is_woken());
let res = assert_ready!(t1.poll());
assert_eq!(*res.unwrap(), "three");
let res = assert_ready!(t2.poll());
assert_eq!(*res.unwrap(), "three");
}
drop(t2);
{
let mut t1 = spawn(rx1.recv_ref());
let mut t2 = spawn(rx2.recv_ref());
assert_pending!(t1.poll());
assert_pending!(t2.poll());
tx.broadcast("four").unwrap();
let res = assert_ready!(t1.poll());
assert_eq!(*res.unwrap(), "four");
drop(t1);
let mut t1 = spawn(rx1.recv_ref());
assert_pending!(t1.poll());
drop(tx);
assert!(t1.is_woken());
let res = assert_ready!(t1.poll());
assert!(res.is_none());
let res = assert_ready!(t2.poll());
assert_eq!(*res.unwrap(), "four");
drop(t2);
let mut t2 = spawn(rx2.recv_ref());
let res = assert_ready!(t2.poll());
assert!(res.is_none());
}
}
#[test]
fn rx_observes_final_value() {
// Initial value
let (tx, mut rx) = watch::channel("one");
drop(tx);
{
let mut t1 = spawn(rx.recv_ref());
let res = assert_ready!(t1.poll());
assert_eq!(*res.unwrap(), "one");
}
{
let mut t1 = spawn(rx.recv_ref());
let res = assert_ready!(t1.poll());
assert!(res.is_none());
}
// Sending a value
let (tx, mut rx) = watch::channel("one");
tx.broadcast("two").unwrap();
{
let mut t1 = spawn(rx.recv_ref());
let res = assert_ready!(t1.poll());
assert_eq!(*res.unwrap(), "two");
}
{
let mut t1 = spawn(rx.recv_ref());
assert_pending!(t1.poll());
tx.broadcast("three").unwrap();
drop(tx);
assert!(t1.is_woken());
let res = assert_ready!(t1.poll());
assert_eq!(*res.unwrap(), "three");
}
{
let mut t1 = spawn(rx.recv_ref());
let res = assert_ready!(t1.poll());
assert!(res.is_none());
}
}
#[test]
fn poll_close() {
let (mut tx, rx) = watch::channel("one");
{
let mut t = spawn(tx.closed());
assert_pending!(t.poll());
drop(rx);
assert!(t.is_woken());
assert_ready!(t.poll());
}
assert!(tx.broadcast("two").is_err());
}
+1 -1
View File
@@ -274,7 +274,7 @@ fn panic_in_task() {
#[test]
fn multi_threadpool() {
use tokio_sync::oneshot;
use tokio::sync::oneshot;
let pool1 = new_pool();
let pool2 = new_pool();
+2 -5
View File
@@ -129,7 +129,6 @@ fn deadline_future_elapses() {
});
}
#[cfg(feature = "async-traits")]
macro_rules! poll {
($task:ident, $stream:ident) => {{
use futures_core::Stream;
@@ -138,9 +137,8 @@ macro_rules! poll {
}
#[test]
#[cfg(feature = "async-traits")]
fn stream_and_timeout_in_future() {
use tokio_sync::mpsc;
use tokio::sync::mpsc;
let mut t = MockTask::new();
@@ -168,9 +166,8 @@ fn stream_and_timeout_in_future() {
}
#[test]
#[cfg(feature = "async-traits")]
fn idle_stream_timesout_periodically() {
use tokio_sync::mpsc;
use tokio::sync::mpsc;
let mut t = MockTask::new();