torrust_tracker/console/ci/e2e/
runner.rs1use std::path::PathBuf;
21
22use anyhow::Context;
23use clap::Parser;
24use tracing::level_filters::LevelFilter;
25
26use super::tracker_container::TrackerContainer;
27use crate::console::ci::e2e::docker::RunOptions;
28use crate::console::ci::e2e::logs_parser::RunningServices;
29use crate::console::ci::e2e::tracker_checker::{self};
30
31const CONTAINER_IMAGE: &str = "torrust-tracker:local";
40const CONTAINER_NAME_PREFIX: &str = "tracker_";
41
42#[derive(Parser, Debug)]
43#[clap(author, version, about, long_about = None)]
44struct Args {
45 #[clap(short, long, env = "TORRUST_TRACKER_CONFIG_TOML_PATH")]
47 config_toml_path: Option<PathBuf>,
48
49 #[clap(env = "TORRUST_TRACKER_CONFIG_TOML", hide_env_values = true)]
51 config_toml: Option<String>,
52}
53
54pub fn run() -> anyhow::Result<()> {
64 tracing_stdout_init(LevelFilter::INFO);
65
66 let args = Args::parse();
67
68 let tracker_config = load_tracker_configuration(&args)?;
69
70 tracing::info!("tracker config:\n{tracker_config}");
71
72 let mut tracker_container = TrackerContainer::new(CONTAINER_IMAGE, CONTAINER_NAME_PREFIX);
73
74 tracker_container.build_image();
75
76 let options = RunOptions {
80 env_vars: vec![("TORRUST_TRACKER_CONFIG_TOML".to_string(), tracker_config.to_string())],
81 ports: vec![
82 "6969:6969/udp".to_string(),
83 "7070:7070/tcp".to_string(),
84 "1212:1212/tcp".to_string(),
85 "1313:1313/tcp".to_string(),
86 ],
87 };
88
89 tracker_container.run(&options);
90
91 let running_services = tracker_container.running_services();
92
93 tracing::info!(
94 "Running services:\n {}",
95 serde_json::to_string_pretty(&running_services).expect("running services to be serializable to JSON")
96 );
97
98 assert_there_is_at_least_one_service_per_type(&running_services);
99
100 let tracker_checker_config =
101 serde_json::to_string_pretty(&running_services).expect("Running services should be serialized into JSON");
102
103 tracker_checker::run(&tracker_checker_config).expect("All tracker services should be running correctly");
104
105 tracker_container.stop();
109
110 tracker_container.remove();
111
112 tracing::info!("Tracker container final state:\n{:#?}", tracker_container);
113
114 Ok(())
115}
116
117fn tracing_stdout_init(filter: LevelFilter) {
118 tracing_subscriber::fmt().with_max_level(filter).init();
119 tracing::info!("Logging initialized");
120}
121
122fn load_tracker_configuration(args: &Args) -> anyhow::Result<String> {
123 match (args.config_toml_path.clone(), args.config_toml.clone()) {
124 (Some(config_path), _) => {
125 tracing::info!(
126 "Reading tracker configuration from file: {} ...",
127 config_path.to_string_lossy()
128 );
129 load_config_from_file(&config_path)
130 }
131 (_, Some(config_content)) => {
132 tracing::info!("Reading tracker configuration from env var ...");
133 Ok(config_content)
134 }
135 _ => Err(anyhow::anyhow!("No configuration provided")),
136 }
137}
138
139fn load_config_from_file(path: &PathBuf) -> anyhow::Result<String> {
140 let config = std::fs::read_to_string(path).with_context(|| format!("CSan't read config file {path:?}"))?;
141
142 Ok(config)
143}
144
145fn assert_there_is_at_least_one_service_per_type(running_services: &RunningServices) {
146 assert!(
147 !running_services.udp_trackers.is_empty(),
148 "At least one UDP tracker should be enabled in E2E tests configuration"
149 );
150 assert!(
151 !running_services.http_trackers.is_empty(),
152 "At least one HTTP tracker should be enabled in E2E tests configuration"
153 );
154 assert!(
155 !running_services.health_checks.is_empty(),
156 "At least one Health Check should be enabled in E2E tests configuration"
157 );
158}