diff --git a/Cargo.lock b/Cargo.lock index 69b752d4f83c1..68e9a40c1c6ba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13213,7 +13213,7 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "vdev" -version = "0.3.35" +version = "0.3.36" dependencies = [ "anyhow", "cfg-if", diff --git a/Makefile b/Makefile index 4ba5895cc7c80..baa6aafab5c11 100644 --- a/Makefile +++ b/Makefile @@ -304,9 +304,6 @@ test-integration-%-cleanup: test-integration-%: $(VDEV) --verbose integration test $* -ifeq ($(AUTODESPAWN), true) - make test-integration-$*-cleanup -endif .PHONY: test-e2e-kubernetes test-e2e-kubernetes: ## Runs Kubernetes E2E tests diff --git a/vdev/Cargo.toml b/vdev/Cargo.toml index e314d17c7067f..f4eb71c9d25fc 100644 --- a/vdev/Cargo.toml +++ b/vdev/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "vdev" -version = "0.3.35" +version = "0.3.36" edition = "2024" authors = ["Vector Contributors "] license = "MPL-2.0" diff --git a/vdev/src/commands/compose_tests/test.rs b/vdev/src/commands/compose_tests/test.rs index b8bcbcb0c7d02..7898a8fcd7680 100644 --- a/vdev/src/commands/compose_tests/test.rs +++ b/vdev/src/commands/compose_tests/test.rs @@ -10,6 +10,52 @@ use crate::testing::{ use super::active_projects::find_active_environment_for_integration; +/// RAII guard that triggers test environment cleanup. +/// +/// Cleanup is skipped if disabled via `AUTODESPAWN` or `AUTOSPAWN` environment +/// variables, or if the environment was already running prior to the test execution +/// (preserving caller-owned environments and fast repeated runs). +struct DespawnGuard<'a> { + local_config: ComposeTestLocalConfig, + test_name: &'a str, + should_despawn: bool, +} + +impl<'a> DespawnGuard<'a> { + pub fn new( + local_config: ComposeTestLocalConfig, + test_name: &'a str, + was_running: bool, + ) -> Self { + let auto_despawn = std::env::var("AUTODESPAWN") + .or_else(|_| std::env::var("AUTOSPAWN")) + .map_or(true, |v| v.eq_ignore_ascii_case("true")); + + let should_despawn = auto_despawn && !was_running; + Self { + local_config, + test_name, + should_despawn, + } + } + + pub fn disarm_and_stop(mut self) -> Result<()> { + if self.should_despawn { + self.should_despawn = false; + super::stop::exec(self.local_config, self.test_name)?; + } + Ok(()) + } +} + +impl Drop for DespawnGuard<'_> { + fn drop(&mut self) { + if self.should_despawn { + let _ = super::stop::exec(self.local_config, self.test_name); + } + } +} + pub fn exec( local_config: ComposeTestLocalConfig, integration: &str, @@ -39,7 +85,10 @@ pub fn exec( } let mut ran_environments = Vec::new(); + let is_running = active.is_some(); for environment in environments { + let despawn_guard = DespawnGuard::new(local_config, integration, is_running); + run_environment( local_config, integration, @@ -51,6 +100,7 @@ pub fn exec( if coverage { ran_environments.push(environment.clone()); } + despawn_guard.disarm_and_stop()?; } if coverage {