From d41e314aaa62d8f62f6f3b600035fc61ea4e6542 Mon Sep 17 00:00:00 2001 From: JyJyJcr <82190170+JyJyJcr@users.noreply.github.com> Date: Sun, 7 Apr 2024 20:08:07 +0900 Subject: [PATCH] feat: split nginx test util into a module --- src/lib.rs | 5 ++ src/test_util.rs | 184 ++++++++++++++++++++++++++++++++++++++++++++++ tests/log_test.rs | 86 ++-------------------- 3 files changed, 195 insertions(+), 80 deletions(-) create mode 100644 src/test_util.rs diff --git a/src/lib.rs b/src/lib.rs index 4c26d89..85d96ba 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -56,6 +56,11 @@ pub mod http; /// This module provides an interface into the NGINX logger framework. pub mod log; +/// The test utility module. +/// +/// This module provides utilities for integration tests with bundled NGINX. +pub mod test_util; + /// Define modules exported by this library. /// /// These are normally generated by the Nginx module system, but need to be diff --git a/src/test_util.rs b/src/test_util.rs new file mode 100644 index 0000000..a026afa --- /dev/null +++ b/src/test_util.rs @@ -0,0 +1,184 @@ +use std::ffi::OsStr; +use std::fs; +use std::fs::read_dir; +use std::io::Result; +use std::path::Path; +use std::path::PathBuf; +use std::process::Command; +use std::process::Output; + +const NGINX_PREFIX: &str = nginx_sys::metadata::NGINX_INSTALL_DIR; + +const NGINX_SBIN_SUFFIX: &str = "sbin/nginx"; +const NGINX_MODULES_SUFFIX: &str = "modules"; +const NGINX_CONF_SUFFIX: &str = "conf/nginx.conf"; +const NGINX_CONF_PREFIX_SUFFIX: &str = "conf"; +const NGINX_ERROR_LOG_SUFFIX: &str = "logs/error.log"; +const NGINX_PID_SUFFIX: &str = "logs/nginx.pid"; +const NGINX_LOCK_SUFFIX: &str = "logs/nginx.lock"; + +const NGINX_HTTP_LOG_SUFFIX: &str = "logs/access.log"; +const NGINX_HTTP_CLIENT_BODY_SUFFIX: &str = "client_body_temp"; +const NGINX_HTTP_PROXY_TEMP_SUFFIX: &str = "proxy_temp"; +const NGINX_HTTP_FASTCGI_TEMP_SUFFIX: &str = "fastcgi_temp"; +const NGINX_HTTP_UWSGI_TEMP_SUFFIX: &str = "uwsgi_temp"; +const NGINX_HTTP_SCGI_TEMP_SUFFIX: &str = "scgi_temp"; + +/// harness to test nginx +#[allow(dead_code)] +pub struct Nginx { + // these paths have options to change them from default paths (in prefix dir) + // most of them are not used, but keep them for future uses + prefix: PathBuf, + sbin_path: PathBuf, + modules_path: PathBuf, + conf_path: PathBuf, + conf_prefix: PathBuf, + error_log_path: PathBuf, + pid_path: PathBuf, + lock_path: PathBuf, + http_log_path: PathBuf, + http_client_body_temp_path: PathBuf, + http_proxy_temp_path: PathBuf, + http_fastcgi_temp_path: PathBuf, + http_uwsgi_temp_path: PathBuf, + http_scgi_temp_path: PathBuf, +} + +impl Default for Nginx { + fn default() -> Nginx { + Self::new_with_prefix(NGINX_PREFIX.into()) + } +} + +impl Nginx { + /// create nginx with prefix only + pub fn new_with_prefix(prefix: PathBuf) -> Nginx { + Nginx { + sbin_path: prefix.join(NGINX_SBIN_SUFFIX), + modules_path: prefix.join(NGINX_MODULES_SUFFIX), + conf_path: prefix.join(NGINX_CONF_SUFFIX), + conf_prefix: prefix.join(NGINX_CONF_PREFIX_SUFFIX), + error_log_path: prefix.join(NGINX_ERROR_LOG_SUFFIX), + pid_path: prefix.join(NGINX_PID_SUFFIX), + lock_path: prefix.join(NGINX_LOCK_SUFFIX), + http_log_path: prefix.join(NGINX_HTTP_LOG_SUFFIX), + http_client_body_temp_path: prefix.join(NGINX_HTTP_CLIENT_BODY_SUFFIX), + http_proxy_temp_path: prefix.join(NGINX_HTTP_PROXY_TEMP_SUFFIX), + http_fastcgi_temp_path: prefix.join(NGINX_HTTP_FASTCGI_TEMP_SUFFIX), + http_uwsgi_temp_path: prefix.join(NGINX_HTTP_UWSGI_TEMP_SUFFIX), + http_scgi_temp_path: prefix.join(NGINX_HTTP_SCGI_TEMP_SUFFIX), + prefix, + } + } + + /// execute nginx process with arguments + pub fn cmd(&mut self, args: &[&str]) -> Result { + let result = Command::new(&self.sbin_path).args(args).output(); + + match result { + Err(e) => Err(e), + + Ok(output) => { + println!("status: {}", output.status); + println!("stdout: {}", String::from_utf8_lossy(&output.stdout)); + println!("stderr: {}", String::from_utf8_lossy(&output.stderr)); + Ok(output) + } + } + } + + /// complete stop the nginx binary + pub fn stop(&mut self) -> Result { + self.cmd(&["-s", "stop"]) + } + + /// start the nginx binary + pub fn start(&mut self) -> Result { + self.cmd(&[]) + } + + /// make sure we stop existing nginx and start new master process + /// intentinally ignore failure in stop + pub fn restart(&mut self) -> Result { + let _ = self.stop(); + self.start() + } + + /// replace config with another config + pub fn copy_config(&mut self, conf_path_from: &Path) -> Result { + let conf_path_to = self + .conf_prefix + .join(conf_path_from.file_name().unwrap_or(OsStr::new("unknown_conf"))); + println!( + "copying config from: {} to: {}", + conf_path_to.display(), + conf_path_from.display() + ); // replace with logging + fs::copy(conf_path_from, conf_path_to) + } + /// create config from &str + pub fn create_config_from_str(&mut self, conf_suffix: &str, conf_content: &str) -> Result<()> { + let conf_path_to = self.conf_prefix.join(conf_suffix); + println!( + "creating config to: {} content: {}", + conf_path_to.display(), + conf_content + ); // replace with logging + fs::write(conf_path_to, conf_content) + } + /// ensure the existance module dir + fn ensure_module_dir(&mut self) -> Result<()> { + fs::create_dir_all(&self.modules_path) + } + /// copy or replace module + pub fn copy_module(&mut self, module_path_from: &Path) -> Result { + self.ensure_module_dir()?; + let module_path_to = self + .modules_path + .join(module_path_from.file_name().unwrap_or(OsStr::new("unknown_module"))); + println!( + "copying module from: {} to: {}", + module_path_to.display(), + module_path_from.display() + ); // replace with logging + fs::copy(module_path_from, module_path_to) + } + /// return prefix + pub fn prefix(&mut self) -> &Path { + &self.prefix + } +} + +#[cfg(target_os = "macos")] +fn target_cands() -> Option> { + match std::env::var("DYLD_FALLBACK_LIBRARY_PATH") { + Ok(cands) => Some(cands.split(':').map(PathBuf::from).collect()), + Err(_) => None, + } +} +#[cfg(target_os = "linux")] +fn target_dir_cands() -> Option> { + match std::env::var("LD_LIBRARY_PATH") { + Ok(cands) => Some(cands.split(':').map(PathBuf::from).collect()), + Err(_) => None, + } +} + +/// search path and return the path to the target +pub fn target_path(target_name: &str) -> std::io::Result { + if let Some(cands) = target_cands() { + for dir in cands { + if let Ok(iter) = read_dir(dir) { + for entry in iter { + if let Ok(entry) = entry { + if entry.file_name() == target_name { + return Ok(entry.path()); + } + } + } + } + } + } + Err(std::io::ErrorKind::NotFound.into()) +} diff --git a/tests/log_test.rs b/tests/log_test.rs index 09325d2..e169892 100644 --- a/tests/log_test.rs +++ b/tests/log_test.rs @@ -1,81 +1,7 @@ -use std::fs; -use std::io::Result; -use std::process::Command; -use std::process::Output; - -const NGINX_BIN: &str = "sbin/nginx"; -const NGINX_CONFIG: &str = "conf/nginx.conf"; - -/// harness to test nginx -pub struct Nginx { - pub install_path: String, -} - -impl Default for Nginx { - /// create nginx with default - fn default() -> Nginx { - Nginx { - install_path: nginx_sys::metadata::NGINX_INSTALL_DIR.into(), - } - } -} - -impl Nginx { - pub fn new(path: String) -> Nginx { - Nginx { install_path: path } - } - - /// get bin path to nginx instance - pub fn bin_path(&mut self) -> String { - format!("{}/{}", self.install_path, NGINX_BIN) - } - - /// start nginx process with arguments - pub fn cmd(&mut self, args: &[&str]) -> Result { - let bin_path = self.bin_path(); - let result = Command::new(bin_path).args(args).output(); - - match result { - Err(e) => Err(e), - - Ok(output) => { - println!("status: {}", output.status); - println!("stdout: {}", String::from_utf8_lossy(&output.stdout)); - println!("stderr: {}", String::from_utf8_lossy(&output.stderr)); - Ok(output) - } - } - } - - /// complete stop the nginx binary - pub fn stop(&mut self) -> Result { - self.cmd(&["-s", "stop"]) - } - - /// start the nginx binary - pub fn start(&mut self) -> Result { - self.cmd(&[]) - } - - // make sure we stop existing nginx and start new master process - // intentinally ignore failure in stop - pub fn restart(&mut self) -> Result { - let _ = self.stop(); - self.start() - } - - // replace config with another config - pub fn replace_config(&mut self, from: &str) -> Result { - let config_path = format!("{}/{}", self.install_path, NGINX_CONFIG); - println!("copying config from: {} to: {}", from, config_path); // replace with logging - fs::copy(from, config_path) - } -} - #[cfg(test)] mod tests { - use super::*; - use std::env; + use ngx::test_util::Nginx; + use std::env::current_dir; const TEST_NGINX_CONFIG: &str = "tests/nginx.conf"; @@ -83,19 +9,19 @@ mod tests { fn test() { let mut nginx = Nginx::default(); - let current_dir = env::current_dir().expect("Unable to get current directory"); + let current_dir = current_dir().expect("Unable to get current directory"); let test_config_path = current_dir.join(TEST_NGINX_CONFIG); assert!( - test_config_path.exists(), + test_config_path.is_file(), "Config file not found: {}\nCurrent directory: {}", test_config_path.to_string_lossy(), current_dir.to_string_lossy() ); nginx - .replace_config(&test_config_path.to_string_lossy()) - .expect(format!("Unable to load config file: {}", test_config_path.to_string_lossy()).as_str()); + .copy_config(&test_config_path) + .expect(format!("Unable to load config file: {}", test_config_path.display()).as_str()); let output = nginx.restart().expect("Unable to restart NGINX"); assert!(output.status.success());