343 lines
9.6 KiB
Rust
343 lines
9.6 KiB
Rust
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);
|
|
});
|
|
}
|