Skip to content

Commit

Permalink
ci: [torrust#634] E2E test runner: open services port in docker run a…
Browse files Browse the repository at this point in the history
…nd run tracker checker
  • Loading branch information
josecelano committed Jan 24, 2024
1 parent 8141665 commit 029706d
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 26 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/testing.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -158,4 +158,4 @@ jobs:

- id: test
name: Run E2E Tests
run: cargo run --bin e2e_tests_runner
run: cargo run --bin e2e_tests_runner ./share/default/config/tracker.e2e.container.sqlite3.toml
12 changes: 10 additions & 2 deletions src/e2e/docker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,21 +39,29 @@ impl Docker {
/// # Errors
///
/// Will fail if the docker run command fails.
pub fn run(image: &str, container: &str, env_vars: &[(String, String)]) -> io::Result<Output> {
pub fn run(image: &str, container: &str, env_vars: &[(String, String)], ports: &[String]) -> io::Result<Output> {
let initial_args = vec![
"run".to_string(),
"--detach".to_string(),
"--name".to_string(),
container.to_string(),
];

// Add environment variables
let mut env_var_args: Vec<String> = vec![];
for (key, value) in env_vars {
env_var_args.push("--env".to_string());
env_var_args.push(format!("{key}={value}"));
}

let args = [initial_args, env_var_args, [image.to_string()].to_vec()].concat();
// Add port mappings
let mut port_args: Vec<String> = vec![];
for port in ports {
port_args.push("--publish".to_string());
port_args.push(port.to_string());
}

let args = [initial_args, env_var_args, port_args, [image.to_string()].to_vec()].concat();

debug!("Docker run args: {:?}", args);

Expand Down
3 changes: 2 additions & 1 deletion src/e2e/logs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ impl RunningServices {

if let Some(start) = line.find(heal_check_pattern) {
let address = &line[start + heal_check_pattern.len()..].trim();
self.health_checks.push(Self::replace_wildcard_ip_with_localhost(address));
self.health_checks
.push(format!("{}/health_check", Self::replace_wildcard_ip_with_localhost(address)));
} else if let Some(start) = line.find(udp_tracker_pattern) {
let address = &line[start + udp_tracker_pattern.len()..].trim();
self.udp_trackers.push(Self::replace_wildcard_ip_with_localhost(address));
Expand Down
85 changes: 63 additions & 22 deletions src/e2e/runner.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use std::env;
use std::fs::File;
use std::io::Write;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::time::Duration;
use std::{env, io};

use log::{debug, LevelFilter};
use rand::distributions::Alphanumeric;
Expand All @@ -22,17 +24,7 @@ pub const NUMBER_OF_ARGUMENTS: usize = 2;
/// - It can't change to the new temp dir.
/// - It can't revert the dit to the previous one.
pub fn run() {
/* todo:
- [x] Build the docker image.
- [x] Run the docker image.
- [x] Wait until the container is healthy.
- [x] Parse logs to get running services.
- [x] Build config file for the tracker_checker.
- [ ] Run the tracker_checker.
- [x] Stop the container.
*/
// todo: stop container or revert current dir on panics.

setup_logging(LevelFilter::Debug);

Expand All @@ -42,9 +34,10 @@ pub fn run() {

let tracker_config = read_tracker_config(&args.tracker_config_path);

let container_tag = "torrust-tracker:local";
let container_tag: &str = "torrust-tracker:local";
let tracker_checker_config_file = "tracker_checker.json";

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

println!(
"Current dir: {:?}",
Expand All @@ -62,9 +55,18 @@ pub fn run() {

let container_name = generate_random_container_name("tracker_");

// 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} ...");
let env_vars = [("TORRUST_TRACKER_CONFIG".to_string(), tracker_config.to_string())];
Docker::run(container_tag, &container_name, &env_vars).expect("A tracker local docker image should be running");
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");

println!("Waiting for the container {container_name} to be healthy ...");
let is_healthy = Docker::wait_until_is_healthy(&container_name, Duration::from_secs(10));
Expand All @@ -80,28 +82,37 @@ pub fn run() {

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

debug!("Logs after starting the container: {logs}");
debug!("Logs after starting the container:\n{logs}");

let mut config = RunningServices::default();
config.extract_from_logs(&logs);

let json = serde_json::to_string_pretty(&config).expect("Running services should be serialized into JSON");
println!("Tracker checker configuration: {json}");

let tracker_checker_config_path = "./tracker_checker.json";
let tracker_checker_config_path = format!("./{tracker_checker_config_file}");

let mut file = File::create(tracker_checker_config_path).expect("Tracker checker config file to be created");
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}");

println!("Stopping docker tracker image: {container_name} ...");
Docker::stop(&container_name).expect("A tracker local docker image should be stopped");

println!("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!(
"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");
}

fn setup_logging(level: LevelFilter) {
Expand Down Expand Up @@ -159,3 +170,33 @@ fn generate_random_container_name(prefix: &str) -> String {

format!("{prefix}{rand_string}")
}

/// Runs the tracker checker
///
/// ```text
/// cargo run --bin tracker_checker "./share/default/config/tracker_checker.json"
/// ```
///
/// # Errors
///
/// Will return an error if the tracker checker fails.
///
/// # Panics
///
/// Will panic if the config path is not a valid string.
pub fn run_tracker_checker(config_path: &Path) -> io::Result<()> {
let path = config_path.to_str().expect("The path should be a valid string");

let status = Command::new("cargo")
.args(["run", "--bin", "tracker_checker", path])
.status()?;

if status.success() {
Ok(())
} else {
Err(io::Error::new(
io::ErrorKind::Other,
format!("Failed to run tracker checker with config file {path}"),
))
}
}

0 comments on commit 029706d

Please sign in to comment.