From 6b6b1185b80434e57d86113b2e66dbd5b8d07369 Mon Sep 17 00:00:00 2001 From: Marcin Anforowicz Date: Wed, 10 Jul 2024 07:24:32 -0700 Subject: [PATCH] Improved tests --- gday/Cargo.toml | 2 +- gday/src/main.rs | 1 - gday/src/tests.rs | 1 - ...ntegration_test.rs => test_integration.rs} | 77 ++++++++++++++----- ...ntegration_test.rs => test_integration.rs} | 20 +++-- gday_hole_punch/Cargo.toml | 2 +- ...ntegration_test.rs => test_integration.rs} | 0 gday_server/Cargo.toml | 2 +- ...ntegration_test.rs => test_integration.rs} | 0 9 files changed, 71 insertions(+), 34 deletions(-) delete mode 100644 gday/src/tests.rs rename gday_encryption/tests/{integration_test.rs => test_integration.rs} (53%) rename gday_file_transfer/tests/{integration_test.rs => test_integration.rs} (95%) rename gday_hole_punch/tests/{integration_test.rs => test_integration.rs} (100%) rename gday_server/tests/{integration_test.rs => test_integration.rs} (100%) diff --git a/gday/Cargo.toml b/gday/Cargo.toml index 2dabf73..2385c30 100644 --- a/gday/Cargo.toml +++ b/gday/Cargo.toml @@ -14,7 +14,7 @@ repository.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -clap = { version = "4.5.8", features = ["derive"] } +clap = { version = "4.5.9", features = ["derive"] } env_logger = "0.11.3" gday_encryption = { version = "^0.2.0", path = "../gday_encryption" } gday_file_transfer = { version = "^0.2.0", path = "../gday_file_transfer" } diff --git a/gday/src/main.rs b/gday/src/main.rs index 4e7f786..c759a0d 100644 --- a/gday/src/main.rs +++ b/gday/src/main.rs @@ -3,7 +3,6 @@ #![warn(clippy::all)] mod dialog; -mod tests; mod transfer; use crate::dialog::ask_receive; diff --git a/gday/src/tests.rs b/gday/src/tests.rs deleted file mode 100644 index 7477a61..0000000 --- a/gday/src/tests.rs +++ /dev/null @@ -1 +0,0 @@ -/* TODO: Add tests! */ diff --git a/gday_encryption/tests/integration_test.rs b/gday_encryption/tests/test_integration.rs similarity index 53% rename from gday_encryption/tests/integration_test.rs rename to gday_encryption/tests/test_integration.rs index 5444c54..38872d0 100644 --- a/gday_encryption/tests/integration_test.rs +++ b/gday_encryption/tests/test_integration.rs @@ -4,36 +4,75 @@ use gday_encryption::EncryptedStream; use rand::{RngCore, SeedableRng}; use std::{ collections::VecDeque, - io::{Read, Write}, - net::Ipv6Addr, - net::SocketAddr, + io::{BufRead, Read, Write}, }; -/// Try to spot edge-cases that occur when sending -/// several large messages. +/// Transfer `bytes` over [`EncryptedStream`], +/// flushing every `chunk_size` bytes. #[test] -fn test_large_messages() { +fn test_transfers() { + // A pseudorandom encryption key + let mut rng = rand::rngs::StdRng::seed_from_u64(5); + let mut shared_key = [0u8; 32]; + rng.fill_bytes(&mut shared_key); + // A pseudorandom test vector let mut rng = rand::rngs::StdRng::seed_from_u64(10); let mut bytes = vec![0_u8; 1_000_000]; rng.fill_bytes(&mut bytes); - test_transfers(bytes, 200_000); + // How many bytes will be sent at a time + let chunk_size = 200_000; + + // Listens on the loopback address + let listener = std::net::TcpListener::bind("[::]:0").unwrap(); + let pipe_addr = listener.local_addr().unwrap(); + + // A thread that will send data to the loopback address + let bytes_clone = bytes.clone(); + std::thread::spawn(move || { + let mut peer_a = std::net::TcpStream::connect(pipe_addr).unwrap(); + + let mut stream_a = EncryptedStream::encrypt_connection(&mut peer_a, &shared_key).unwrap(); + + for chunk in bytes_clone.chunks(chunk_size) { + stream_a.write_all(chunk).unwrap(); + stream_a.flush().unwrap(); + } + }); + + // Stream that will receive the test data sent to the loopback address. + let mut peer_b = listener.accept().unwrap().0; + let mut stream_b = EncryptedStream::encrypt_connection(&mut peer_b, &shared_key).unwrap(); + + // Receive and verify the encrypted test data. + for chunk in bytes.chunks(chunk_size) { + let mut received = vec![0; chunk.len()]; + stream_b.read_exact(&mut received).unwrap(); + assert_eq!(*chunk, received); + } } -/// Transfer `bytes` over [`EncryptedStream`], -/// flushing every `chunk_size` bytes. -fn test_transfers(bytes: Vec, chunk_size: usize) { +/// Test bufread +#[test] +fn test_bufread() { // A pseudorandom encryption key - let mut rng = rand::rngs::StdRng::seed_from_u64(10); + let mut rng = rand::rngs::StdRng::seed_from_u64(20); let mut shared_key = [0u8; 32]; rng.fill_bytes(&mut shared_key); - // The loopback address that peer_a will connect to. - let pipe_addr = SocketAddr::from((Ipv6Addr::LOCALHOST, 2000)); + // A pseudorandom test vector + let mut rng = rand::rngs::StdRng::seed_from_u64(25); + let mut bytes = vec![0_u8; 1_000_000]; + rng.fill_bytes(&mut bytes); + bytes.push(0); + + // How many bytes will be sent at a time + let chunk_size = 200_000; // Listens on the loopback address - let listener = std::net::TcpListener::bind(pipe_addr).unwrap(); + let listener = std::net::TcpListener::bind("[::]:0").unwrap(); + let pipe_addr = listener.local_addr().unwrap(); // A thread that will send data to the loopback address let bytes_clone = bytes.clone(); @@ -53,11 +92,13 @@ fn test_transfers(bytes: Vec, chunk_size: usize) { let mut stream_b = EncryptedStream::encrypt_connection(&mut peer_b, &shared_key).unwrap(); // Receive and verify the encrypted test data. - for chunk in bytes.chunks(chunk_size) { - let mut received = vec![0; chunk.len()]; - stream_b.read_exact(&mut received).unwrap(); - assert_eq!(*chunk, received); + let mut received = Vec::new(); + let zeros = bytes.iter().filter(|num| **num == 0).count(); + for _ in 0..zeros { + let bytes_read = stream_b.read_until(0, &mut received).unwrap(); + assert_ne!(bytes_read, 0); } + assert_eq!(received, bytes); } /// Confirm there are no infinite loops on EOF diff --git a/gday_file_transfer/tests/integration_test.rs b/gday_file_transfer/tests/test_integration.rs similarity index 95% rename from gday_file_transfer/tests/integration_test.rs rename to gday_file_transfer/tests/test_integration.rs index aed4e9d..7f68402 100644 --- a/gday_file_transfer/tests/integration_test.rs +++ b/gday_file_transfer/tests/test_integration.rs @@ -6,7 +6,6 @@ use gday_file_transfer::{ }; use std::fs::{self, create_dir_all}; use std::io::Write; -use std::net::SocketAddr; use std::{fs::File, path::PathBuf}; /// Returns a temporary directory @@ -207,11 +206,9 @@ fn test_get_file_metas_2() { /// Test the file transfer. #[test] fn file_transfer() { - // The loopback address that peer_a will connect to. - let pipe_addr: SocketAddr = "[::1]:2000".parse().unwrap(); - // Listens on the loopback address - let listener = std::net::TcpListener::bind(pipe_addr).unwrap(); + let listener = std::net::TcpListener::bind("[::1]:0").unwrap(); + let pipe_addr = listener.local_addr().unwrap(); // dir_a contains test files, some of which // will be sent @@ -239,14 +236,14 @@ fn file_transfer() { send_files(&file_metas, &response, &mut stream_a, |_| {}).unwrap(); }); - // directory to receive the files in + // dir_b will receive the files in let dir_b = tempfile::tempdir().unwrap(); // create pre-existing file1 and file1 (1) let mut f = File::create_new(dir_b.path().join("file1")).unwrap(); write!(f, "This is a pre-existing file1").unwrap(); let mut f = File::create_new(dir_b.path().join("file1 (1)")).unwrap(); - write!(f, "This is a pre-existing file1 (1)").unwrap(); + write!(f, "This is file1").unwrap(); // create pre-existing file2.txt let mut f = File::create_new(dir_b.path().join("file2.txt")).unwrap(); @@ -258,7 +255,7 @@ fn file_transfer() { let mut f = File::create_new(dir_b.path().join("subdir1/file2.txt.part29")).unwrap(); write!(f, "This is dir/subdi").unwrap(); - // Stream that will receive the files to the loopback address.s + // Stream that will receive the files from the loopback address. let mut stream_b = listener.accept().unwrap().0; // read the file offer message @@ -267,9 +264,9 @@ fn file_transfer() { let response_msg = FileResponseMsg::accept_only_new_and_interrupted(&file_offer, dir_b.path()).unwrap(); - assert_eq!(response_msg.get_num_not_rejected(), 4); + assert_eq!(response_msg.get_num_not_rejected(), 3); assert_eq!(response_msg.get_num_partially_accepted(), 1); - assert_eq!(response_msg.get_num_fully_accepted(), 3); + assert_eq!(response_msg.get_num_fully_accepted(), 2); write_to(&response_msg, &mut stream_b).unwrap(); @@ -300,7 +297,7 @@ fn file_transfer() { ); assert_eq!( fs::read(dir_b.path().join("file1 (1)")).unwrap(), - b"This is a pre-existing file1 (1)" + b"This is file1" ); assert_eq!( fs::read(dir_b.path().join("file2.txt")).unwrap(), @@ -310,6 +307,7 @@ fn file_transfer() { // confirm that files rejected or not offered // weren't downloaded assert!(fs::read(dir_b.path().join("dir/file1")).is_err()); + assert!(fs::read(dir_b.path().join("dir/file1 (2)")).is_err()); assert!(fs::read(dir_b.path().join("dir/file2.txt")).is_err()); assert!(fs::read(dir_b.path().join("dir/subdir2/file1")).is_err()); assert!(fs::read(dir_b.path().join("dir/subdir2/file2.txt")).is_err()); diff --git a/gday_hole_punch/Cargo.toml b/gday_hole_punch/Cargo.toml index 32775a8..4e01244 100644 --- a/gday_hole_punch/Cargo.toml +++ b/gday_hole_punch/Cargo.toml @@ -18,7 +18,7 @@ blake3 = "1.5.1" gday_contact_exchange_protocol = { version = "^0.2.0", path = "../gday_contact_exchange_protocol" } log = "0.4.22" rand = "0.8.5" -rustls = { version = "0.23.10", features = ["ring", "log", "logging", "std", "tls12"], default-features = false } +rustls = { version = "0.23.11", features = ["ring", "log", "logging", "std", "tls12"], default-features = false } serde = "1.0.204" socket2 = { version = "0.5.7", features = ["all"] } spake2 = { version = "0.4.0", features = ["std"] } diff --git a/gday_hole_punch/tests/integration_test.rs b/gday_hole_punch/tests/test_integration.rs similarity index 100% rename from gday_hole_punch/tests/integration_test.rs rename to gday_hole_punch/tests/test_integration.rs diff --git a/gday_server/Cargo.toml b/gday_server/Cargo.toml index 1824e04..c054c57 100644 --- a/gday_server/Cargo.toml +++ b/gday_server/Cargo.toml @@ -14,7 +14,7 @@ repository.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -clap = { version = "4.5.8", features = ["derive"] } +clap = { version = "4.5.9", features = ["derive"] } socket2 = { version = "0.5.7", features = ["all"] } tokio = { version = "1.38.0", features = [ "rt-multi-thread", diff --git a/gday_server/tests/integration_test.rs b/gday_server/tests/test_integration.rs similarity index 100% rename from gday_server/tests/integration_test.rs rename to gday_server/tests/test_integration.rs