Carl Lerche 70f4fc481c
sync: Add watch, a single value broadcast channel (#922)
A single-producer, multi-consumer channel that only retains the _last_ sent
value. Values are broadcasted out.

This channel is useful for watching for changes to a value from multiple
points in the code base (for example, changes to a configuration value).
2019-02-22 21:54:50 -08:00

235 lines
4.9 KiB
Rust

extern crate futures;
extern crate tokio_mock_task;
extern crate tokio_sync;
use tokio_mock_task::*;
use tokio_sync::watch;
macro_rules! assert_ready {
($e:expr) => {{
match $e {
Ok(futures::Async::Ready(v)) => v,
Ok(_) => panic!("not ready"),
Err(e) => panic!("error = {:?}", e),
}
}};
}
macro_rules! assert_not_ready {
($e:expr) => {{
match $e {
Ok(futures::Async::NotReady) => {}
Ok(futures::Async::Ready(v)) => panic!("ready; value = {:?}", v),
Err(e) => panic!("error = {:?}", e),
}
}};
}
#[test]
fn single_rx() {
let (mut tx, mut rx) = watch::channel("one");
let mut task = MockTask::new();
task.enter(|| {
let v = assert_ready!(rx.poll_ref()).unwrap();
assert_eq!(*v, "one");
});
task.enter(|| assert_not_ready!(rx.poll_ref()));
assert!(!task.is_notified());
tx.broadcast("two").unwrap();
assert!(task.is_notified());
task.enter(|| {
let v = assert_ready!(rx.poll_ref()).unwrap();
assert_eq!(*v, "two");
});
task.enter(|| assert_not_ready!(rx.poll_ref()));
drop(tx);
assert!(task.is_notified());
task.enter(|| {
let res = assert_ready!(rx.poll_ref());
assert!(res.is_none());
});
}
#[test]
fn stream_impl() {
use futures::Stream;
let (mut tx, mut rx) = watch::channel("one");
let mut task = MockTask::new();
task.enter(|| {
let v = assert_ready!(rx.poll()).unwrap();
assert_eq!(v, "one");
});
task.enter(|| assert_not_ready!(rx.poll()));
assert!(!task.is_notified());
tx.broadcast("two").unwrap();
assert!(task.is_notified());
task.enter(|| {
let v = assert_ready!(rx.poll()).unwrap();
assert_eq!(v, "two");
});
task.enter(|| assert_not_ready!(rx.poll()));
drop(tx);
assert!(task.is_notified());
task.enter(|| {
let res = assert_ready!(rx.poll());
assert!(res.is_none());
});
}
#[test]
fn multi_rx() {
let (mut tx, mut rx1) = watch::channel("one");
let mut rx2 = rx1.clone();
let mut task1 = MockTask::new();
let mut task2 = MockTask::new();
task1.enter(|| {
let res = assert_ready!(rx1.poll_ref());
assert_eq!(*res.unwrap(), "one");
});
task2.enter(|| {
let res = assert_ready!(rx2.poll_ref());
assert_eq!(*res.unwrap(), "one");
});
tx.broadcast("two").unwrap();
assert!(task1.is_notified());
assert!(task2.is_notified());
task1.enter(|| {
let res = assert_ready!(rx1.poll_ref());
assert_eq!(*res.unwrap(), "two");
});
tx.broadcast("three").unwrap();
assert!(task1.is_notified());
assert!(task2.is_notified());
task1.enter(|| {
let res = assert_ready!(rx1.poll_ref());
assert_eq!(*res.unwrap(), "three");
});
task2.enter(|| {
let res = assert_ready!(rx2.poll_ref());
assert_eq!(*res.unwrap(), "three");
});
tx.broadcast("four").unwrap();
task1.enter(|| {
let res = assert_ready!(rx1.poll_ref());
assert_eq!(*res.unwrap(), "four");
});
drop(tx);
task1.enter(|| {
let res = assert_ready!(rx1.poll_ref());
assert!(res.is_none());
});
task2.enter(|| {
let res = assert_ready!(rx2.poll_ref());
assert_eq!(*res.unwrap(), "four");
});
task2.enter(|| {
let res = assert_ready!(rx2.poll_ref());
assert!(res.is_none());
});
}
#[test]
fn rx_observes_final_value() {
// Initial value
let (tx, mut rx) = watch::channel("one");
let mut task = MockTask::new();
drop(tx);
task.enter(|| {
let res = assert_ready!(rx.poll_ref());
assert!(res.is_some());
assert_eq!(*res.unwrap(), "one");
});
task.enter(|| {
let res = assert_ready!(rx.poll_ref());
assert!(res.is_none());
});
// Sending a value
let (mut tx, mut rx) = watch::channel("one");
let mut task = MockTask::new();
tx.broadcast("two").unwrap();
task.enter(|| {
let res = assert_ready!(rx.poll_ref());
assert!(res.is_some());
assert_eq!(*res.unwrap(), "two");
});
task.enter(|| assert_not_ready!(rx.poll_ref()));
tx.broadcast("three").unwrap();
drop(tx);
assert!(task.is_notified());
task.enter(|| {
let res = assert_ready!(rx.poll_ref());
assert!(res.is_some());
assert_eq!(*res.unwrap(), "three");
});
task.enter(|| {
let res = assert_ready!(rx.poll_ref());
assert!(res.is_none());
});
}
#[test]
fn poll_close() {
let (mut tx, rx) = watch::channel("one");
let mut task = MockTask::new();
task.enter(|| assert_not_ready!(tx.poll_close()));
drop(rx);
assert!(task.is_notified());
task.enter(|| assert_ready!(tx.poll_close()));
assert!(tx.broadcast("two").is_err());
}