Skip to content

Commit

Permalink
ci: [torrust#634] remove container when execution is done
Browse files Browse the repository at this point in the history
  • Loading branch information
josecelano committed Jan 24, 2024
1 parent 911ba72 commit 9211ca0
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 53 deletions.
2 changes: 1 addition & 1 deletion src/bin/e2e_tests_runner.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Program to run E2E tests.
//!
//! ```text
//! cargo run --bin e2e_tests_runner
//! cargo run --bin e2e_tests_runner share/default/config/tracker.e2e.container.sqlite3.toml
//! ```
use torrust_tracker::e2e::runner;

Expand Down
45 changes: 23 additions & 22 deletions src/e2e/docker.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,26 @@
use std::io;
use std::process::{Child, Command, Output, Stdio};
use std::process::{Command, Output};
use std::thread::sleep;
use std::time::{Duration, Instant};

use log::debug;

pub struct Docker {}

pub struct RunningContainer {
pub name: String,
pub output: Output,
}

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);
}
}

impl Docker {
/// Builds a Docker image from a given Dockerfile.
///
Expand Down Expand Up @@ -39,7 +53,7 @@ impl Docker {
/// # Errors
///
/// Will fail if the docker run command fails.
pub fn run(image: &str, container: &str, env_vars: &[(String, String)], ports: &[String]) -> io::Result<Output> {
pub fn run(image: &str, container: &str, env_vars: &[(String, String)], ports: &[String]) -> io::Result<RunningContainer> {
let initial_args = vec![
"run".to_string(),
"--detach".to_string(),
Expand Down Expand Up @@ -68,7 +82,10 @@ impl Docker {
let output = Command::new("docker").args(args).output()?;

if output.status.success() {
Ok(output)
Ok(RunningContainer {
name: container.to_owned(),
output,
})
} else {
Err(io::Error::new(
io::ErrorKind::Other,
Expand All @@ -77,36 +94,20 @@ impl Docker {
}
}

/// Runs a Docker container from a given image in the background.
///
/// # Errors
///
/// Will fail if the docker run command fails to start.
pub fn run_spawned(image: &str, container: &str) -> io::Result<Child> {
let child = Command::new("docker")
.args(["run", "--name", container, image])
.stdin(Stdio::null()) // Ignore stdin
.stdout(Stdio::null()) // Ignore stdout
.stderr(Stdio::null()) // Ignore stderr
.spawn()?;

Ok(child)
}

/// Stops a Docker container.
///
/// # Errors
///
/// Will fail if the docker stop command fails.
pub fn stop(container: &str) -> io::Result<()> {
let status = Command::new("docker").args(["stop", container]).status()?;
pub fn stop(container: &RunningContainer) -> io::Result<()> {
let status = Command::new("docker").args(["stop", &container.name]).status()?;

if status.success() {
Ok(())
} else {
Err(io::Error::new(
io::ErrorKind::Other,
format!("Failed to stop Docker container {container}"),
format!("Failed to stop Docker container {}", container.name),
))
}
}
Expand Down
47 changes: 17 additions & 30 deletions src/e2e/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::process::Command;
use std::time::Duration;
use std::{env, io};

use log::{debug, LevelFilter};
use log::{debug, info, LevelFilter};
use rand::distributions::Alphanumeric;
use rand::Rng;

Expand All @@ -17,20 +17,13 @@ pub const NUMBER_OF_ARGUMENTS: usize = 2;

/// # Panics
///
/// Will panic if:
///
/// - It can't build the docker image.
/// - It can't create a temp dir.
/// - It can't change to the new temp dir.
/// - It can't revert the dit to the previous one.
/// Will panic if it can't not perform any of the operations.
pub fn run() {
// todo: stop container or revert current dir on panics.

setup_logging(LevelFilter::Debug);
setup_logging(LevelFilter::Info);

let args = parse_arguments();

println!("Reading tracker configuration from file: {} ...", args.tracker_config_path);
info!("Reading tracker configuration from file: {} ...", args.tracker_config_path);

let tracker_config = read_tracker_config(&args.tracker_config_path);

Expand All @@ -39,16 +32,15 @@ pub fn run() {

Docker::build("./Containerfile", container_tag).expect("A tracker local docker image should be built");

println!(
info!(
"Current dir: {:?}",
env::current_dir().expect("It should return the current dir")
);

println!("Create temp dir ...");
let temp_dir_handler = Handler::new().expect("A temp dir should be created");
println!("Temp dir created: {:?}", temp_dir_handler.temp_dir);
info!("Temp dir created: {:?}", temp_dir_handler.temp_dir);

println!("Change dir to: {:?}", temp_dir_handler.temp_dir);
info!("Change dir to: {:?}", temp_dir_handler.temp_dir);
temp_dir_handler
.change_to_temp_dir()
.expect("The app should change dir to the temp dir");
Expand All @@ -58,27 +50,23 @@ pub fn run() {
// code-review: if we want to use port 0 we don't know which ports we have to open.
// Besides, if we don't use port 0 we should get the port numbers from the tracker configuration.
// We could not use docker, but the intention was to create E2E tests including containerization.
println!("Running docker tracker image: {container_name} ...");
info!("Running docker tracker image: {container_name} ...");
let env_vars = [("TORRUST_TRACKER_CONFIG".to_string(), tracker_config.to_string())];
let ports = [
"6969:6969/udp".to_string(),
"7070:7070/tcp".to_string(),
"1212:1212/tcp".to_string(),
"1313:1313/tcp".to_string(),
];
Docker::run(container_tag, &container_name, &env_vars, &ports).expect("A tracker local docker image should be running");
let container =
Docker::run(container_tag, &container_name, &env_vars, &ports).expect("A tracker local docker image should be running");

println!("Waiting for the container {container_name} to be healthy ...");
info!("Waiting for the container {container_name} to be healthy ...");
let is_healthy = Docker::wait_until_is_healthy(&container_name, Duration::from_secs(10));

if !is_healthy {
println!("Unhealthy container: {container_name}");
println!("Stopping container: {container_name} ...");
Docker::stop(&container_name).expect("A tracker local docker image should be stopped");
panic!("Unhealthy container: {container_name}");
}
assert!(is_healthy, "Unhealthy tracker container: {container_name}");

println!("Container {container_name} is healthy ...");
info!("Container {container_name} is healthy ...");

let logs = Docker::logs(&container_name).expect("Logs should be captured from running container");

Expand All @@ -94,25 +82,24 @@ pub fn run() {
let mut file = File::create(tracker_checker_config_path.clone()).expect("Tracker checker config file to be created");
file.write_all(json.as_bytes())
.expect("Tracker checker config file to be written");
println!("Tracker checker configuration file: {tracker_checker_config_path} \n{json}");
info!("Tracker checker configuration file: {tracker_checker_config_path} \n{json}");

println!("Revert current dir to: {:?}", temp_dir_handler.original_dir);
info!("Revert current dir to: {:?}", temp_dir_handler.original_dir);
temp_dir_handler
.revert_to_original_dir()
.expect("The app should revert dir from temp dir to the original one");

let mut absolute_tracker_checker_config_path = PathBuf::from(&temp_dir_handler.temp_dir.path());
absolute_tracker_checker_config_path.push(tracker_checker_config_file);

println!(
info!(
"Running tacker checker: cargo --bin tracker_checker {}",
absolute_tracker_checker_config_path.display()
);

run_tracker_checker(&absolute_tracker_checker_config_path).expect("Tracker checker should check running services");

println!("Stopping docker tracker image: {container_name} ...");
Docker::stop(&container_name).expect("A tracker local docker image should be stopped");
info!("Running container `{}` will be automatically removed", container.name);
}

fn setup_logging(level: LevelFilter) {
Expand Down

0 comments on commit 9211ca0

Please sign in to comment.