//! Common integration test utilities. //! //! `miltertest` is spawned in a separate thread (not main), rather than have //! the actual `Milter` be in a spawned thread and `miltertest` in main: just as //! it is outside of tests. use std::{ ffi::OsString, path::PathBuf, process::{Command, ExitStatus}, thread::{self, JoinHandle}, time::Duration, }; // Integration tests require the `miltertest` program. const MILTERTEST: &str = "miltertest"; pub fn test_name(test_file_name: &str) -> OsString { PathBuf::from(test_file_name) .as_path() .file_stem() .expect("no file stem") .to_os_string() } pub fn spawn_miltertest_runner(test_file_name: &str) -> JoinHandle { let _timeout_thread = thread::spawn(|| { thread::sleep(Duration::from_secs(15)); eprintln!("miltertest runner timed out"); milter::shutdown(); }); let file_name = to_miltertest_file_name(test_file_name); thread::spawn(move || { thread::sleep(Duration::from_millis(100)); let output = Command::new(MILTERTEST) .arg("-s") .arg(&file_name) .output() .expect("miltertest execution failed"); print_output_stream("STDOUT", output.stdout); print_output_stream("STDERR", output.stderr); milter::shutdown(); output.status }) } fn to_miltertest_file_name(file_name: &str) -> OsString { let mut path = PathBuf::from(file_name); path.set_extension("lua"); path.into_os_string() } fn print_output_stream(name: &str, output: Vec) { if !output.is_empty() { let output = String::from_utf8(output).unwrap(); eprintln!("{}:", name); if output.ends_with('\n') { eprint!("{}", &output) } else { eprintln!("{}", &output) } } }