From b9f32d720ae5ec60cadeb492af781ade48cd6cbf Mon Sep 17 00:00:00 2001 From: Quentin Dufour Date: Fri, 8 Mar 2024 10:20:45 +0100 Subject: Finalize Aerogramme's refactor --- aerogramme/tests/common/mod.rs | 99 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 aerogramme/tests/common/mod.rs (limited to 'aerogramme/tests/common/mod.rs') diff --git a/aerogramme/tests/common/mod.rs b/aerogramme/tests/common/mod.rs new file mode 100644 index 0000000..cbe0271 --- /dev/null +++ b/aerogramme/tests/common/mod.rs @@ -0,0 +1,99 @@ +#![allow(dead_code)] +pub mod constants; +pub mod fragments; + +use anyhow::{bail, Context, Result}; +use std::io::Read; +use std::net::{Shutdown, TcpStream}; +use std::process::Command; +use std::thread; + +use constants::SMALL_DELAY; + +pub fn aerogramme_provider_daemon_dev( + mut fx: impl FnMut(&mut TcpStream, &mut TcpStream) -> Result<()>, +) -> Result<()> { + // Check port is not used (= free) before starting the test + let mut max_retry = 20; + loop { + max_retry -= 1; + match (TcpStream::connect("[::1]:1143"), max_retry) { + (Ok(_), 0) => bail!("something is listening on [::1]:1143 and prevent the test from starting"), + (Ok(_), _) => println!("something is listening on [::1]:1143, maybe a previous daemon quitting, retrying soon..."), + (Err(_), _) => { + println!("test ready to start, [::1]:1143 is free!"); + break + } + } + thread::sleep(SMALL_DELAY); + } + + // Start daemon + let mut daemon = Command::new(env!("CARGO_BIN_EXE_aerogramme")) + .arg("--dev") + .arg("provider") + .arg("daemon") + .spawn()?; + + // Check that our daemon is correctly listening on the free port + let mut max_retry = 20; + let mut imap_socket = loop { + max_retry -= 1; + match (TcpStream::connect("[::1]:1143"), max_retry) { + (Err(e), 0) => bail!("no more retry, last error is: {}", e), + (Err(e), _) => { + println!("unable to connect: {} ; will retry soon...", e); + } + (Ok(v), _) => break v, + } + thread::sleep(SMALL_DELAY); + }; + + // Assuming now it's safe to open a LMTP socket + let mut lmtp_socket = + TcpStream::connect("[::1]:1025").context("lmtp socket must be connected")?; + + println!("-- ready to test imap features --"); + let result = fx(&mut imap_socket, &mut lmtp_socket); + println!("-- test teardown --"); + + imap_socket + .shutdown(Shutdown::Both) + .context("closing imap socket at the end of the test")?; + lmtp_socket + .shutdown(Shutdown::Both) + .context("closing lmtp socket at the end of the test")?; + daemon.kill().context("daemon should be killed")?; + + result.context("all tests passed") +} + +pub fn read_lines<'a, F: Read>( + reader: &mut F, + buffer: &'a mut [u8], + stop_marker: Option<&[u8]>, +) -> Result<&'a [u8]> { + let mut nbytes = 0; + loop { + nbytes += reader.read(&mut buffer[nbytes..])?; + //println!("partial read: {}", std::str::from_utf8(&buffer[..nbytes])?); + let pre_condition = match stop_marker { + None => true, + Some(mark) => buffer[..nbytes].windows(mark.len()).any(|w| w == mark), + }; + if pre_condition && nbytes >= 2 && &buffer[nbytes - 2..nbytes] == &b"\r\n"[..] { + break; + } + } + println!("read: {}", std::str::from_utf8(&buffer[..nbytes])?); + Ok(&buffer[..nbytes]) +} + +pub fn read_first_u32(inp: &str) -> Result { + Ok(inp + .chars() + .skip_while(|c| !c.is_digit(10)) + .take_while(|c| c.is_digit(10)) + .collect::() + .parse::()?) +} -- cgit v1.2.3