diff --git a/testcontainers/src/core/client.rs b/testcontainers/src/core/client.rs index 0b36c6a2..06a20541 100644 --- a/testcontainers/src/core/client.rs +++ b/testcontainers/src/core/client.rs @@ -162,9 +162,16 @@ impl Client { .map_err(ClientError::RemoveContainer) } - pub(crate) async fn stop(&self, id: &str) -> Result<(), ClientError> { + pub(crate) async fn stop( + &self, + id: &str, + timeout_seconds: Option, + ) -> Result<(), ClientError> { self.bollard - .stop_container(id, None) + .stop_container( + id, + timeout_seconds.map(|t| bollard::container::StopContainerOptions { t }), + ) .await .map_err(ClientError::StopContainer) } @@ -497,10 +504,10 @@ where message, } => io::Error::new( io::ErrorKind::UnexpectedEof, - format!("Docker container has been dropped: {}", message), + format!("Docker container has been dropped: {message}"), ), bollard::errors::Error::IOError { err } => err, - err => io::Error::new(io::ErrorKind::Other, err), + err => io::Error::other(err), }) .boxed(); LogStream::new(stream) diff --git a/testcontainers/src/core/containers/async_container.rs b/testcontainers/src/core/containers/async_container.rs index f618d74a..e8ff8c97 100644 --- a/testcontainers/src/core/containers/async_container.rs +++ b/testcontainers/src/core/containers/async_container.rs @@ -183,7 +183,7 @@ where let network_settings = self.docker_client.inspect_network(&network_mode).await?; network_settings.driver.ok_or_else(|| { - TestcontainersError::other(format!("network {} is not in bridge mode", network_mode)) + TestcontainersError::other(format!("network {network_mode} is not in bridge mode")) })?; let container_network_settings = container_settings @@ -280,11 +280,27 @@ where Ok(()) } - /// Stops the container (not the same with `pause`). + /// Stops the container (not the same with `pause`) using the default 10 second timeout pub async fn stop(&self) -> Result<()> { - log::debug!("Stopping docker container {}", self.id); + self.stop_with_timeout(None).await?; + Ok(()) + } + + /// Stops the container with timeout before issuing SIGKILL (not the same with `pause`). + /// + /// Set Some(-1) to wait indefinitely, None to use system configured default and Some(0) + /// to forcibly stop the container immediately - otherwise the runtime will issue SIGINT + /// and then wait timeout_seconds seconds for the process to stop before issuing SIGKILL. + pub async fn stop_with_timeout(&self, timeout_seconds: Option) -> Result<()> { + log::debug!( + "Stopping docker container {} with {} second timeout", + self.id, + timeout_seconds + .map(|t| t.to_string()) + .unwrap_or("'system default'".into()) + ); - self.docker_client.stop(&self.id).await?; + self.docker_client.stop(&self.id, timeout_seconds).await?; Ok(()) } diff --git a/testcontainers/src/core/containers/sync_container.rs b/testcontainers/src/core/containers/sync_container.rs index 7b26e36f..6ff3e2ab 100644 --- a/testcontainers/src/core/containers/sync_container.rs +++ b/testcontainers/src/core/containers/sync_container.rs @@ -127,11 +127,21 @@ where }) } - /// Stops the container (not the same with `pause`). + /// Stops the container (not the same with `pause`) using the default 10 second timeout. pub fn stop(&self) -> Result<()> { self.rt().block_on(self.async_impl().stop()) } + /// Stops the container with timeout before issuing SIGKILL (not the same with `pause`). + /// + /// Set Some(-1) to wait indefinitely, None to use system configured default and Some(0) + /// to forcibly stop the container immediately - otherwise the runtime will issue SIGINT + /// and then wait timeout_seconds seconds for the process to stop before issuing SIGKILL. + pub fn stop_with_timeout(&self, timeout_seconds: Option) -> Result<()> { + self.rt() + .block_on(self.async_impl().stop_with_timeout(timeout_seconds)) + } + /// Starts the container. pub fn start(&self) -> Result<()> { self.rt().block_on(self.async_impl().start()) diff --git a/testcontainers/src/core/logs/consumer/logging_consumer.rs b/testcontainers/src/core/logs/consumer/logging_consumer.rs index 4f9ce383..de2cf71f 100644 --- a/testcontainers/src/core/logs/consumer/logging_consumer.rs +++ b/testcontainers/src/core/logs/consumer/logging_consumer.rs @@ -47,7 +47,7 @@ impl LoggingConsumer { let message = message.trim_end_matches(['\n', '\r']); if let Some(prefix) = &self.prefix { - Cow::Owned(format!("{} {}", prefix, message)) + Cow::Owned(format!("{prefix} {message}")) } else { Cow::Borrowed(message) } diff --git a/testcontainers/src/core/logs/stream.rs b/testcontainers/src/core/logs/stream.rs index 898245c6..4299ca67 100644 --- a/testcontainers/src/core/logs/stream.rs +++ b/testcontainers/src/core/logs/stream.rs @@ -79,12 +79,8 @@ impl LogStream { } Err(err) => { let err = Arc::new(err); - handle_error!( - stdout_tx.send(Err(io::Error::new(io::ErrorKind::Other, err.clone()))) - ); - handle_error!( - stderr_tx.send(Err(io::Error::new(io::ErrorKind::Other, err))) - ); + handle_error!(stdout_tx.send(Err(io::Error::other(err.clone())))); + handle_error!(stderr_tx.send(Err(io::Error::other(err)))); } } } diff --git a/testcontainers/src/core/wait/mod.rs b/testcontainers/src/core/wait/mod.rs index afb258d7..d6752a47 100644 --- a/testcontainers/src/core/wait/mod.rs +++ b/testcontainers/src/core/wait/mod.rs @@ -41,7 +41,7 @@ pub enum WaitFor { /// Wait for a certain HTTP response. #[cfg(feature = "http_wait")] #[cfg_attr(docsrs, doc(cfg(feature = "http_wait")))] - Http(HttpWaitStrategy), + Http(Box), /// Wait for the container to exit. Exit(ExitWaitStrategy), } @@ -74,7 +74,7 @@ impl WaitFor { #[cfg(feature = "http_wait")] #[cfg_attr(docsrs, doc(cfg(feature = "http_wait")))] pub fn http(http_strategy: HttpWaitStrategy) -> WaitFor { - WaitFor::Http(http_strategy) + WaitFor::Http(Box::new(http_strategy)) } /// Wait for the container to exit. @@ -121,7 +121,7 @@ impl WaitFor { #[cfg_attr(docsrs, doc(cfg(feature = "http_wait")))] impl From for WaitFor { fn from(value: HttpWaitStrategy) -> Self { - Self::Http(value) + Self::Http(Box::new(value)) } } diff --git a/testcontainers/src/runners/async_runner.rs b/testcontainers/src/runners/async_runner.rs index 42f0dcc1..3d98bf1d 100644 --- a/testcontainers/src/runners/async_runner.rs +++ b/testcontainers/src/runners/async_runner.rs @@ -290,8 +290,7 @@ where res => res, }?; - let copy_to_sources: Vec<&CopyToContainer> = - container_req.copy_to_sources().map(Into::into).collect(); + let copy_to_sources: Vec<&CopyToContainer> = container_req.copy_to_sources().collect(); for copy_to_source in copy_to_sources { client diff --git a/testcontainers/src/watchdog.rs b/testcontainers/src/watchdog.rs index 232c9a63..fa091f0f 100644 --- a/testcontainers/src/watchdog.rs +++ b/testcontainers/src/watchdog.rs @@ -34,7 +34,7 @@ static WATCHDOG: Lazy> = Lazy::new(|| { .unwrap_or_default() { signal_docker - .stop(&container_id) + .stop(&container_id, None) .await .expect("failed to stop container"); signal_docker