| //! Inspired by tests from <https://github.com/faern/oneshot/blob/main/tests/sync.rs> | |
| use std::sync::mpsc::RecvError; | |
| use std::sync::oneshot; | |
| use std::sync::oneshot::{RecvTimeoutError, TryRecvError}; | |
| use std::time::{Duration, Instant}; | |
| use std::{mem, thread}; | |
| #[test] | |
| fn send_before_try_recv() { | |
| let (sender, receiver) = oneshot::channel(); | |
| assert!(sender.send(19i128).is_ok()); | |
| match receiver.try_recv() { | |
| Ok(19) => {} | |
| _ => panic!("expected Ok(19)"), | |
| } | |
| } | |
| #[test] | |
| fn send_before_recv() { | |
| let (sender, receiver) = oneshot::channel::<()>(); | |
| assert!(sender.send(()).is_ok()); | |
| assert_eq!(receiver.recv(), Ok(())); | |
| let (sender, receiver) = oneshot::channel::<u64>(); | |
| assert!(sender.send(42).is_ok()); | |
| assert_eq!(receiver.recv(), Ok(42)); | |
| let (sender, receiver) = oneshot::channel::<[u8; 4096]>(); | |
| assert!(sender.send([0b10101010; 4096]).is_ok()); | |
| assert!(receiver.recv().unwrap()[..] == [0b10101010; 4096][..]); | |
| } | |
| #[test] | |
| fn sender_drop() { | |
| { | |
| let (sender, receiver) = oneshot::channel::<u128>(); | |
| mem::drop(sender); | |
| match receiver.recv() { | |
| Err(RecvError) => {} | |
| _ => panic!("expected recv error"), | |
| } | |
| } | |
| { | |
| let (sender, receiver) = oneshot::channel::<i32>(); | |
| mem::drop(sender); | |
| match receiver.try_recv() { | |
| Err(TryRecvError::Disconnected) => {} | |
| _ => panic!("expected disconnected error"), | |
| } | |
| } | |
| { | |
| let (sender, receiver) = oneshot::channel::<i32>(); | |
| mem::drop(sender); | |
| match receiver.recv_timeout(Duration::from_secs(1)) { | |
| Err(RecvTimeoutError::Disconnected) => {} | |
| _ => panic!("expected disconnected error"), | |
| } | |
| } | |
| } | |
| #[test] | |
| fn send_never_deadline() { | |
| let (sender, receiver) = oneshot::channel::<i32>(); | |
| mem::drop(sender); | |
| match receiver.recv_deadline(Instant::now()) { | |
| Err(RecvTimeoutError::Disconnected) => {} | |
| _ => panic!("expected disconnected error"), | |
| } | |
| } | |
| #[test] | |
| fn send_before_recv_timeout() { | |
| let (sender, receiver) = oneshot::channel(); | |
| assert!(sender.send(22i128).is_ok()); | |
| let timeout = Duration::from_secs(1); | |
| match receiver.recv_timeout(timeout) { | |
| Ok(22) => {} | |
| _ => panic!("expected Ok(22)"), | |
| } | |
| // FIXME(#152648): There previously was a timing assertion here. | |
| // This was removed, because under load there's no guarantee that the main thread is | |
| // scheduled and run before `timeout` expires | |
| } | |
| #[test] | |
| fn send_error() { | |
| let (sender, receiver) = oneshot::channel(); | |
| mem::drop(receiver); | |
| let send_error = sender.send(32u128).unwrap_err(); | |
| assert_eq!(send_error.0, 32); | |
| } | |
| #[test] | |
| fn recv_before_send() { | |
| let (sender, receiver) = oneshot::channel(); | |
| let t1 = thread::spawn(move || { | |
| thread::sleep(Duration::from_millis(10)); | |
| sender.send(9u128).unwrap(); | |
| }); | |
| let t2 = thread::spawn(move || { | |
| assert_eq!(receiver.recv(), Ok(9)); | |
| }); | |
| t1.join().unwrap(); | |
| t2.join().unwrap(); | |
| } | |
| #[test] | |
| #[ignore = "Inherently flaky and has caused several CI failures"] | |
| fn recv_timeout_before_send() { | |
| let (sender, receiver) = oneshot::channel(); | |
| let t = thread::spawn(move || { | |
| thread::sleep(Duration::from_millis(100)); | |
| sender.send(99u128).unwrap(); | |
| }); | |
| // FIXME(#152145): Under load, there's no guarantee that thread `t` has | |
| // ever been scheduled and run before this timeout expires. | |
| match receiver.recv_timeout(Duration::from_secs(1)) { | |
| Ok(99) => {} | |
| _ => panic!("expected Ok(99)"), | |
| } | |
| t.join().unwrap(); | |
| } | |
| #[test] | |
| fn recv_then_drop_sender() { | |
| let (sender, receiver) = oneshot::channel::<u128>(); | |
| let t1 = thread::spawn(move || match receiver.recv() { | |
| Err(RecvError) => {} | |
| _ => panic!("expected recv error"), | |
| }); | |
| let t2 = thread::spawn(move || { | |
| thread::sleep(Duration::from_millis(10)); | |
| mem::drop(sender); | |
| }); | |
| t1.join().unwrap(); | |
| t2.join().unwrap(); | |
| } | |
| #[test] | |
| fn drop_sender_then_recv() { | |
| let (sender, receiver) = oneshot::channel::<u128>(); | |
| let t1 = thread::spawn(move || { | |
| thread::sleep(Duration::from_millis(10)); | |
| mem::drop(sender); | |
| }); | |
| let t2 = thread::spawn(move || match receiver.recv() { | |
| Err(RecvError) => {} | |
| _ => panic!("expected disconnected error"), | |
| }); | |
| t1.join().unwrap(); | |
| t2.join().unwrap(); | |
| } | |
| #[test] | |
| fn try_recv_empty() { | |
| let (sender, receiver) = oneshot::channel::<u128>(); | |
| match receiver.try_recv() { | |
| Err(TryRecvError::Empty(_)) => {} | |
| _ => panic!("expected empty error"), | |
| } | |
| mem::drop(sender); | |
| } | |
| #[test] | |
| fn try_recv_then_drop_receiver() { | |
| let (sender, receiver) = oneshot::channel::<u128>(); | |
| let t1 = thread::spawn(move || { | |
| thread::sleep(Duration::from_millis(100)); | |
| let _ = sender.send(42); | |
| }); | |
| let t2 = thread::spawn(move || match receiver.try_recv() { | |
| Ok(_) => {} | |
| Err(TryRecvError::Empty(r)) => { | |
| mem::drop(r); | |
| } | |
| Err(TryRecvError::Disconnected) => {} | |
| }); | |
| t2.join().unwrap(); | |
| t1.join().unwrap(); | |
| } | |
| #[test] | |
| fn recv_no_time() { | |
| let (_sender, receiver) = oneshot::channel::<u128>(); | |
| let start = Instant::now(); | |
| match receiver.recv_deadline(start) { | |
| Err(RecvTimeoutError::Timeout(_)) => {} | |
| _ => panic!("expected timeout error"), | |
| } | |
| let (_sender, receiver) = oneshot::channel::<u128>(); | |
| match receiver.recv_timeout(Duration::from_millis(0)) { | |
| Err(RecvTimeoutError::Timeout(_)) => {} | |
| _ => panic!("expected timeout error"), | |
| } | |
| } | |
| #[test] | |
| fn recv_deadline_passed() { | |
| let (_sender, receiver) = oneshot::channel::<u128>(); | |
| let start = Instant::now(); | |
| let timeout = Duration::from_millis(100); | |
| match receiver.recv_deadline(start + timeout) { | |
| Err(RecvTimeoutError::Timeout(_)) => {} | |
| _ => panic!("expected timeout error"), | |
| } | |
| assert!(start.elapsed() >= timeout); | |
| // FIXME(#152878): An upper-bound assertion on the elapsed time was removed, | |
| // because CI runners can starve individual threads for a surprisingly long | |
| // time, leading to flaky failures. | |
| } | |
| #[test] | |
| fn recv_time_passed() { | |
| let (_sender, receiver) = oneshot::channel::<u128>(); | |
| let start = Instant::now(); | |
| let timeout = Duration::from_millis(100); | |
| match receiver.recv_timeout(timeout) { | |
| Err(RecvTimeoutError::Timeout(_)) => {} | |
| _ => panic!("expected timeout error"), | |
| } | |
| assert!(start.elapsed() >= timeout); | |
| // FIXME(#152878): An upper-bound assertion on the elapsed time was removed, | |
| // because CI runners can starve individual threads for a surprisingly long | |
| // time, leading to flaky failures. | |
| } | |
| #[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())); | |
| } | |
| /// Helper for testing drop behavior (taken directly from the `oneshot` crate). | |
| struct DropCounter { | |
| count: std::rc::Rc<std::cell::RefCell<usize>>, | |
| } | |
| impl DropCounter { | |
| fn new() -> (DropTracker, DropCounter) { | |
| let count = std::rc::Rc::new(std::cell::RefCell::new(0)); | |
| (DropTracker { count: count.clone() }, DropCounter { count }) | |
| } | |
| fn count(&self) -> usize { | |
| *self.count.borrow() | |
| } | |
| } | |
| struct DropTracker { | |
| count: std::rc::Rc<std::cell::RefCell<usize>>, | |
| } | |
| impl Drop for DropTracker { | |
| fn drop(&mut self) { | |
| *self.count.borrow_mut() += 1; | |
| } | |
| } | |
| #[test] | |
| fn message_in_channel_dropped_on_receiver_drop() { | |
| 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() { | |
| let (sender, receiver) = oneshot::channel(); | |
| mem::drop(receiver); | |
| 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_extract() { | |
| let (sender, receiver) = oneshot::channel(); | |
| mem::drop(receiver); | |
| let (message, counter) = DropCounter::new(); | |
| let send_error = sender.send(message).unwrap_err(); | |
| assert_eq!(counter.count(), 0); | |
| let message = send_error.0; // Access the inner value directly | |
| assert_eq!(counter.count(), 0); | |
| mem::drop(message); | |
| assert_eq!(counter.count(), 1); | |
| } |