From 3cf01efd8485da8a248ffd509b7ffb881d25433b Mon Sep 17 00:00:00 2001 From: Jacobtread Date: Wed, 22 May 2024 19:05:25 +1200 Subject: [PATCH] feat: windows process constructor, windows tests --- src/signal.rs | 2 +- src/windows.rs | 8 +- tests/killport_windows_tests.rs | 149 ++++++++++++++++++++++++++++++++ 3 files changed, 157 insertions(+), 2 deletions(-) create mode 100644 tests/killport_windows_tests.rs diff --git a/src/signal.rs b/src/signal.rs index 68b5127..7f16e9e 100644 --- a/src/signal.rs +++ b/src/signal.rs @@ -8,7 +8,7 @@ pub struct KillportSignal(pub nix::sys::signal::Signal); /// On a platform where we don't have the proper signals enum #[cfg(not(unix))] -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct KillportSignal(pub String); impl Display for KillportSignal { diff --git a/src/windows.rs b/src/windows.rs index 00a2950..05f6745 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -36,6 +36,12 @@ pub struct WindowsProcess { name: Option, } +impl WindowsProcess { + pub fn new(pid: u32, name: Option) -> Self { + Self { pid, name } + } +} + /// Finds the processes associated with the specified `port`. /// /// Returns a `Vec` of native processes. @@ -65,7 +71,7 @@ pub fn find_target_processes(port: u16) -> Result> { // Collect the processes let mut processes: Vec = pids .into_iter() - .map(|pid| WindowsProcess { pid, name: None }) + .map(|pid| WindowsProcess::new(pid, None)) .collect(); lookup_proccess_names(&mut processes)?; diff --git a/tests/killport_windows_tests.rs b/tests/killport_windows_tests.rs new file mode 100644 index 0000000..6d19668 --- /dev/null +++ b/tests/killport_windows_tests.rs @@ -0,0 +1,149 @@ +#![cfg(windows)] + +use killport::cli::Mode; +use killport::killport::{Killable, KillableType}; +use killport::signal::KillportSignal; +use killport::windows::WindowsProcess; +use mockall::*; + +use std::io::Error; + +// Setup Mocks +mock! { + DockerContainer {} + + impl Killable for DockerContainer { + fn kill(&self, signal: KillportSignal) -> Result; + fn get_type(&self) -> KillableType; + fn get_name(&self) -> String; + } +} + +mock! { + WindowsProcess {} + + impl Killable for WindowsProcess { + fn kill(&self, signal: KillportSignal) -> Result; + fn get_type(&self) -> KillableType; + fn get_name(&self) -> String; + } +} +mock! { + KillportOperations { + fn find_target_killables(&self, port: u16, mode: Mode) -> Result>, Error>; + fn kill_service_by_port(&self, port: u16, signal: KillportSignal, mode: Mode, dry_run: bool) -> Result, Error>; + } +} + +#[test] +fn native_process_kill_succeeds() { + let mut mock_process = MockWindowsProcess::new(); + // Setup the expectation for the mock + mock_process + .expect_kill() + .with(mockall::predicate::eq(KillportSignal( + "SIGKILL".to_string(), + ))) + .times(1) // Ensure the kill method is called exactly once + .returning(|_| Ok(true)); // Simulate successful kill + + assert!(mock_process + .kill(KillportSignal("SIGKILL".to_string())) + .unwrap()); +} + +#[test] +fn docker_container_kill_succeeds() { + let mut mock_container = MockDockerContainer::new(); + mock_container + .expect_kill() + .with(mockall::predicate::eq(KillportSignal( + "SIGKILL".to_string(), + ))) + .times(1) + .returning(|_| Ok(true)); + + assert!(mock_container + .kill(KillportSignal("SIGKILL".to_string())) + .unwrap()); +} + +#[test] +fn find_killables_processes_only() { + let mut mock_killport = MockKillportOperations::new(); + + mock_killport + .expect_find_target_killables() + .withf(|&port, &mode| port == 8080 && mode == Mode::Process) + .returning(|_, _| { + let mut mock_process = MockWindowsProcess::new(); + mock_process + .expect_get_type() + .return_const(KillableType::Process); + mock_process + .expect_get_name() + .return_const("mock_process".to_string()); + Ok(vec![Box::new(mock_process)]) + }); + + let port = 8080; + let mode = Mode::Process; + let found_killables = mock_killport.find_target_killables(port, mode).unwrap(); + assert!(found_killables + .iter() + .all(|k| k.get_type() == KillableType::Process)); +} + +#[test] +fn kill_service_by_port_dry_run() { + let mut mock_killport = MockKillportOperations::new(); + let mut mock_process = MockWindowsProcess::new(); + + mock_process.expect_kill().never(); + mock_process + .expect_get_type() + .return_const(KillableType::Process); + mock_process + .expect_get_name() + .return_const("mock_process".to_string()); + + mock_killport + .expect_kill_service_by_port() + .returning(|_, _, _, _| Ok(vec![(KillableType::Process, "mock_process".to_string())])); + + let port = 8080; + let mode = Mode::Process; + let dry_run = true; + let signal = KillportSignal("SIGKILL".to_string()); + + let results = mock_killport + .kill_service_by_port(port, signal, mode, dry_run) + .unwrap(); + assert_eq!(results.len(), 1); + assert_eq!(results[0].0, KillableType::Process); + assert_eq!(results[0].1, "mock_process"); +} + +#[test] +fn check_process_type_and_name() { + let process = WindowsProcess::new(1234, Some("unique_process".to_string())); + + assert_eq!(process.get_type(), KillableType::Process); + assert_eq!(process.get_name(), "unique_process"); +} + +#[test] +fn check_docker_container_type_and_name() { + let mut mock_container = MockDockerContainer::new(); + mock_container + .expect_get_type() + .times(1) + .returning(|| KillableType::Container); + mock_container + .expect_get_name() + .times(1) + .returning(|| "docker_container".to_string()); + + assert_eq!(mock_container.get_type(), KillableType::Container); + assert_eq!(mock_container.get_name(), "docker_container"); +}