summaryrefslogtreecommitdiff
path: root/tests/sync.rs
diff options
context:
space:
mode:
Diffstat (limited to 'tests/sync.rs')
-rw-r--r--tests/sync.rs343
1 files changed, 343 insertions, 0 deletions
diff --git a/tests/sync.rs b/tests/sync.rs
new file mode 100644
index 0000000..c6ba081
--- /dev/null
+++ b/tests/sync.rs
@@ -0,0 +1,343 @@
+use core::mem;
+use oneshot::TryRecvError;
+
+#[cfg(feature = "std")]
+use oneshot::{RecvError, RecvTimeoutError};
+#[cfg(feature = "std")]
+use std::time::{Duration, Instant};
+
+#[cfg(feature = "std")]
+mod thread {
+ #[cfg(loom)]
+ pub use loom::thread::spawn;
+ #[cfg(not(loom))]
+ pub use std::thread::{sleep, spawn};
+
+ #[cfg(loom)]
+ pub fn sleep(_timeout: core::time::Duration) {
+ loom::thread::yield_now()
+ }
+}
+
+mod helpers;
+use helpers::{maybe_loom_model, DropCounter};
+
+#[test]
+fn send_before_try_recv() {
+ maybe_loom_model(|| {
+ let (sender, receiver) = oneshot::channel();
+ assert!(sender.send(19i128).is_ok());
+
+ assert_eq!(receiver.try_recv(), Ok(19i128));
+ assert_eq!(receiver.try_recv(), Err(TryRecvError::Disconnected));
+ #[cfg(feature = "std")]
+ {
+ assert_eq!(receiver.recv_ref(), Err(RecvError));
+ assert!(receiver.recv_timeout(Duration::from_secs(1)).is_err());
+ }
+ })
+}
+
+#[cfg(feature = "std")]
+#[test]
+fn send_before_recv() {
+ maybe_loom_model(|| {
+ let (sender, receiver) = oneshot::channel::<()>();
+ assert!(sender.send(()).is_ok());
+ assert_eq!(receiver.recv(), Ok(()));
+ });
+ maybe_loom_model(|| {
+ let (sender, receiver) = oneshot::channel::<u8>();
+ assert!(sender.send(19).is_ok());
+ assert_eq!(receiver.recv(), Ok(19));
+ });
+ maybe_loom_model(|| {
+ let (sender, receiver) = oneshot::channel::<u64>();
+ assert!(sender.send(21).is_ok());
+ assert_eq!(receiver.recv(), Ok(21));
+ });
+ // FIXME: This test does not work with loom. There is something that happens after the
+ // channel object becomes larger than ~500 bytes and that makes an atomic read from the state
+ // result in "signal: 10, SIGBUS: access to undefined memory"
+ #[cfg(not(loom))]
+ maybe_loom_model(|| {
+ let (sender, receiver) = oneshot::channel::<[u8; 4096]>();
+ assert!(sender.send([0b10101010; 4096]).is_ok());
+ assert!(receiver.recv().unwrap()[..] == [0b10101010; 4096][..]);
+ });
+}
+
+#[cfg(feature = "std")]
+#[test]
+fn send_before_recv_ref() {
+ maybe_loom_model(|| {
+ let (sender, receiver) = oneshot::channel();
+ assert!(sender.send(19i128).is_ok());
+
+ assert_eq!(receiver.recv_ref(), Ok(19i128));
+ assert_eq!(receiver.recv_ref(), Err(RecvError));
+ assert_eq!(receiver.try_recv(), Err(TryRecvError::Disconnected));
+ assert!(receiver.recv_timeout(Duration::from_secs(1)).is_err());
+ })
+}
+
+#[cfg(feature = "std")]
+#[test]
+fn send_before_recv_timeout() {
+ maybe_loom_model(|| {
+ let (sender, receiver) = oneshot::channel();
+ assert!(sender.send(19i128).is_ok());
+
+ let start = Instant::now();
+ let timeout = Duration::from_secs(1);
+ assert_eq!(receiver.recv_timeout(timeout), Ok(19i128));
+ assert!(start.elapsed() < Duration::from_millis(100));
+
+ assert!(receiver.recv_timeout(timeout).is_err());
+ assert!(receiver.try_recv().is_err());
+ assert!(receiver.recv().is_err());
+ })
+}
+
+#[test]
+fn send_then_drop_receiver() {
+ maybe_loom_model(|| {
+ let (sender, receiver) = oneshot::channel();
+ assert!(sender.send(19i128).is_ok());
+ mem::drop(receiver);
+ })
+}
+
+#[test]
+fn send_with_dropped_receiver() {
+ maybe_loom_model(|| {
+ let (sender, receiver) = oneshot::channel();
+ mem::drop(receiver);
+ let send_error = sender.send(5u128).unwrap_err();
+ assert_eq!(*send_error.as_inner(), 5);
+ assert_eq!(send_error.into_inner(), 5);
+ })
+}
+
+#[test]
+fn try_recv_with_dropped_sender() {
+ maybe_loom_model(|| {
+ let (sender, receiver) = oneshot::channel::<u128>();
+ mem::drop(sender);
+ receiver.try_recv().unwrap_err();
+ })
+}
+
+#[cfg(feature = "std")]
+#[test]
+fn recv_with_dropped_sender() {
+ maybe_loom_model(|| {
+ let (sender, receiver) = oneshot::channel::<u128>();
+ mem::drop(sender);
+ receiver.recv().unwrap_err();
+ })
+}
+
+#[cfg(feature = "std")]
+#[test]
+fn recv_before_send() {
+ maybe_loom_model(|| {
+ let (sender, receiver) = oneshot::channel();
+ let t = thread::spawn(move || {
+ thread::sleep(Duration::from_millis(2));
+ sender.send(9u128).unwrap();
+ });
+ assert_eq!(receiver.recv(), Ok(9));
+ t.join().unwrap();
+ })
+}
+
+#[cfg(feature = "std")]
+#[test]
+fn recv_timeout_before_send() {
+ maybe_loom_model(|| {
+ let (sender, receiver) = oneshot::channel();
+ let t = thread::spawn(move || {
+ thread::sleep(Duration::from_millis(2));
+ sender.send(9u128).unwrap();
+ });
+ assert_eq!(receiver.recv_timeout(Duration::from_secs(1)), Ok(9));
+ t.join().unwrap();
+ })
+}
+
+#[cfg(feature = "std")]
+#[test]
+fn recv_before_send_then_drop_sender() {
+ maybe_loom_model(|| {
+ let (sender, receiver) = oneshot::channel::<u128>();
+ let t = thread::spawn(move || {
+ thread::sleep(Duration::from_millis(10));
+ mem::drop(sender);
+ });
+ assert!(receiver.recv().is_err());
+ t.join().unwrap();
+ })
+}
+
+#[cfg(feature = "std")]
+#[test]
+fn recv_timeout_before_send_then_drop_sender() {
+ maybe_loom_model(|| {
+ let (sender, receiver) = oneshot::channel::<u128>();
+ let t = thread::spawn(move || {
+ thread::sleep(Duration::from_millis(10));
+ mem::drop(sender);
+ });
+ assert!(receiver.recv_timeout(Duration::from_secs(1)).is_err());
+ t.join().unwrap();
+ })
+}
+
+#[test]
+fn try_recv() {
+ maybe_loom_model(|| {
+ let (sender, receiver) = oneshot::channel::<u128>();
+ assert_eq!(receiver.try_recv(), Err(TryRecvError::Empty));
+ mem::drop(sender)
+ })
+}
+
+#[cfg(feature = "std")]
+#[test]
+fn try_recv_then_drop_receiver() {
+ maybe_loom_model(|| {
+ let (sender, receiver) = oneshot::channel::<u128>();
+ let t1 = thread::spawn(move || {
+ let _ = sender.send(42);
+ });
+ let t2 = thread::spawn(move || {
+ assert!(matches!(
+ receiver.try_recv(),
+ Ok(42) | Err(TryRecvError::Empty)
+ ));
+ mem::drop(receiver);
+ });
+ t1.join().unwrap();
+ t2.join().unwrap();
+ })
+}
+
+#[cfg(feature = "std")]
+#[test]
+fn recv_deadline_and_timeout_no_time() {
+ maybe_loom_model(|| {
+ let (_sender, receiver) = oneshot::channel::<u128>();
+
+ let start = Instant::now();
+ assert_eq!(
+ receiver.recv_deadline(start),
+ Err(RecvTimeoutError::Timeout)
+ );
+ assert!(start.elapsed() < Duration::from_millis(200));
+
+ let start = Instant::now();
+ assert_eq!(
+ receiver.recv_timeout(Duration::from_millis(0)),
+ Err(RecvTimeoutError::Timeout)
+ );
+ assert!(start.elapsed() < Duration::from_millis(200));
+ })
+}
+
+// This test doesn't give meaningful results when run with oneshot_test_delay and loom
+#[cfg(all(feature = "std", not(all(oneshot_test_delay, loom))))]
+#[test]
+fn recv_deadline_time_should_elapse() {
+ maybe_loom_model(|| {
+ let (_sender, receiver) = oneshot::channel::<u128>();
+
+ let start = Instant::now();
+ #[cfg(not(loom))]
+ let timeout = Duration::from_millis(100);
+ #[cfg(loom)]
+ let timeout = Duration::from_millis(1);
+ assert_eq!(
+ receiver.recv_deadline(start + timeout),
+ Err(RecvTimeoutError::Timeout)
+ );
+ assert!(start.elapsed() > timeout);
+ assert!(start.elapsed() < timeout * 3);
+ })
+}
+
+#[cfg(all(feature = "std", not(all(oneshot_test_delay, loom))))]
+#[test]
+fn recv_timeout_time_should_elapse() {
+ maybe_loom_model(|| {
+ let (_sender, receiver) = oneshot::channel::<u128>();
+
+ let start = Instant::now();
+ #[cfg(not(loom))]
+ let timeout = Duration::from_millis(100);
+ #[cfg(loom)]
+ let timeout = Duration::from_millis(1);
+
+ assert_eq!(
+ receiver.recv_timeout(timeout),
+ Err(RecvTimeoutError::Timeout)
+ );
+ assert!(start.elapsed() > timeout);
+ assert!(start.elapsed() < timeout * 3);
+ })
+}
+
+#[cfg(not(loom))]
+#[test]
+fn non_send_type_can_be_used_on_same_thread() {
+ use std::ptr;
+
+ #[derive(Debug, Eq, PartialEq)]
+ struct NotSend(*mut ());
+
+ let (sender, receiver) = oneshot::channel();
+ sender.send(NotSend(ptr::null_mut())).unwrap();
+ let reply = receiver.try_recv().unwrap();
+ assert_eq!(reply, NotSend(ptr::null_mut()));
+}
+
+#[test]
+fn message_in_channel_dropped_on_receiver_drop() {
+ maybe_loom_model(|| {
+ let (sender, receiver) = oneshot::channel();
+ let (message, counter) = DropCounter::new(());
+ assert_eq!(counter.count(), 0);
+ sender.send(message).unwrap();
+ assert_eq!(counter.count(), 0);
+ mem::drop(receiver);
+ assert_eq!(counter.count(), 1);
+ })
+}
+
+#[test]
+fn send_error_drops_message_correctly() {
+ maybe_loom_model(|| {
+ let (sender, _) = oneshot::channel();
+ let (message, counter) = DropCounter::new(());
+
+ let send_error = sender.send(message).unwrap_err();
+ assert_eq!(counter.count(), 0);
+ mem::drop(send_error);
+ assert_eq!(counter.count(), 1);
+ });
+}
+
+#[test]
+fn send_error_drops_message_correctly_on_into_inner() {
+ maybe_loom_model(|| {
+ let (sender, _) = oneshot::channel();
+ let (message, counter) = DropCounter::new(());
+
+ let send_error = sender.send(message).unwrap_err();
+ assert_eq!(counter.count(), 0);
+ let message = send_error.into_inner();
+ assert_eq!(counter.count(), 0);
+ mem::drop(message);
+ assert_eq!(counter.count(), 1);
+ });
+}