blob: a0627d299c747c1a0a890b0c7a0beab40675c52b [file] [log] [blame]
mod config;
use config::{hw_config, HardwareConfig};
use rstest::rstest;
use serialport::*;
use std::io::Read;
use std::thread;
use std::time::{Duration, Instant};
#[rstest]
#[case(1, Vec::from(b"abcdef"))]
#[case(
20,
Vec::from(b"0123456789:;<=>?@abcdefghijklmnopqrstuvwxyz[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~")
)]
#[cfg_attr(feature = "ignore-hardware-tests", ignore)]
fn test_read_returns_available_data_before_timeout(
hw_config: HardwareConfig,
#[case] chunk_size: usize,
#[case] message: Vec<u8>,
) {
let send_period = Duration::from_millis(500);
let receive_timeout = Duration::from_millis(3000);
let marign = Duration::from_millis(100);
let mut sender = serialport::new(hw_config.port_1, 115200).open().unwrap();
let mut receiver = serialport::new(hw_config.port_2, 115200)
.timeout(receive_timeout)
.open()
.unwrap();
sender.clear(ClearBuffer::All).unwrap();
receiver.clear(ClearBuffer::All).unwrap();
let expected_message = message.clone();
let receiver_thread = thread::spawn(move || {
let chunk_timeout = send_period + marign;
assert!(receiver.timeout() > 3 * chunk_timeout);
let mut received_message = Vec::with_capacity(expected_message.len());
loop {
let chunk_start = Instant::now();
let expected_chunk_until = chunk_start + chunk_timeout;
let mut buffer = [0u8; 1024];
assert!(buffer.len() > expected_message.len());
// Try to read more data than we are expecting and expect some data to be available
// after the send period (plus some margin).
match receiver.read(&mut buffer) {
Ok(read) => {
assert!(expected_chunk_until > Instant::now());
assert!(read > 0);
println!(
"receive: {} bytes after waiting {} ms",
read,
(Instant::now() - chunk_start).as_millis()
);
received_message.extend_from_slice(&buffer[..read]);
}
e => panic!("unexpected error {:?}", e),
}
if received_message.len() >= expected_message.len() {
break;
}
}
assert_eq!(expected_message, received_message);
});
let sender_thread = thread::spawn(move || {
let mut next = Instant::now();
for chunk in message.chunks(chunk_size) {
sender.write_all(chunk).unwrap();
sender.flush().unwrap();
println!("send: {} bytes", chunk.len());
next += send_period;
thread::sleep(next - Instant::now());
}
});
sender_thread.join().unwrap();
receiver_thread.join().unwrap();
}
#[rstest]
#[case(b"a")]
#[case(b"0123456789")]
#[case(b"0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~")]
#[cfg_attr(feature = "ignore-hardware-tests", ignore)]
fn test_timeout_zero(hw_config: HardwareConfig, #[case] message: &[u8]) {
let timeout = Duration::ZERO;
let margin = Duration::from_millis(100);
let mut sender = serialport::new(hw_config.port_1, 115200).open().unwrap();
let mut receiver = serialport::new(hw_config.port_2, 115200)
.timeout(timeout)
.open()
.unwrap();
let mut buffer: [u8; 1024] = [0xff; 1024];
sender.clear(ClearBuffer::All).unwrap();
receiver.clear(ClearBuffer::All).unwrap();
sender.write_all(message).unwrap();
sender.flush().unwrap();
let flushed_at = Instant::now();
let expected_until = flushed_at + timeout + margin;
let mut timeouts = 0usize;
loop {
match receiver.read(&mut buffer) {
Ok(read) => {
assert!(read > 0);
println!(
"read: {} bytes of {} after {} timeouts/{} ms",
read,
message.len(),
timeouts,
(Instant::now() - flushed_at).as_millis()
);
assert_eq!(message[..read], buffer[..read]);
break;
}
Err(e) => {
assert_eq!(e.kind(), std::io::ErrorKind::TimedOut);
timeouts += 1;
}
}
assert!(expected_until > Instant::now());
}
}
#[rstest]
#[case(Duration::from_millis(10))]
#[case(Duration::from_millis(100))]
#[case(Duration::from_millis(1000))]
#[cfg_attr(feature = "ignore-hardware-tests", ignore)]
fn test_timeout_greater_zero(hw_config: HardwareConfig, #[case] timeout: Duration) {
let margin = Duration::from_millis(100);
let mut sender = serialport::new(hw_config.port_1, 115200).open().unwrap();
let mut receiver = serialport::new(hw_config.port_2, 115200)
.timeout(timeout)
.open()
.unwrap();
let message =
b"0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";
let mut buffer: [u8; 1024] = [0xff; 1024];
sender.clear(ClearBuffer::All).unwrap();
receiver.clear(ClearBuffer::All).unwrap();
sender.write_all(message).unwrap();
sender.flush().unwrap();
let flushed_at = Instant::now();
let read = receiver.read(&mut buffer).unwrap();
let read_at = Instant::now();
println!(
"read: {} bytes of {} after {} ms",
read,
message.len(),
(Instant::now() - flushed_at).as_millis()
);
assert!(read > 0);
assert!(flushed_at + timeout + margin > read_at);
assert_eq!(buffer[..read], message[..read]);
}
/// Checks that reading data with a timeout of `Duration::MAX` returns some data and no error. It
/// does not check the actual timeout for obvious reason.
#[rstest]
#[cfg_attr(feature = "ignore-hardware-tests", ignore)]
fn test_timeout_max(hw_config: HardwareConfig) {
let sleep = Duration::from_millis(3000);
let margin = Duration::from_millis(500);
let mut sender = serialport::new(hw_config.port_1, 115200).open().unwrap();
let mut receiver = serialport::new(hw_config.port_2, 115200)
.timeout(Duration::MAX)
.open()
.unwrap();
let message =
b"0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";
let mut buffer: [u8; 1024] = [0xff; 1024];
sender.clear(ClearBuffer::All).unwrap();
receiver.clear(ClearBuffer::All).unwrap();
let started_at = Instant::now();
let sender_thread = thread::spawn(move || {
thread::sleep(sleep);
sender.write_all(message).unwrap();
sender.flush().unwrap();
});
let read = receiver.read(&mut buffer).unwrap();
let read_at = Instant::now();
println!(
"read: {} bytes of {} after {} ms",
read,
message.len(),
(Instant::now() - started_at).as_millis()
);
assert!(read > 0);
assert!(read_at > started_at + sleep);
assert!(read_at < started_at + sleep + margin);
assert_eq!(buffer[..read], message[..read]);
sender_thread.join().unwrap();
}