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, ) { 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(); }