diff --git a/src/e2e/docker.rs b/src/e2e/docker.rs index 75c67d64..6eb64783 100644 --- a/src/e2e/docker.rs +++ b/src/e2e/docker.rs @@ -18,8 +18,12 @@ impl Drop for RunningContainer { /// Ensures that the temporary container is stopped and removed when the /// struct goes out of scope. fn drop(&mut self) { - let _unused = Docker::stop(self); - let _unused = Docker::remove(&self.name); + if Docker::is_container_running(&self.name) { + let _unused = Docker::stop(self); + } + if Docker::container_exist(&self.name) { + let _unused = Docker::remove(&self.name); + } } } @@ -180,4 +184,50 @@ impl Docker { false } + + /// Checks if a Docker container is running. + /// + /// # Arguments + /// + /// * `container` - The name of the Docker container. + /// + /// # Returns + /// + /// `true` if the container is running, `false` otherwise. + #[must_use] + pub fn is_container_running(container: &str) -> bool { + match Command::new("docker") + .args(["ps", "-f", &format!("name={container}"), "--format", "{{.Names}}"]) + .output() + { + Ok(output) => { + let output_str = String::from_utf8_lossy(&output.stdout); + output_str.contains(container) + } + Err(_) => false, + } + } + + /// Checks if a Docker container exists. + /// + /// # Arguments + /// + /// * `container` - The name of the Docker container. + /// + /// # Returns + /// + /// `true` if the container exists, `false` otherwise. + #[must_use] + pub fn container_exist(container: &str) -> bool { + match Command::new("docker") + .args(["ps", "-a", "-f", &format!("name={container}"), "--format", "{{.Names}}"]) + .output() + { + Ok(output) => { + let output_str = String::from_utf8_lossy(&output.stdout); + output_str.contains(container) + } + Err(_) => false, + } + } } diff --git a/src/e2e/runner.rs b/src/e2e/runner.rs index 058ebed4..37006954 100644 --- a/src/e2e/runner.rs +++ b/src/e2e/runner.rs @@ -57,6 +57,8 @@ pub fn run() { let running_services = parse_running_services_from_logs(&container); + assert_there_are_no_panics_in_logs(&container); + assert_there_is_at_least_one_service_per_type(&running_services); let tracker_checker_config = @@ -69,9 +71,12 @@ pub fn run() { run_tracker_checker(&tracker_checker_config_path).expect("Tracker checker should check running services"); - // More E2E tests could be executed here in the future. For example: `cargo test ...`. + // More E2E tests could be added here in the future. + // For example: `cargo test ...` for only E2E tests, using this shared test env. + + stop_tracker_container(&container); - info!("Running container `{}` will be automatically removed", container.name); + remove_tracker_container(&container_name); } fn setup_runner_logging(level: LevelFilter) { @@ -164,6 +169,29 @@ fn run_tracker_container(image: &str, container_name: &str, options: &RunOptions container } +fn stop_tracker_container(container: &RunningContainer) { + info!("Stopping docker tracker image: {} ...", container.name); + Docker::stop(container).expect("Container should be stopped"); + assert_there_are_no_panics_in_logs(container); +} + +fn remove_tracker_container(container_name: &str) { + info!("Removing docker tracker image: {container_name} ..."); + Docker::remove(container_name).expect("Container should be removed"); +} + +fn assert_there_are_no_panics_in_logs(container: &RunningContainer) -> RunningServices { + let logs = Docker::logs(&container.name).expect("Logs should be captured from running container"); + + assert!( + !(logs.contains(" panicked at ") || logs.contains("RUST_BACKTRACE=1")), + "{}", + format!("Panics found is logs:\n{logs}") + ); + + RunningServices::parse_from_logs(&logs) +} + fn parse_running_services_from_logs(container: &RunningContainer) -> RunningServices { let logs = Docker::logs(&container.name).expect("Logs should be captured from running container");