use std::net::*; use rand::Rng; use nardol::Bytes; use nardol::{Packet, PacketKind}; /// This checks only if size of Packet was calculated correctly. #[test] fn new() { let packet = Packet::new(PacketKind::Empty, Bytes::from([1_u8, 2_u8, 3_u8, 4_u8])).unwrap(); assert_eq!(packet.size(), 8_u16); } /// Checks if FromBytes::from_buff implementation for Packet correctly returns an error if buffer is to small. #[test] fn from_buff_size_test() { let too_short_buff = [1_u8, 2_u8, 3_u8]; let mut returns_error = false; if Packet::try_from(too_short_buff.as_slice()).is_err() { returns_error = true; } assert!(returns_error); } /// Checks if FromBytes::from_buff implementation for Packet correctly builds a packet from_buff. #[test] fn from_buff_correctness_test() { // This should create a Packet with size 6, kind Unit and two bytes in its content. let buff = vec![0_u8, 6_u8, 4_u8, 0_u8, 1_u8, 2_u8]; let packet = Packet::new(PacketKind::Unit, Bytes::from([1_u8, 2_u8])).unwrap(); let packet_from_buff = Packet::try_from(buff.as_slice()).unwrap(); assert_eq!(packet, packet_from_buff); } /// Checks if IntoBytes::into_Bytes creates a correct buff from a Packet. #[test] #[allow(non_snake_case)] fn into_Bytes() { let packet = Packet::new(PacketKind::Unit, Bytes::from([1_u8, 2_u8])).unwrap(); let buff = vec![0_u8, 6_u8, 4_u8, 0_u8, 1_u8, 2_u8]; let buff_from_packet = Bytes::from(packet).into_vec(); assert_eq!(buff, buff_from_packet); } /// Tests if Packet::receive works and returns the same data for successive calls. /// Also tests Packet::send if correct data are sent. #[test] fn receive() { let addrs = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8000); let listener = TcpListener::bind(addrs).unwrap(); let created_packet = Packet::new(PacketKind::Unit, Bytes::from([0, 1, 2, 3, 4, 5])).unwrap(); let created_packet_in_thread = created_packet.clone(); std::thread::spawn(move || { std::thread::sleep(std::time::Duration::from_secs(1)); let packet = created_packet_in_thread; let mut stream = TcpStream::connect(addrs).unwrap(); packet.send(&mut stream).unwrap(); }); let (mut stream, _) = listener.accept().unwrap(); let packet = Packet::receive(&mut stream).unwrap(); assert_eq!(created_packet, packet); } /// Tests if Packet::receive_from works and returns the same data for successive calls. /// Also tests Packet::send_to if correct data are sent. #[test] fn receive_from() { let addrs1 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8001); let addrs2 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8002); let socket1 = UdpSocket::bind(addrs1).unwrap(); let socket2 = UdpSocket::bind(addrs2).unwrap(); let created_packet = Packet::new(PacketKind::Unit, Bytes::from([0, 1, 2, 3, 4, 5])).unwrap(); created_packet.clone().send_to(socket1, addrs2).unwrap(); let (packet, _) = Packet::receive_from(socket2.try_clone().unwrap()).unwrap(); assert_eq!(created_packet, packet); } /// Tests if Packet::peek_from_connected works and returns the same data for successive calls. /// Also tests Packet::send_to_connected if correct data are sent. #[test] fn receive_from_connected() { let addrs1 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8003); let addrs2 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8004); let socket1 = UdpSocket::bind(addrs1).unwrap(); let socket2 = UdpSocket::bind(addrs2).unwrap(); socket1.connect(addrs2).unwrap(); let created_packet = Packet::new(PacketKind::Unit, Bytes::from([0, 1, 2, 3, 4, 5])).unwrap(); created_packet.clone().send_to_connected(socket1).unwrap(); let packet = Packet::receive_from_connected(socket2.try_clone().unwrap()).unwrap(); assert_eq!(created_packet, packet); } /// Tests if Packet::peek works and returns the same data for successive calls. /// Also tests Packet::send if correct data are sent. #[test] fn peek() { let addrs = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8005); let listener = TcpListener::bind(addrs).unwrap(); let created_packet = Packet::new(PacketKind::Unit, Bytes::from([0, 1, 2, 3, 4, 5])).unwrap(); let created_packet_in_thread = created_packet.clone(); std::thread::spawn(move || { std::thread::sleep(std::time::Duration::from_secs(1)); let packet = created_packet_in_thread; let mut stream = TcpStream::connect(addrs).unwrap(); packet.send(&mut stream).unwrap(); }); let mut received = Vec::new(); let (mut stream, _) = listener.accept().unwrap(); for _ in 0..10 { let packet = Packet::peek(&mut stream); received.push(packet); } assert!(received .into_iter() .map(|recv| recv.unwrap()) .collect::>() .into_iter() .all(|packet| packet == created_packet)) } /// Tests if Packet::peek_from a works and returns the same data for successive calls. /// Also tests Packet::send_to if correct data are sent. #[test] fn peek_from_and_send_to() { let addrs1 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8006); let addrs2 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8007); let socket1 = UdpSocket::bind(addrs1).unwrap(); let socket2 = UdpSocket::bind(addrs2).unwrap(); let created_packet = Packet::new(PacketKind::Unit, Bytes::from([0, 1, 2, 3, 4, 5])).unwrap(); created_packet.clone().send_to(socket1, addrs2).unwrap(); let mut received = Vec::new(); for _ in 0..10 { let packet = Packet::peek_from(socket2.try_clone().unwrap()); received.push(packet); } assert!(received .into_iter() .map(|recv| { let (packet, _) = recv.unwrap(); packet }) .collect::>() .into_iter() .all(|packet| packet == created_packet)) } /// Tests if Packet::peek_from_connected works and returns the same data for successive calls. /// Also tests Packet::send_to_connected if correct data are sent. #[test] fn peek_from_and_send_to_connected() { let addrs1 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8008); let addrs2 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8009); let socket1 = UdpSocket::bind(addrs1).unwrap(); let socket2 = UdpSocket::bind(addrs2).unwrap(); socket1.connect(addrs2).unwrap(); let created_packet = Packet::new(PacketKind::Unit, Bytes::from([0, 1, 2, 3, 4, 5])).unwrap(); created_packet.clone().send_to_connected(socket1).unwrap(); let mut received = Vec::new(); for _ in 0..10 { let packet = Packet::peek_from_connected(socket2.try_clone().unwrap()); received.push(packet); } assert!(received .into_iter() .map(|recv| recv.unwrap()) .collect::>() .into_iter() .all(|packet| packet == created_packet)) } /// Tests if Packet::number_of_packets returns a correct number of packets. #[test] fn number_of_packets() { assert_eq!(5, Packet::number_of_packets(5000)); } /// Tests if Packet::split_to_max_packet_size splits given buffer to correctly sized packets. /// /// This test might fail if Packet::max_size is changed between setting it in this test and call of /// Packet::split_to_max_packet_size by other test which makes it to created differently sized buffers than /// those against it is checked. /// /// It is not a design problem of the function, it actually shows that the function /// works correctly, but the test itself is poorly written. /// /// The simplest solutions is to run it by itself or run all tests limited to one thread, so there is no call that /// would change the maximum size of the Packet. #[test] fn split_to_max_packet_size() { let buff: Bytes = vec![0_u8; 9].into(); Packet::set_max_size(6); let packets = Packet::split_to_max_packet_size(buff); let manual_packets: Vec = vec![ vec![0_u8; 2].into(), vec![0_u8; 2].into(), vec![0_u8; 2].into(), vec![0_u8; 2].into(), vec![0_u8; 1].into(), ]; assert_eq!( manual_packets, packets, "Check the test description, this might be a false failure." ); } /// Tests if Packet::max_size works correctly in single threaded context. #[test] fn max_size_single_threaded_access() { Packet::set_max_size(1024); assert_eq!(1024, Packet::max_size()) } /// Tests if Packet::max_size works correctly in multi threaded context. #[test] fn max_size_multiple_threads_access() { Packet::set_max_size(1024); let mut receivers = Vec::new(); for _ in 0..10 { let (p, c) = std::sync::mpsc::channel(); receivers.push(c); std::thread::spawn(move || { let mut is_correct = true; for _ in 0..100 { if Packet::max_size() != 1024 { is_correct = false; } std::thread::sleep(std::time::Duration::new(0, 0)); } p.send(is_correct).unwrap(); }); } assert!( receivers .iter() .map(|recv| recv.recv().unwrap()) .collect::>() .into_iter() .all(|v| v), "This might be a false failure if tests are run in parallel." ); } /// Tests if Packet::set_max_size works correctly in multi threaded context by creating multiple threads /// and successively setting MAX_SIZE to randomly generated number. #[test] fn set_max_size_multiple_threads_access() { let (p, c) = std::sync::mpsc::sync_channel(1000); for _ in 0..10 { let p_into_thread = p.clone(); std::thread::spawn(move || { let mut rng = rand::thread_rng(); for _ in 0..100 { let x: u16 = rng.gen(); Packet::set_max_size(x); p_into_thread.send(x).unwrap(); } }); } // Drop producer in main thread, so last value can be recognized. drop(p); let mut last = None; loop { match c.recv() { Ok(v) => last = Some(v), Err(_) => { // Just a safe check if there is any slowdown from some reason. std::thread::sleep(std::time::Duration::from_secs(1)); match c.recv() { Ok(v) => last = Some(v), Err(_) => { if last.is_none() { panic!(); } break; } } } } } assert_eq!(Packet::max_size(), last.unwrap()); } /// Tests if Packet::max_description_size works correctly in single threaded context. #[test] fn description_size_single_threaded_access() { assert_eq!(4, Packet::description_size()) } /// Tests if Packet::max_size works correctly in multi threaded context. #[test] fn description_size_multiple_threads_access() { let mut receivers = Vec::new(); for _ in 0..10 { let (p, c) = std::sync::mpsc::channel(); receivers.push(c); std::thread::spawn(move || { let mut is_correct = true; for _ in 0..100 { if Packet::description_size() != 4 { is_correct = false; } std::thread::sleep(std::time::Duration::new(0, 0)); } p.send(is_correct).unwrap(); }); } assert!(receivers .iter() .map(|recv| recv.recv().unwrap()) .collect::>() .into_iter() .all(|v| v)); } /// Tests if Packet::max_content_size returns correct value. /// /// This test might fail if Packet::max_size is changed between setting it in this test and call of /// Packet::max_content_size by other test which makes it to created differently sized buffers than /// those against it is checked. /// /// The simplest solutions is to run it by itself or run all tests limited to one thread, so there is no call that /// would change the maximum size of the Packet. #[test] fn max_content_size() { Packet::set_max_size(1024); if (Packet::max_size() == 1024) && (Packet::description_size() == 4) { assert_eq!( 1020, Packet::max_content_size(), "Check test description, might be false failure." ); } }