From e4e346c5f3d332fc04fde51d8ec6780163dd837b Mon Sep 17 00:00:00 2001 From: tison Date: Mon, 1 Dec 2025 13:45:03 +0800 Subject: [PATCH 1/3] fix: reuse container requires name Signed-off-by: tison --- .../src/core/containers/sync_container.rs | 21 +++++++------------ testcontainers/src/core/env/config.rs | 3 +++ testcontainers/src/runners/async_runner.rs | 11 +++++++++- 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/testcontainers/src/core/containers/sync_container.rs b/testcontainers/src/core/containers/sync_container.rs index c6b228ec..2319d5cf 100644 --- a/testcontainers/src/core/containers/sync_container.rs +++ b/testcontainers/src/core/containers/sync_container.rs @@ -1,9 +1,7 @@ use std::{fmt, io::BufRead, net::IpAddr, sync::Arc}; use crate::{ - core::{ - copy::CopyFileFromContainer, env, error::Result, ports::Ports, ContainerPort, ExecCommand, - }, + core::{copy::CopyFileFromContainer, error::Result, ports::Ports, ContainerPort, ExecCommand}, ContainerAsync, Image, }; @@ -257,17 +255,12 @@ where impl Drop for Container { fn drop(&mut self) { - if let Some(active) = self.inner.take() { - active.runtime.block_on(async { - match active.async_impl.docker_client().config.command() { - env::Command::Remove => { - if let Err(e) = active.async_impl.rm().await { - log::error!("Failed to remove container on drop: {}", e); - } - } - env::Command::Keep => {} - } - }); + if let Some(ActiveContainer { + runtime, + async_impl, + }) = self.inner.take() + { + runtime.block_on(async { drop(async_impl) }); } } } diff --git a/testcontainers/src/core/env/config.rs b/testcontainers/src/core/env/config.rs index 655cf26e..3ee6ca02 100644 --- a/testcontainers/src/core/env/config.rs +++ b/testcontainers/src/core/env/config.rs @@ -17,6 +17,9 @@ pub enum ConfigurationError { #[cfg(feature = "properties-config")] #[error("failed to load testcontainers properties: {0}")] WrongPropertiesFormat(#[from] serde_java_properties::de::Error), + #[cfg(feature = "reusable-containers")] + #[error("container name must be provided when reusing containers")] + MissingContainerName, } /// The default path to the Docker configuration file. diff --git a/testcontainers/src/runners/async_runner.rs b/testcontainers/src/runners/async_runner.rs index ff969d0b..50dc8082 100644 --- a/testcontainers/src/runners/async_runner.rs +++ b/testcontainers/src/runners/async_runner.rs @@ -117,12 +117,21 @@ where #[cfg(feature = "reusable-containers")] { + use crate::core::env::ConfigurationError; use crate::ReuseDirective::{Always, CurrentSession}; + use crate::TestcontainersError; if matches!(container_req.reuse(), Always | CurrentSession) { + let container_name = + container_req.container_name().as_deref().ok_or_else(|| { + TestcontainersError::Client(ClientError::Configuration( + ConfigurationError::MissingContainerName, + )) + })?; + if let Some(container_id) = client .get_running_container_id( - container_req.container_name().as_deref(), + Some(container_name), container_req.network().as_deref(), &labels, ) From 8cd16dab91048c866cde7887121a6b434e329b6f Mon Sep 17 00:00:00 2001 From: tison Date: Mon, 1 Dec 2025 15:13:33 +0800 Subject: [PATCH 2/3] fixup cargo fmt Signed-off-by: tison --- testcontainers/src/runners/async_runner.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/testcontainers/src/runners/async_runner.rs b/testcontainers/src/runners/async_runner.rs index 50dc8082..5df3f36b 100644 --- a/testcontainers/src/runners/async_runner.rs +++ b/testcontainers/src/runners/async_runner.rs @@ -117,9 +117,11 @@ where #[cfg(feature = "reusable-containers")] { - use crate::core::env::ConfigurationError; - use crate::ReuseDirective::{Always, CurrentSession}; - use crate::TestcontainersError; + use crate::{ + core::env::ConfigurationError, + ReuseDirective::{Always, CurrentSession}, + TestcontainersError, + }; if matches!(container_req.reuse(), Always | CurrentSession) { let container_name = From 499d5c61e67cfcc337e24941c9797c94666f16e0 Mon Sep 17 00:00:00 2001 From: tison Date: Mon, 1 Dec 2025 15:28:34 +0800 Subject: [PATCH 3/3] fixup config checks Signed-off-by: tison --- testcontainers/src/core/env/config.rs | 4 ++-- testcontainers/src/runners/async_runner.rs | 13 ++++++------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/testcontainers/src/core/env/config.rs b/testcontainers/src/core/env/config.rs index 3ee6ca02..05ffd1ee 100644 --- a/testcontainers/src/core/env/config.rs +++ b/testcontainers/src/core/env/config.rs @@ -18,8 +18,8 @@ pub enum ConfigurationError { #[error("failed to load testcontainers properties: {0}")] WrongPropertiesFormat(#[from] serde_java_properties::de::Error), #[cfg(feature = "reusable-containers")] - #[error("container name must be provided when reusing containers")] - MissingContainerName, + #[error("container name or labels must be provided when reusing containers")] + MissingContainerNameAndLabels, } /// The default path to the Docker configuration file. diff --git a/testcontainers/src/runners/async_runner.rs b/testcontainers/src/runners/async_runner.rs index 5df3f36b..22575698 100644 --- a/testcontainers/src/runners/async_runner.rs +++ b/testcontainers/src/runners/async_runner.rs @@ -124,16 +124,15 @@ where }; if matches!(container_req.reuse(), Always | CurrentSession) { - let container_name = - container_req.container_name().as_deref().ok_or_else(|| { - TestcontainersError::Client(ClientError::Configuration( - ConfigurationError::MissingContainerName, - )) - })?; + if labels.is_empty() && container_req.container_name().is_none() { + return Err(TestcontainersError::Client(ClientError::Configuration( + ConfigurationError::MissingContainerNameAndLabels, + ))); + } if let Some(container_id) = client .get_running_container_id( - Some(container_name), + container_req.container_name().as_deref(), container_req.network().as_deref(), &labels, )