diff --git a/src/bootstrap/jobs/health_check_api.rs b/src/bootstrap/jobs/health_check_api.rs index 1a981528..7eeafe97 100644 --- a/src/bootstrap/jobs/health_check_api.rs +++ b/src/bootstrap/jobs/health_check_api.rs @@ -22,6 +22,7 @@ use torrust_tracker_configuration::HealthCheckApi; use super::Started; use crate::servers::health_check_api::server; use crate::servers::registar::ServiceRegistry; +use crate::servers::signals::Halted; /// This function starts a new Health Check API server with the provided /// configuration. @@ -40,12 +41,14 @@ pub async fn start_job(config: &HealthCheckApi, register: ServiceRegistry) -> Jo .expect("it should have a valid health check bind address"); let (tx_start, rx_start) = oneshot::channel::(); + let (tx_halt, rx_halt) = tokio::sync::oneshot::channel::(); + drop(tx_halt); // Run the API server let join_handle = tokio::spawn(async move { info!(target: "Health Check API", "Starting on: http://{}", bind_addr); - let handle = server::start(bind_addr, tx_start, register); + let handle = server::start(bind_addr, tx_start, rx_halt, register); if let Ok(()) = handle.await { info!(target: "Health Check API", "Stopped server running on: http://{}", bind_addr); diff --git a/src/servers/health_check_api/handlers.rs b/src/servers/health_check_api/handlers.rs index 35382583..944e84a1 100644 --- a/src/servers/health_check_api/handlers.rs +++ b/src/servers/health_check_api/handlers.rs @@ -21,6 +21,11 @@ pub(crate) async fn health_check_handler(State(register): State checks = mutex.await.values().map(ServiceRegistration::spawn_check).collect(); } + // if we do not have any checks, lets return a `none` result. + if checks.is_empty() { + return responses::none(); + } + let jobs = checks.drain(..).map(|c| { tokio::spawn(async move { CheckReport { diff --git a/src/servers/health_check_api/resources.rs b/src/servers/health_check_api/resources.rs index bb57cf20..3302fb96 100644 --- a/src/servers/health_check_api/resources.rs +++ b/src/servers/health_check_api/resources.rs @@ -6,6 +6,7 @@ use serde::{Deserialize, Serialize}; pub enum Status { Ok, Error, + None, } #[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq)] @@ -34,6 +35,15 @@ pub struct Report { } impl Report { + #[must_use] + pub fn none() -> Report { + Self { + status: Status::None, + message: String::new(), + details: Vec::default(), + } + } + #[must_use] pub fn ok(details: Vec) -> Report { Self { diff --git a/src/servers/health_check_api/responses.rs b/src/servers/health_check_api/responses.rs index 8658caeb..3796d8be 100644 --- a/src/servers/health_check_api/responses.rs +++ b/src/servers/health_check_api/responses.rs @@ -9,3 +9,7 @@ pub fn ok(details: Vec) -> Json { pub fn error(message: String, details: Vec) -> Json { Json(Report::error(message, details)) } + +pub fn none() -> Json { + Json(Report::none()) +} diff --git a/src/servers/health_check_api/server.rs b/src/servers/health_check_api/server.rs index a7cbf4a8..ecc6fe42 100644 --- a/src/servers/health_check_api/server.rs +++ b/src/servers/health_check_api/server.rs @@ -8,13 +8,13 @@ use axum::routing::get; use axum::{Json, Router}; use axum_server::Handle; use futures::Future; -use log::info; use serde_json::json; -use tokio::sync::oneshot::Sender; +use tokio::sync::oneshot::{Receiver, Sender}; use crate::bootstrap::jobs::Started; use crate::servers::health_check_api::handlers::health_check_handler; use crate::servers::registar::ServiceRegistry; +use crate::servers::signals::{graceful_shutdown, Halted}; /// Starts Health Check API server. /// @@ -22,30 +22,30 @@ use crate::servers::registar::ServiceRegistry; /// /// Will panic if binding to the socket address fails. pub fn start( - address: SocketAddr, + bind_to: SocketAddr, tx: Sender, + rx_halt: Receiver, register: ServiceRegistry, ) -> impl Future> { - let app = Router::new() + let router = Router::new() .route("/", get(|| async { Json(json!({})) })) .route("/health_check", get(health_check_handler)) .with_state(register); - let handle = Handle::new(); - let cloned_handle = handle.clone(); - - let socket = std::net::TcpListener::bind(address).expect("Could not bind tcp_listener to address."); + let socket = std::net::TcpListener::bind(bind_to).expect("Could not bind tcp_listener to address."); let address = socket.local_addr().expect("Could not get local_addr from tcp_listener."); - tokio::task::spawn(async move { - tokio::signal::ctrl_c().await.expect("Failed to listen to shutdown signal."); - info!("Stopping Torrust Health Check API server o http://{} ...", address); - cloned_handle.shutdown(); - }); + let handle = Handle::new(); + + tokio::task::spawn(graceful_shutdown( + handle.clone(), + rx_halt, + format!("shutting down http server on socket address: {address}"), + )); let running = axum_server::from_tcp(socket) .handle(handle) - .serve(app.into_make_service_with_connect_info::()); + .serve(router.into_make_service_with_connect_info::()); tx.send(Started { address }) .expect("the Health Check API server should not be dropped"); diff --git a/src/shared/bit_torrent/tracker/udp/client.rs b/src/shared/bit_torrent/tracker/udp/client.rs index f0a981c8..00f0b8ac 100644 --- a/src/shared/bit_torrent/tracker/udp/client.rs +++ b/src/shared/bit_torrent/tracker/udp/client.rs @@ -1,9 +1,11 @@ use std::io::Cursor; use std::net::SocketAddr; use std::sync::Arc; +use std::time::Duration; use aquatic_udp_protocol::{ConnectRequest, Request, Response, TransactionId}; use tokio::net::UdpSocket; +use tokio::time; use crate::shared::bit_torrent::tracker::udp::{source_address, MAX_PACKET_SIZE}; @@ -112,6 +114,8 @@ pub async fn new_udp_tracker_client_connected(remote_address: &str) -> UdpTracke /// # Errors /// /// It will return an error if unable to connect to the UDP service. +/// +/// # Panics pub async fn check(binding: &SocketAddr) -> Result { let client = new_udp_tracker_client_connected(binding.to_string().as_str()).await; @@ -121,11 +125,23 @@ pub async fn check(binding: &SocketAddr) -> Result { client.send(connect_request.into()).await; - let response = client.receive().await; + let process = move |response| { + if matches!(response, Response::Connect(_connect_response)) { + Ok("Connected".to_string()) + } else { + Err("Did not Connect".to_string()) + } + }; + + let sleep = time::sleep(Duration::from_millis(2000)); + tokio::pin!(sleep); - if matches!(response, Response::Connect(_connect_response)) { - Ok("Connected".to_string()) - } else { - Err("Did not Connect".to_string()) + tokio::select! { + () = &mut sleep => { + Err("Timed Out".to_string()) + } + response = client.receive() => { + process(response) + } } } diff --git a/tests/common/app.rs b/tests/common/app.rs deleted file mode 100644 index 1b735bc8..00000000 --- a/tests/common/app.rs +++ /dev/null @@ -1,8 +0,0 @@ -use std::sync::Arc; - -use torrust_tracker::bootstrap; -use torrust_tracker::core::Tracker; - -pub fn setup_with_configuration(configuration: &Arc) -> Arc { - bootstrap::app::initialize_with_configuration(configuration) -} diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 51a8a5b0..b5799629 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -1,4 +1,3 @@ -pub mod app; pub mod fixtures; pub mod http; pub mod udp; diff --git a/tests/servers/api/environment.rs b/tests/servers/api/environment.rs new file mode 100644 index 00000000..186b7ea3 --- /dev/null +++ b/tests/servers/api/environment.rs @@ -0,0 +1,94 @@ +use std::net::SocketAddr; +use std::sync::Arc; + +use futures::executor::block_on; +use torrust_tracker::bootstrap::app::initialize_with_configuration; +use torrust_tracker::bootstrap::jobs::make_rust_tls; +use torrust_tracker::core::peer::Peer; +use torrust_tracker::core::Tracker; +use torrust_tracker::servers::apis::server::{ApiServer, Launcher, Running, Stopped}; +use torrust_tracker::servers::registar::Registar; +use torrust_tracker::shared::bit_torrent::info_hash::InfoHash; +use torrust_tracker_configuration::{Configuration, HttpApi}; + +use super::connection_info::ConnectionInfo; + +pub struct Environment { + pub config: Arc, + pub tracker: Arc, + pub registar: Registar, + pub server: ApiServer, +} + +impl Environment { + /// Add a torrent to the tracker + pub async fn add_torrent_peer(&self, info_hash: &InfoHash, peer: &Peer) { + self.tracker.update_torrent_with_peer_and_get_stats(info_hash, peer).await; + } +} + +impl Environment { + pub fn new(configuration: &Arc) -> Self { + let tracker = initialize_with_configuration(configuration); + + let config = Arc::new(configuration.http_api.clone()); + + let bind_to = config + .bind_address + .parse::() + .expect("Tracker API bind_address invalid."); + + let tls = block_on(make_rust_tls(config.ssl_enabled, &config.ssl_cert_path, &config.ssl_key_path)) + .map(|tls| tls.expect("tls config failed")); + + let server = ApiServer::new(Launcher::new(bind_to, tls)); + + Self { + config, + tracker, + registar: Registar::default(), + server, + } + } + + pub async fn start(self) -> Environment { + let access_tokens = Arc::new(self.config.access_tokens.clone()); + + Environment { + config: self.config, + tracker: self.tracker.clone(), + registar: self.registar.clone(), + server: self + .server + .start(self.tracker, self.registar.give_form(), access_tokens) + .await + .unwrap(), + } + } +} + +impl Environment { + pub async fn new(configuration: &Arc) -> Self { + Environment::::new(configuration).start().await + } + + pub async fn stop(self) -> Environment { + Environment { + config: self.config, + tracker: self.tracker, + registar: Registar::default(), + server: self.server.stop().await.unwrap(), + } + } + + pub fn get_connection_info(&self) -> ConnectionInfo { + ConnectionInfo { + bind_address: self.server.state.binding.to_string(), + api_token: self.config.access_tokens.get("admin").cloned(), + } + } + + pub fn bind_address(&self) -> SocketAddr { + self.server.state.binding + } +} diff --git a/tests/servers/api/mod.rs b/tests/servers/api/mod.rs index 155ac0de..9c30e316 100644 --- a/tests/servers/api/mod.rs +++ b/tests/servers/api/mod.rs @@ -1,11 +1,14 @@ use std::sync::Arc; use torrust_tracker::core::Tracker; +use torrust_tracker::servers::apis::server; pub mod connection_info; -pub mod test_environment; +pub mod environment; pub mod v1; +pub type Started = environment::Environment; + /// It forces a database error by dropping all tables. /// That makes any query fail. /// code-review: alternatively we could inject a database mock in the future. diff --git a/tests/servers/api/test_environment.rs b/tests/servers/api/test_environment.rs deleted file mode 100644 index 080fab55..00000000 --- a/tests/servers/api/test_environment.rs +++ /dev/null @@ -1,126 +0,0 @@ -use std::sync::Arc; - -use futures::executor::block_on; -use torrust_tracker::bootstrap::jobs::make_rust_tls; -use torrust_tracker::core::peer::Peer; -use torrust_tracker::core::Tracker; -use torrust_tracker::servers::apis::server::{ApiServer, Launcher, RunningApiServer, StoppedApiServer}; -use torrust_tracker::servers::registar::Registar; -use torrust_tracker::shared::bit_torrent::info_hash::InfoHash; -use torrust_tracker_configuration::HttpApi; - -use super::connection_info::ConnectionInfo; -use crate::common::app::setup_with_configuration; - -#[allow(clippy::module_name_repetitions, dead_code)] -pub type StoppedTestEnvironment = TestEnvironment; -#[allow(clippy::module_name_repetitions)] -pub type RunningTestEnvironment = TestEnvironment; - -pub struct TestEnvironment { - pub config: Arc, - pub tracker: Arc, - pub state: S, -} - -#[allow(dead_code)] -pub struct Stopped { - api_server: StoppedApiServer, -} - -pub struct Running { - api_server: RunningApiServer, -} - -impl TestEnvironment { - /// Add a torrent to the tracker - pub async fn add_torrent_peer(&self, info_hash: &InfoHash, peer: &Peer) { - self.tracker.update_torrent_with_peer_and_get_stats(info_hash, peer).await; - } -} - -impl TestEnvironment { - pub fn new(cfg: torrust_tracker_configuration::Configuration) -> Self { - let cfg = Arc::new(cfg); - let tracker = setup_with_configuration(&cfg); - - let config = Arc::new(cfg.http_api.clone()); - - let bind_to = config - .bind_address - .parse::() - .expect("Tracker API bind_address invalid."); - - let tls = block_on(make_rust_tls(config.ssl_enabled, &config.ssl_cert_path, &config.ssl_key_path)) - .map(|tls| tls.expect("tls config failed")); - - let api_server = api_server(Launcher::new(bind_to, tls)); - - Self { - config, - tracker, - state: Stopped { api_server }, - } - } - - pub async fn start(self) -> TestEnvironment { - let access_tokens = Arc::new(self.config.access_tokens.clone()); - - TestEnvironment { - config: self.config, - tracker: self.tracker.clone(), - state: Running { - api_server: self - .state - .api_server - .start(self.tracker, Registar::default().give_form(), access_tokens) - .await - .unwrap(), - }, - } - } - - // pub fn config_mut(&mut self) -> &mut torrust_tracker_configuration::HttpApi { - // &mut self.cfg.http_api - // } -} - -impl TestEnvironment { - pub async fn new_running(cfg: torrust_tracker_configuration::Configuration) -> Self { - let test_env = StoppedTestEnvironment::new(cfg); - - test_env.start().await - } - - pub async fn stop(self) -> TestEnvironment { - TestEnvironment { - config: self.config, - tracker: self.tracker, - state: Stopped { - api_server: self.state.api_server.stop().await.unwrap(), - }, - } - } - - pub fn get_connection_info(&self) -> ConnectionInfo { - ConnectionInfo { - bind_address: self.state.api_server.state.binding.to_string(), - api_token: self.config.access_tokens.get("admin").cloned(), - } - } -} - -#[allow(clippy::module_name_repetitions)] -#[allow(dead_code)] -pub fn stopped_test_environment(cfg: torrust_tracker_configuration::Configuration) -> StoppedTestEnvironment { - TestEnvironment::new(cfg) -} - -#[allow(clippy::module_name_repetitions)] -pub async fn running_test_environment(cfg: torrust_tracker_configuration::Configuration) -> RunningTestEnvironment { - TestEnvironment::new_running(cfg).await -} - -pub fn api_server(launcher: Launcher) -> StoppedApiServer { - ApiServer::new(launcher) -} diff --git a/tests/servers/api/v1/contract/authentication.rs b/tests/servers/api/v1/contract/authentication.rs index fb8de181..49981dd0 100644 --- a/tests/servers/api/v1/contract/authentication.rs +++ b/tests/servers/api/v1/contract/authentication.rs @@ -1,83 +1,83 @@ use torrust_tracker_test_helpers::configuration; use crate::common::http::{Query, QueryParam}; -use crate::servers::api::test_environment::running_test_environment; use crate::servers::api::v1::asserts::{assert_token_not_valid, assert_unauthorized}; use crate::servers::api::v1::client::Client; +use crate::servers::api::Started; #[tokio::test] async fn should_authenticate_requests_by_using_a_token_query_param() { - let test_env = running_test_environment(configuration::ephemeral()).await; + let env = Started::new(&configuration::ephemeral().into()).await; - let token = test_env.get_connection_info().api_token.unwrap(); + let token = env.get_connection_info().api_token.unwrap(); - let response = Client::new(test_env.get_connection_info()) + let response = Client::new(env.get_connection_info()) .get_request_with_query("stats", Query::params([QueryParam::new("token", &token)].to_vec())) .await; assert_eq!(response.status(), 200); - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_not_authenticate_requests_when_the_token_is_missing() { - let test_env = running_test_environment(configuration::ephemeral()).await; + let env = Started::new(&configuration::ephemeral().into()).await; - let response = Client::new(test_env.get_connection_info()) + let response = Client::new(env.get_connection_info()) .get_request_with_query("stats", Query::default()) .await; assert_unauthorized(response).await; - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_not_authenticate_requests_when_the_token_is_empty() { - let test_env = running_test_environment(configuration::ephemeral()).await; + let env = Started::new(&configuration::ephemeral().into()).await; - let response = Client::new(test_env.get_connection_info()) + let response = Client::new(env.get_connection_info()) .get_request_with_query("stats", Query::params([QueryParam::new("token", "")].to_vec())) .await; assert_token_not_valid(response).await; - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_not_authenticate_requests_when_the_token_is_invalid() { - let test_env = running_test_environment(configuration::ephemeral()).await; + let env = Started::new(&configuration::ephemeral().into()).await; - let response = Client::new(test_env.get_connection_info()) + let response = Client::new(env.get_connection_info()) .get_request_with_query("stats", Query::params([QueryParam::new("token", "INVALID TOKEN")].to_vec())) .await; assert_token_not_valid(response).await; - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_allow_the_token_query_param_to_be_at_any_position_in_the_url_query() { - let test_env = running_test_environment(configuration::ephemeral()).await; + let env = Started::new(&configuration::ephemeral().into()).await; - let token = test_env.get_connection_info().api_token.unwrap(); + let token = env.get_connection_info().api_token.unwrap(); // At the beginning of the query component - let response = Client::new(test_env.get_connection_info()) + let response = Client::new(env.get_connection_info()) .get_request(&format!("torrents?token={token}&limit=1")) .await; assert_eq!(response.status(), 200); // At the end of the query component - let response = Client::new(test_env.get_connection_info()) + let response = Client::new(env.get_connection_info()) .get_request(&format!("torrents?limit=1&token={token}")) .await; assert_eq!(response.status(), 200); - test_env.stop().await; + env.stop().await; } diff --git a/tests/servers/api/v1/contract/configuration.rs b/tests/servers/api/v1/contract/configuration.rs index a551a8b3..4220f62d 100644 --- a/tests/servers/api/v1/contract/configuration.rs +++ b/tests/servers/api/v1/contract/configuration.rs @@ -5,7 +5,7 @@ // use torrust_tracker_test_helpers::configuration; // use crate::common::app::setup_with_configuration; -// use crate::servers::api::test_environment::stopped_test_environment; +// use crate::servers::api::environment::stopped_environment; #[tokio::test] #[ignore] @@ -27,7 +27,7 @@ async fn should_fail_with_ssl_enabled_and_bad_ssl_config() { // None // }; - // let test_env = new_stopped(tracker, bind_to, tls); + // let env = new_stopped(tracker, bind_to, tls); - // test_env.start().await; + // env.start().await; } diff --git a/tests/servers/api/v1/contract/context/auth_key.rs b/tests/servers/api/v1/contract/context/auth_key.rs index 4c59b4e9..f9630baf 100644 --- a/tests/servers/api/v1/contract/context/auth_key.rs +++ b/tests/servers/api/v1/contract/context/auth_key.rs @@ -4,62 +4,57 @@ use torrust_tracker::core::auth::Key; use torrust_tracker_test_helpers::configuration; use crate::servers::api::connection_info::{connection_with_invalid_token, connection_with_no_token}; -use crate::servers::api::force_database_error; -use crate::servers::api::test_environment::running_test_environment; use crate::servers::api::v1::asserts::{ assert_auth_key_utf8, assert_failed_to_delete_key, assert_failed_to_generate_key, assert_failed_to_reload_keys, assert_invalid_auth_key_param, assert_invalid_key_duration_param, assert_ok, assert_token_not_valid, assert_unauthorized, }; use crate::servers::api::v1::client::Client; +use crate::servers::api::{force_database_error, Started}; #[tokio::test] async fn should_allow_generating_a_new_auth_key() { - let test_env = running_test_environment(configuration::ephemeral()).await; + let env = Started::new(&configuration::ephemeral().into()).await; let seconds_valid = 60; - let response = Client::new(test_env.get_connection_info()) - .generate_auth_key(seconds_valid) - .await; + let response = Client::new(env.get_connection_info()).generate_auth_key(seconds_valid).await; let auth_key_resource = assert_auth_key_utf8(response).await; // Verify the key with the tracker - assert!(test_env + assert!(env .tracker .verify_auth_key(&auth_key_resource.key.parse::().unwrap()) .await .is_ok()); - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_not_allow_generating_a_new_auth_key_for_unauthenticated_users() { - let test_env = running_test_environment(configuration::ephemeral()).await; + let env = Started::new(&configuration::ephemeral().into()).await; let seconds_valid = 60; - let response = Client::new(connection_with_invalid_token( - test_env.get_connection_info().bind_address.as_str(), - )) - .generate_auth_key(seconds_valid) - .await; + let response = Client::new(connection_with_invalid_token(env.get_connection_info().bind_address.as_str())) + .generate_auth_key(seconds_valid) + .await; assert_token_not_valid(response).await; - let response = Client::new(connection_with_no_token(test_env.get_connection_info().bind_address.as_str())) + let response = Client::new(connection_with_no_token(env.get_connection_info().bind_address.as_str())) .generate_auth_key(seconds_valid) .await; assert_unauthorized(response).await; - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_fail_generating_a_new_auth_key_when_the_key_duration_is_invalid() { - let test_env = running_test_environment(configuration::ephemeral()).await; + let env = Started::new(&configuration::ephemeral().into()).await; let invalid_key_durations = [ // "", it returns 404 @@ -68,55 +63,53 @@ async fn should_fail_generating_a_new_auth_key_when_the_key_duration_is_invalid( ]; for invalid_key_duration in invalid_key_durations { - let response = Client::new(test_env.get_connection_info()) + let response = Client::new(env.get_connection_info()) .post(&format!("key/{invalid_key_duration}")) .await; assert_invalid_key_duration_param(response, invalid_key_duration).await; } - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_fail_when_the_auth_key_cannot_be_generated() { - let test_env = running_test_environment(configuration::ephemeral()).await; + let env = Started::new(&configuration::ephemeral().into()).await; - force_database_error(&test_env.tracker); + force_database_error(&env.tracker); let seconds_valid = 60; - let response = Client::new(test_env.get_connection_info()) - .generate_auth_key(seconds_valid) - .await; + let response = Client::new(env.get_connection_info()).generate_auth_key(seconds_valid).await; assert_failed_to_generate_key(response).await; - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_allow_deleting_an_auth_key() { - let test_env = running_test_environment(configuration::ephemeral()).await; + let env = Started::new(&configuration::ephemeral().into()).await; let seconds_valid = 60; - let auth_key = test_env + let auth_key = env .tracker .generate_auth_key(Duration::from_secs(seconds_valid)) .await .unwrap(); - let response = Client::new(test_env.get_connection_info()) + let response = Client::new(env.get_connection_info()) .delete_auth_key(&auth_key.key.to_string()) .await; assert_ok(response).await; - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_fail_deleting_an_auth_key_when_the_key_id_is_invalid() { - let test_env = running_test_environment(configuration::ephemeral()).await; + let env = Started::new(&configuration::ephemeral().into()).await; let invalid_auth_keys = [ // "", it returns a 404 @@ -129,137 +122,128 @@ async fn should_fail_deleting_an_auth_key_when_the_key_id_is_invalid() { ]; for invalid_auth_key in &invalid_auth_keys { - let response = Client::new(test_env.get_connection_info()) - .delete_auth_key(invalid_auth_key) - .await; + let response = Client::new(env.get_connection_info()).delete_auth_key(invalid_auth_key).await; assert_invalid_auth_key_param(response, invalid_auth_key).await; } - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_fail_when_the_auth_key_cannot_be_deleted() { - let test_env = running_test_environment(configuration::ephemeral()).await; + let env = Started::new(&configuration::ephemeral().into()).await; let seconds_valid = 60; - let auth_key = test_env + let auth_key = env .tracker .generate_auth_key(Duration::from_secs(seconds_valid)) .await .unwrap(); - force_database_error(&test_env.tracker); + force_database_error(&env.tracker); - let response = Client::new(test_env.get_connection_info()) + let response = Client::new(env.get_connection_info()) .delete_auth_key(&auth_key.key.to_string()) .await; assert_failed_to_delete_key(response).await; - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_not_allow_deleting_an_auth_key_for_unauthenticated_users() { - let test_env = running_test_environment(configuration::ephemeral()).await; + let env = Started::new(&configuration::ephemeral().into()).await; let seconds_valid = 60; // Generate new auth key - let auth_key = test_env + let auth_key = env .tracker .generate_auth_key(Duration::from_secs(seconds_valid)) .await .unwrap(); - let response = Client::new(connection_with_invalid_token( - test_env.get_connection_info().bind_address.as_str(), - )) - .delete_auth_key(&auth_key.key.to_string()) - .await; + let response = Client::new(connection_with_invalid_token(env.get_connection_info().bind_address.as_str())) + .delete_auth_key(&auth_key.key.to_string()) + .await; assert_token_not_valid(response).await; // Generate new auth key - let auth_key = test_env + let auth_key = env .tracker .generate_auth_key(Duration::from_secs(seconds_valid)) .await .unwrap(); - let response = Client::new(connection_with_no_token(test_env.get_connection_info().bind_address.as_str())) + let response = Client::new(connection_with_no_token(env.get_connection_info().bind_address.as_str())) .delete_auth_key(&auth_key.key.to_string()) .await; assert_unauthorized(response).await; - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_allow_reloading_keys() { - let test_env = running_test_environment(configuration::ephemeral()).await; + let env = Started::new(&configuration::ephemeral().into()).await; let seconds_valid = 60; - test_env - .tracker + env.tracker .generate_auth_key(Duration::from_secs(seconds_valid)) .await .unwrap(); - let response = Client::new(test_env.get_connection_info()).reload_keys().await; + let response = Client::new(env.get_connection_info()).reload_keys().await; assert_ok(response).await; - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_fail_when_keys_cannot_be_reloaded() { - let test_env = running_test_environment(configuration::ephemeral()).await; + let env = Started::new(&configuration::ephemeral().into()).await; let seconds_valid = 60; - test_env - .tracker + env.tracker .generate_auth_key(Duration::from_secs(seconds_valid)) .await .unwrap(); - force_database_error(&test_env.tracker); + force_database_error(&env.tracker); - let response = Client::new(test_env.get_connection_info()).reload_keys().await; + let response = Client::new(env.get_connection_info()).reload_keys().await; assert_failed_to_reload_keys(response).await; - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_not_allow_reloading_keys_for_unauthenticated_users() { - let test_env = running_test_environment(configuration::ephemeral()).await; + let env = Started::new(&configuration::ephemeral().into()).await; let seconds_valid = 60; - test_env - .tracker + env.tracker .generate_auth_key(Duration::from_secs(seconds_valid)) .await .unwrap(); - let response = Client::new(connection_with_invalid_token( - test_env.get_connection_info().bind_address.as_str(), - )) - .reload_keys() - .await; + let response = Client::new(connection_with_invalid_token(env.get_connection_info().bind_address.as_str())) + .reload_keys() + .await; assert_token_not_valid(response).await; - let response = Client::new(connection_with_no_token(test_env.get_connection_info().bind_address.as_str())) + let response = Client::new(connection_with_no_token(env.get_connection_info().bind_address.as_str())) .reload_keys() .await; assert_unauthorized(response).await; - test_env.stop().await; + env.stop().await; } diff --git a/tests/servers/api/v1/contract/context/health_check.rs b/tests/servers/api/v1/contract/context/health_check.rs index 108ae237..d8dc3c03 100644 --- a/tests/servers/api/v1/contract/context/health_check.rs +++ b/tests/servers/api/v1/contract/context/health_check.rs @@ -1,14 +1,14 @@ use torrust_tracker::servers::apis::v1::context::health_check::resources::{Report, Status}; use torrust_tracker_test_helpers::configuration; -use crate::servers::api::test_environment::running_test_environment; use crate::servers::api::v1::client::get; +use crate::servers::api::Started; #[tokio::test] async fn health_check_endpoint_should_return_status_ok_if_api_is_running() { - let test_env = running_test_environment(configuration::ephemeral()).await; + let env = Started::new(&configuration::ephemeral().into()).await; - let url = format!("http://{}/api/health_check", test_env.get_connection_info().bind_address); + let url = format!("http://{}/api/health_check", env.get_connection_info().bind_address); let response = get(&url, None).await; @@ -16,5 +16,5 @@ async fn health_check_endpoint_should_return_status_ok_if_api_is_running() { assert_eq!(response.headers().get("content-type").unwrap(), "application/json"); assert_eq!(response.json::().await.unwrap(), Report { status: Status::Ok }); - test_env.stop().await; + env.stop().await; } diff --git a/tests/servers/api/v1/contract/context/stats.rs b/tests/servers/api/v1/contract/context/stats.rs index 71738f8e..54263f8b 100644 --- a/tests/servers/api/v1/contract/context/stats.rs +++ b/tests/servers/api/v1/contract/context/stats.rs @@ -6,22 +6,21 @@ use torrust_tracker::shared::bit_torrent::info_hash::InfoHash; use torrust_tracker_test_helpers::configuration; use crate::servers::api::connection_info::{connection_with_invalid_token, connection_with_no_token}; -use crate::servers::api::test_environment::running_test_environment; use crate::servers::api::v1::asserts::{assert_stats, assert_token_not_valid, assert_unauthorized}; use crate::servers::api::v1::client::Client; +use crate::servers::api::Started; #[tokio::test] async fn should_allow_getting_tracker_statistics() { - let test_env = running_test_environment(configuration::ephemeral()).await; + let env = Started::new(&configuration::ephemeral().into()).await; - test_env - .add_torrent_peer( - &InfoHash::from_str("9e0217d0fa71c87332cd8bf9dbeabcb2c2cf3c4d").unwrap(), - &PeerBuilder::default().into(), - ) - .await; + env.add_torrent_peer( + &InfoHash::from_str("9e0217d0fa71c87332cd8bf9dbeabcb2c2cf3c4d").unwrap(), + &PeerBuilder::default().into(), + ) + .await; - let response = Client::new(test_env.get_connection_info()).get_tracker_statistics().await; + let response = Client::new(env.get_connection_info()).get_tracker_statistics().await; assert_stats( response, @@ -46,26 +45,24 @@ async fn should_allow_getting_tracker_statistics() { ) .await; - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_not_allow_getting_tracker_statistics_for_unauthenticated_users() { - let test_env = running_test_environment(configuration::ephemeral()).await; + let env = Started::new(&configuration::ephemeral().into()).await; - let response = Client::new(connection_with_invalid_token( - test_env.get_connection_info().bind_address.as_str(), - )) - .get_tracker_statistics() - .await; + let response = Client::new(connection_with_invalid_token(env.get_connection_info().bind_address.as_str())) + .get_tracker_statistics() + .await; assert_token_not_valid(response).await; - let response = Client::new(connection_with_no_token(test_env.get_connection_info().bind_address.as_str())) + let response = Client::new(connection_with_no_token(env.get_connection_info().bind_address.as_str())) .get_tracker_statistics() .await; assert_unauthorized(response).await; - test_env.stop().await; + env.stop().await; } diff --git a/tests/servers/api/v1/contract/context/torrent.rs b/tests/servers/api/v1/contract/context/torrent.rs index dc91e8fc..63b97b40 100644 --- a/tests/servers/api/v1/contract/context/torrent.rs +++ b/tests/servers/api/v1/contract/context/torrent.rs @@ -8,7 +8,6 @@ use torrust_tracker_test_helpers::configuration; use crate::common::http::{Query, QueryParam}; use crate::servers::api::connection_info::{connection_with_invalid_token, connection_with_no_token}; -use crate::servers::api::test_environment::running_test_environment; use crate::servers::api::v1::asserts::{ assert_bad_request, assert_invalid_infohash_param, assert_not_found, assert_token_not_valid, assert_torrent_info, assert_torrent_list, assert_torrent_not_known, assert_unauthorized, @@ -17,16 +16,17 @@ use crate::servers::api::v1::client::Client; use crate::servers::api::v1::contract::fixtures::{ invalid_infohashes_returning_bad_request, invalid_infohashes_returning_not_found, }; +use crate::servers::api::Started; #[tokio::test] async fn should_allow_getting_torrents() { - let test_env = running_test_environment(configuration::ephemeral()).await; + let env = Started::new(&configuration::ephemeral().into()).await; let info_hash = InfoHash::from_str("9e0217d0fa71c87332cd8bf9dbeabcb2c2cf3c4d").unwrap(); - test_env.add_torrent_peer(&info_hash, &PeerBuilder::default().into()).await; + env.add_torrent_peer(&info_hash, &PeerBuilder::default().into()).await; - let response = Client::new(test_env.get_connection_info()).get_torrents(Query::empty()).await; + let response = Client::new(env.get_connection_info()).get_torrents(Query::empty()).await; assert_torrent_list( response, @@ -39,21 +39,21 @@ async fn should_allow_getting_torrents() { ) .await; - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_allow_limiting_the_torrents_in_the_result() { - let test_env = running_test_environment(configuration::ephemeral()).await; + let env = Started::new(&configuration::ephemeral().into()).await; // torrents are ordered alphabetically by infohashes let info_hash_1 = InfoHash::from_str("9e0217d0fa71c87332cd8bf9dbeabcb2c2cf3c4d").unwrap(); let info_hash_2 = InfoHash::from_str("0b3aea4adc213ce32295be85d3883a63bca25446").unwrap(); - test_env.add_torrent_peer(&info_hash_1, &PeerBuilder::default().into()).await; - test_env.add_torrent_peer(&info_hash_2, &PeerBuilder::default().into()).await; + env.add_torrent_peer(&info_hash_1, &PeerBuilder::default().into()).await; + env.add_torrent_peer(&info_hash_2, &PeerBuilder::default().into()).await; - let response = Client::new(test_env.get_connection_info()) + let response = Client::new(env.get_connection_info()) .get_torrents(Query::params([QueryParam::new("limit", "1")].to_vec())) .await; @@ -68,21 +68,21 @@ async fn should_allow_limiting_the_torrents_in_the_result() { ) .await; - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_allow_the_torrents_result_pagination() { - let test_env = running_test_environment(configuration::ephemeral()).await; + let env = Started::new(&configuration::ephemeral().into()).await; // torrents are ordered alphabetically by infohashes let info_hash_1 = InfoHash::from_str("9e0217d0fa71c87332cd8bf9dbeabcb2c2cf3c4d").unwrap(); let info_hash_2 = InfoHash::from_str("0b3aea4adc213ce32295be85d3883a63bca25446").unwrap(); - test_env.add_torrent_peer(&info_hash_1, &PeerBuilder::default().into()).await; - test_env.add_torrent_peer(&info_hash_2, &PeerBuilder::default().into()).await; + env.add_torrent_peer(&info_hash_1, &PeerBuilder::default().into()).await; + env.add_torrent_peer(&info_hash_2, &PeerBuilder::default().into()).await; - let response = Client::new(test_env.get_connection_info()) + let response = Client::new(env.get_connection_info()) .get_torrents(Query::params([QueryParam::new("offset", "1")].to_vec())) .await; @@ -97,75 +97,73 @@ async fn should_allow_the_torrents_result_pagination() { ) .await; - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_fail_getting_torrents_when_the_offset_query_parameter_cannot_be_parsed() { - let test_env = running_test_environment(configuration::ephemeral()).await; + let env = Started::new(&configuration::ephemeral().into()).await; let invalid_offsets = [" ", "-1", "1.1", "INVALID OFFSET"]; for invalid_offset in &invalid_offsets { - let response = Client::new(test_env.get_connection_info()) + let response = Client::new(env.get_connection_info()) .get_torrents(Query::params([QueryParam::new("offset", invalid_offset)].to_vec())) .await; assert_bad_request(response, "Failed to deserialize query string: invalid digit found in string").await; } - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_fail_getting_torrents_when_the_limit_query_parameter_cannot_be_parsed() { - let test_env = running_test_environment(configuration::ephemeral()).await; + let env = Started::new(&configuration::ephemeral().into()).await; let invalid_limits = [" ", "-1", "1.1", "INVALID LIMIT"]; for invalid_limit in &invalid_limits { - let response = Client::new(test_env.get_connection_info()) + let response = Client::new(env.get_connection_info()) .get_torrents(Query::params([QueryParam::new("limit", invalid_limit)].to_vec())) .await; assert_bad_request(response, "Failed to deserialize query string: invalid digit found in string").await; } - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_not_allow_getting_torrents_for_unauthenticated_users() { - let test_env = running_test_environment(configuration::ephemeral()).await; + let env = Started::new(&configuration::ephemeral().into()).await; - let response = Client::new(connection_with_invalid_token( - test_env.get_connection_info().bind_address.as_str(), - )) - .get_torrents(Query::empty()) - .await; + let response = Client::new(connection_with_invalid_token(env.get_connection_info().bind_address.as_str())) + .get_torrents(Query::empty()) + .await; assert_token_not_valid(response).await; - let response = Client::new(connection_with_no_token(test_env.get_connection_info().bind_address.as_str())) + let response = Client::new(connection_with_no_token(env.get_connection_info().bind_address.as_str())) .get_torrents(Query::default()) .await; assert_unauthorized(response).await; - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_allow_getting_a_torrent_info() { - let test_env = running_test_environment(configuration::ephemeral()).await; + let env = Started::new(&configuration::ephemeral().into()).await; let info_hash = InfoHash::from_str("9e0217d0fa71c87332cd8bf9dbeabcb2c2cf3c4d").unwrap(); let peer = PeerBuilder::default().into(); - test_env.add_torrent_peer(&info_hash, &peer).await; + env.add_torrent_peer(&info_hash, &peer).await; - let response = Client::new(test_env.get_connection_info()) + let response = Client::new(env.get_connection_info()) .get_torrent(&info_hash.to_string()) .await; @@ -181,68 +179,62 @@ async fn should_allow_getting_a_torrent_info() { ) .await; - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_fail_while_getting_a_torrent_info_when_the_torrent_does_not_exist() { - let test_env = running_test_environment(configuration::ephemeral()).await; + let env = Started::new(&configuration::ephemeral().into()).await; let info_hash = InfoHash::from_str("9e0217d0fa71c87332cd8bf9dbeabcb2c2cf3c4d").unwrap(); - let response = Client::new(test_env.get_connection_info()) + let response = Client::new(env.get_connection_info()) .get_torrent(&info_hash.to_string()) .await; assert_torrent_not_known(response).await; - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_fail_getting_a_torrent_info_when_the_provided_infohash_is_invalid() { - let test_env = running_test_environment(configuration::ephemeral()).await; + let env = Started::new(&configuration::ephemeral().into()).await; for invalid_infohash in &invalid_infohashes_returning_bad_request() { - let response = Client::new(test_env.get_connection_info()) - .get_torrent(invalid_infohash) - .await; + let response = Client::new(env.get_connection_info()).get_torrent(invalid_infohash).await; assert_invalid_infohash_param(response, invalid_infohash).await; } for invalid_infohash in &invalid_infohashes_returning_not_found() { - let response = Client::new(test_env.get_connection_info()) - .get_torrent(invalid_infohash) - .await; + let response = Client::new(env.get_connection_info()).get_torrent(invalid_infohash).await; assert_not_found(response).await; } - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_not_allow_getting_a_torrent_info_for_unauthenticated_users() { - let test_env = running_test_environment(configuration::ephemeral()).await; + let env = Started::new(&configuration::ephemeral().into()).await; let info_hash = InfoHash::from_str("9e0217d0fa71c87332cd8bf9dbeabcb2c2cf3c4d").unwrap(); - test_env.add_torrent_peer(&info_hash, &PeerBuilder::default().into()).await; + env.add_torrent_peer(&info_hash, &PeerBuilder::default().into()).await; - let response = Client::new(connection_with_invalid_token( - test_env.get_connection_info().bind_address.as_str(), - )) - .get_torrent(&info_hash.to_string()) - .await; + let response = Client::new(connection_with_invalid_token(env.get_connection_info().bind_address.as_str())) + .get_torrent(&info_hash.to_string()) + .await; assert_token_not_valid(response).await; - let response = Client::new(connection_with_no_token(test_env.get_connection_info().bind_address.as_str())) + let response = Client::new(connection_with_no_token(env.get_connection_info().bind_address.as_str())) .get_torrent(&info_hash.to_string()) .await; assert_unauthorized(response).await; - test_env.stop().await; + env.stop().await; } diff --git a/tests/servers/api/v1/contract/context/whitelist.rs b/tests/servers/api/v1/contract/context/whitelist.rs index 60ab4c90..358a4a19 100644 --- a/tests/servers/api/v1/contract/context/whitelist.rs +++ b/tests/servers/api/v1/contract/context/whitelist.rs @@ -4,8 +4,6 @@ use torrust_tracker::shared::bit_torrent::info_hash::InfoHash; use torrust_tracker_test_helpers::configuration; use crate::servers::api::connection_info::{connection_with_invalid_token, connection_with_no_token}; -use crate::servers::api::force_database_error; -use crate::servers::api::test_environment::running_test_environment; use crate::servers::api::v1::asserts::{ assert_failed_to_reload_whitelist, assert_failed_to_remove_torrent_from_whitelist, assert_failed_to_whitelist_torrent, assert_invalid_infohash_param, assert_not_found, assert_ok, assert_token_not_valid, assert_unauthorized, @@ -14,35 +12,33 @@ use crate::servers::api::v1::client::Client; use crate::servers::api::v1::contract::fixtures::{ invalid_infohashes_returning_bad_request, invalid_infohashes_returning_not_found, }; +use crate::servers::api::{force_database_error, Started}; #[tokio::test] async fn should_allow_whitelisting_a_torrent() { - let test_env = running_test_environment(configuration::ephemeral()).await; + let env = Started::new(&configuration::ephemeral().into()).await; let info_hash = "9e0217d0fa71c87332cd8bf9dbeabcb2c2cf3c4d".to_owned(); - let response = Client::new(test_env.get_connection_info()) - .whitelist_a_torrent(&info_hash) - .await; + let response = Client::new(env.get_connection_info()).whitelist_a_torrent(&info_hash).await; assert_ok(response).await; assert!( - test_env - .tracker + env.tracker .is_info_hash_whitelisted(&InfoHash::from_str(&info_hash).unwrap()) .await ); - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_allow_whitelisting_a_torrent_that_has_been_already_whitelisted() { - let test_env = running_test_environment(configuration::ephemeral()).await; + let env = Started::new(&configuration::ephemeral().into()).await; let info_hash = "9e0217d0fa71c87332cd8bf9dbeabcb2c2cf3c4d".to_owned(); - let api_client = Client::new(test_env.get_connection_info()); + let api_client = Client::new(env.get_connection_info()); let response = api_client.whitelist_a_torrent(&info_hash).await; assert_ok(response).await; @@ -50,55 +46,51 @@ async fn should_allow_whitelisting_a_torrent_that_has_been_already_whitelisted() let response = api_client.whitelist_a_torrent(&info_hash).await; assert_ok(response).await; - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_not_allow_whitelisting_a_torrent_for_unauthenticated_users() { - let test_env = running_test_environment(configuration::ephemeral()).await; + let env = Started::new(&configuration::ephemeral().into()).await; let info_hash = "9e0217d0fa71c87332cd8bf9dbeabcb2c2cf3c4d".to_owned(); - let response = Client::new(connection_with_invalid_token( - test_env.get_connection_info().bind_address.as_str(), - )) - .whitelist_a_torrent(&info_hash) - .await; + let response = Client::new(connection_with_invalid_token(env.get_connection_info().bind_address.as_str())) + .whitelist_a_torrent(&info_hash) + .await; assert_token_not_valid(response).await; - let response = Client::new(connection_with_no_token(test_env.get_connection_info().bind_address.as_str())) + let response = Client::new(connection_with_no_token(env.get_connection_info().bind_address.as_str())) .whitelist_a_torrent(&info_hash) .await; assert_unauthorized(response).await; - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_fail_when_the_torrent_cannot_be_whitelisted() { - let test_env = running_test_environment(configuration::ephemeral()).await; + let env = Started::new(&configuration::ephemeral().into()).await; let info_hash = "9e0217d0fa71c87332cd8bf9dbeabcb2c2cf3c4d".to_owned(); - force_database_error(&test_env.tracker); + force_database_error(&env.tracker); - let response = Client::new(test_env.get_connection_info()) - .whitelist_a_torrent(&info_hash) - .await; + let response = Client::new(env.get_connection_info()).whitelist_a_torrent(&info_hash).await; assert_failed_to_whitelist_torrent(response).await; - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_fail_whitelisting_a_torrent_when_the_provided_infohash_is_invalid() { - let test_env = running_test_environment(configuration::ephemeral()).await; + let env = Started::new(&configuration::ephemeral().into()).await; for invalid_infohash in &invalid_infohashes_returning_bad_request() { - let response = Client::new(test_env.get_connection_info()) + let response = Client::new(env.get_connection_info()) .whitelist_a_torrent(invalid_infohash) .await; @@ -106,55 +98,55 @@ async fn should_fail_whitelisting_a_torrent_when_the_provided_infohash_is_invali } for invalid_infohash in &invalid_infohashes_returning_not_found() { - let response = Client::new(test_env.get_connection_info()) + let response = Client::new(env.get_connection_info()) .whitelist_a_torrent(invalid_infohash) .await; assert_not_found(response).await; } - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_allow_removing_a_torrent_from_the_whitelist() { - let test_env = running_test_environment(configuration::ephemeral()).await; + let env = Started::new(&configuration::ephemeral().into()).await; let hash = "9e0217d0fa71c87332cd8bf9dbeabcb2c2cf3c4d".to_owned(); let info_hash = InfoHash::from_str(&hash).unwrap(); - test_env.tracker.add_torrent_to_whitelist(&info_hash).await.unwrap(); + env.tracker.add_torrent_to_whitelist(&info_hash).await.unwrap(); - let response = Client::new(test_env.get_connection_info()) + let response = Client::new(env.get_connection_info()) .remove_torrent_from_whitelist(&hash) .await; assert_ok(response).await; - assert!(!test_env.tracker.is_info_hash_whitelisted(&info_hash).await); + assert!(!env.tracker.is_info_hash_whitelisted(&info_hash).await); - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_not_fail_trying_to_remove_a_non_whitelisted_torrent_from_the_whitelist() { - let test_env = running_test_environment(configuration::ephemeral()).await; + let env = Started::new(&configuration::ephemeral().into()).await; let non_whitelisted_torrent_hash = "9e0217d0fa71c87332cd8bf9dbeabcb2c2cf3c4d".to_owned(); - let response = Client::new(test_env.get_connection_info()) + let response = Client::new(env.get_connection_info()) .remove_torrent_from_whitelist(&non_whitelisted_torrent_hash) .await; assert_ok(response).await; - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_fail_removing_a_torrent_from_the_whitelist_when_the_provided_infohash_is_invalid() { - let test_env = running_test_environment(configuration::ephemeral()).await; + let env = Started::new(&configuration::ephemeral().into()).await; for invalid_infohash in &invalid_infohashes_returning_bad_request() { - let response = Client::new(test_env.get_connection_info()) + let response = Client::new(env.get_connection_info()) .remove_torrent_from_whitelist(invalid_infohash) .await; @@ -162,99 +154,97 @@ async fn should_fail_removing_a_torrent_from_the_whitelist_when_the_provided_inf } for invalid_infohash in &invalid_infohashes_returning_not_found() { - let response = Client::new(test_env.get_connection_info()) + let response = Client::new(env.get_connection_info()) .remove_torrent_from_whitelist(invalid_infohash) .await; assert_not_found(response).await; } - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_fail_when_the_torrent_cannot_be_removed_from_the_whitelist() { - let test_env = running_test_environment(configuration::ephemeral()).await; + let env = Started::new(&configuration::ephemeral().into()).await; let hash = "9e0217d0fa71c87332cd8bf9dbeabcb2c2cf3c4d".to_owned(); let info_hash = InfoHash::from_str(&hash).unwrap(); - test_env.tracker.add_torrent_to_whitelist(&info_hash).await.unwrap(); + env.tracker.add_torrent_to_whitelist(&info_hash).await.unwrap(); - force_database_error(&test_env.tracker); + force_database_error(&env.tracker); - let response = Client::new(test_env.get_connection_info()) + let response = Client::new(env.get_connection_info()) .remove_torrent_from_whitelist(&hash) .await; assert_failed_to_remove_torrent_from_whitelist(response).await; - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_not_allow_removing_a_torrent_from_the_whitelist_for_unauthenticated_users() { - let test_env = running_test_environment(configuration::ephemeral()).await; + let env = Started::new(&configuration::ephemeral().into()).await; let hash = "9e0217d0fa71c87332cd8bf9dbeabcb2c2cf3c4d".to_owned(); let info_hash = InfoHash::from_str(&hash).unwrap(); - test_env.tracker.add_torrent_to_whitelist(&info_hash).await.unwrap(); - let response = Client::new(connection_with_invalid_token( - test_env.get_connection_info().bind_address.as_str(), - )) - .remove_torrent_from_whitelist(&hash) - .await; + env.tracker.add_torrent_to_whitelist(&info_hash).await.unwrap(); + let response = Client::new(connection_with_invalid_token(env.get_connection_info().bind_address.as_str())) + .remove_torrent_from_whitelist(&hash) + .await; assert_token_not_valid(response).await; - test_env.tracker.add_torrent_to_whitelist(&info_hash).await.unwrap(); - let response = Client::new(connection_with_no_token(test_env.get_connection_info().bind_address.as_str())) + env.tracker.add_torrent_to_whitelist(&info_hash).await.unwrap(); + let response = Client::new(connection_with_no_token(env.get_connection_info().bind_address.as_str())) .remove_torrent_from_whitelist(&hash) .await; assert_unauthorized(response).await; - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_allow_reload_the_whitelist_from_the_database() { - let test_env = running_test_environment(configuration::ephemeral()).await; + let env = Started::new(&configuration::ephemeral().into()).await; let hash = "9e0217d0fa71c87332cd8bf9dbeabcb2c2cf3c4d".to_owned(); let info_hash = InfoHash::from_str(&hash).unwrap(); - test_env.tracker.add_torrent_to_whitelist(&info_hash).await.unwrap(); + env.tracker.add_torrent_to_whitelist(&info_hash).await.unwrap(); - let response = Client::new(test_env.get_connection_info()).reload_whitelist().await; + let response = Client::new(env.get_connection_info()).reload_whitelist().await; assert_ok(response).await; /* todo: this assert fails because the whitelist has not been reloaded yet. We could add a new endpoint GET /api/whitelist/:info_hash to check if a torrent is whitelisted and use that endpoint to check if the torrent is still there after reloading. assert!( - !(test_env + !(env .tracker .is_info_hash_whitelisted(&InfoHash::from_str(&info_hash).unwrap()) .await) ); */ - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_fail_when_the_whitelist_cannot_be_reloaded_from_the_database() { - let test_env = running_test_environment(configuration::ephemeral()).await; + let env = Started::new(&configuration::ephemeral().into()).await; let hash = "9e0217d0fa71c87332cd8bf9dbeabcb2c2cf3c4d".to_owned(); let info_hash = InfoHash::from_str(&hash).unwrap(); - test_env.tracker.add_torrent_to_whitelist(&info_hash).await.unwrap(); + env.tracker.add_torrent_to_whitelist(&info_hash).await.unwrap(); - force_database_error(&test_env.tracker); + force_database_error(&env.tracker); - let response = Client::new(test_env.get_connection_info()).reload_whitelist().await; + let response = Client::new(env.get_connection_info()).reload_whitelist().await; assert_failed_to_reload_whitelist(response).await; - test_env.stop().await; + env.stop().await; } diff --git a/tests/servers/health_check_api/contract.rs b/tests/servers/health_check_api/contract.rs index c02335d0..7b00866d 100644 --- a/tests/servers/health_check_api/contract.rs +++ b/tests/servers/health_check_api/contract.rs @@ -3,23 +3,311 @@ use torrust_tracker::servers::registar::Registar; use torrust_tracker_test_helpers::configuration; use crate::servers::health_check_api::client::get; -use crate::servers::health_check_api::test_environment; +use crate::servers::health_check_api::Started; #[tokio::test] -async fn health_check_endpoint_should_return_status_ok_when_no_service_is_running() { +async fn health_check_endpoint_should_return_status_ok_when_there_is_no_services_registered() { let configuration = configuration::ephemeral_with_no_services(); - let registar = &Registar::default(); + let env = Started::new(&configuration.health_check_api.into(), Registar::default()).await; - let (bound_addr, test_env) = test_environment::start(&configuration.health_check_api, registar.entries()).await; - - let url = format!("http://{bound_addr}/health_check"); - - let response = get(&url).await; + let response = get(&format!("http://{}/health_check", env.state.binding)).await; assert_eq!(response.status(), 200); assert_eq!(response.headers().get("content-type").unwrap(), "application/json"); - assert_eq!(response.json::().await.unwrap().status, Status::Ok); - test_env.abort(); + let report = response + .json::() + .await + .expect("it should be able to get the report as json"); + + assert_eq!(report.status, Status::None); + + env.stop().await.expect("it should stop the service"); +} + +mod api { + use std::sync::Arc; + + use torrust_tracker::servers::health_check_api::resources::{Report, Status}; + use torrust_tracker_test_helpers::configuration; + + use crate::servers::api; + use crate::servers::health_check_api::client::get; + use crate::servers::health_check_api::Started; + + #[tokio::test] + pub(crate) async fn it_should_return_good_health_for_api_service() { + let configuration = Arc::new(configuration::ephemeral()); + + let service = api::Started::new(&configuration).await; + + let registar = service.registar.clone(); + + { + let config = configuration.health_check_api.clone(); + let env = Started::new(&config.into(), registar).await; + + let response = get(&format!("http://{}/health_check", env.state.binding)).await; + + assert_eq!(response.status(), 200); + assert_eq!(response.headers().get("content-type").unwrap(), "application/json"); + + let report: Report = response + .json() + .await + .expect("it should be able to get the report from the json"); + + assert_eq!(report.status, Status::Ok); + assert_eq!(report.message, String::new()); + + let details = report.details.first().expect("it should have some details"); + + assert_eq!(details.binding, service.bind_address()); + + assert_eq!(details.result, Ok("200 OK".to_string())); + + assert_eq!( + details.info, + format!( + "checking api health check at: http://{}/api/health_check", + service.bind_address() + ) + ); + + env.stop().await.expect("it should stop the service"); + } + + service.stop().await; + } + + #[tokio::test] + pub(crate) async fn it_should_return_error_when_api_service_was_stopped_after_registration() { + let configuration = Arc::new(configuration::ephemeral()); + + let service = api::Started::new(&configuration).await; + + let binding = service.bind_address(); + + let registar = service.registar.clone(); + + service.server.stop().await.expect("it should stop udp server"); + + { + let config = configuration.health_check_api.clone(); + let env = Started::new(&config.into(), registar).await; + + let response = get(&format!("http://{}/health_check", env.state.binding)).await; + + assert_eq!(response.status(), 200); + assert_eq!(response.headers().get("content-type").unwrap(), "application/json"); + + let report: Report = response + .json() + .await + .expect("it should be able to get the report from the json"); + + assert_eq!(report.status, Status::Error); + assert_eq!(report.message, "health check failed".to_string()); + + let details = report.details.first().expect("it should have some details"); + + assert_eq!(details.binding, binding); + assert!(details.result.as_ref().is_err_and(|e| e.contains("Connection refused"))); + assert_eq!( + details.info, + format!("checking api health check at: http://{binding}/api/health_check") + ); + + env.stop().await.expect("it should stop the service"); + } + } +} + +mod http { + use std::sync::Arc; + + use torrust_tracker::servers::health_check_api::resources::{Report, Status}; + use torrust_tracker_test_helpers::configuration; + + use crate::servers::health_check_api::client::get; + use crate::servers::health_check_api::Started; + use crate::servers::http; + + #[tokio::test] + pub(crate) async fn it_should_return_good_health_for_http_service() { + let configuration = Arc::new(configuration::ephemeral()); + + let service = http::Started::new(&configuration).await; + + let registar = service.registar.clone(); + + { + let config = configuration.health_check_api.clone(); + let env = Started::new(&config.into(), registar).await; + + let response = get(&format!("http://{}/health_check", env.state.binding)).await; + + assert_eq!(response.status(), 200); + assert_eq!(response.headers().get("content-type").unwrap(), "application/json"); + + let report: Report = response + .json() + .await + .expect("it should be able to get the report from the json"); + + assert_eq!(report.status, Status::Ok); + assert_eq!(report.message, String::new()); + + let details = report.details.first().expect("it should have some details"); + + assert_eq!(details.binding, *service.bind_address()); + assert_eq!(details.result, Ok("200 OK".to_string())); + + assert_eq!( + details.info, + format!( + "checking http tracker health check at: http://{}/health_check", + service.bind_address() + ) + ); + + env.stop().await.expect("it should stop the service"); + } + + service.stop().await; + } + + #[tokio::test] + pub(crate) async fn it_should_return_error_when_http_service_was_stopped_after_registration() { + let configuration = Arc::new(configuration::ephemeral()); + + let service = http::Started::new(&configuration).await; + + let binding = *service.bind_address(); + + let registar = service.registar.clone(); + + service.server.stop().await.expect("it should stop udp server"); + + { + let config = configuration.health_check_api.clone(); + let env = Started::new(&config.into(), registar).await; + + let response = get(&format!("http://{}/health_check", env.state.binding)).await; + + assert_eq!(response.status(), 200); + assert_eq!(response.headers().get("content-type").unwrap(), "application/json"); + + let report: Report = response + .json() + .await + .expect("it should be able to get the report from the json"); + + assert_eq!(report.status, Status::Error); + assert_eq!(report.message, "health check failed".to_string()); + + let details = report.details.first().expect("it should have some details"); + + assert_eq!(details.binding, binding); + assert!(details.result.as_ref().is_err_and(|e| e.contains("Connection refused"))); + assert_eq!( + details.info, + format!("checking http tracker health check at: http://{binding}/health_check") + ); + + env.stop().await.expect("it should stop the service"); + } + } +} + +mod udp { + use std::sync::Arc; + + use torrust_tracker::servers::health_check_api::resources::{Report, Status}; + use torrust_tracker_test_helpers::configuration; + + use crate::servers::health_check_api::client::get; + use crate::servers::health_check_api::Started; + use crate::servers::udp; + + #[tokio::test] + pub(crate) async fn it_should_return_good_health_for_udp_service() { + let configuration = Arc::new(configuration::ephemeral()); + + let service = udp::Started::new(&configuration).await; + + let registar = service.registar.clone(); + + { + let config = configuration.health_check_api.clone(); + let env = Started::new(&config.into(), registar).await; + + let response = get(&format!("http://{}/health_check", env.state.binding)).await; + + assert_eq!(response.status(), 200); + assert_eq!(response.headers().get("content-type").unwrap(), "application/json"); + + let report: Report = response + .json() + .await + .expect("it should be able to get the report from the json"); + + assert_eq!(report.status, Status::Ok); + assert_eq!(report.message, String::new()); + + let details = report.details.first().expect("it should have some details"); + + assert_eq!(details.binding, service.bind_address()); + assert_eq!(details.result, Ok("Connected".to_string())); + + assert_eq!( + details.info, + format!("checking the udp tracker health check at: {}", service.bind_address()) + ); + + env.stop().await.expect("it should stop the service"); + } + + service.stop().await; + } + + #[tokio::test] + pub(crate) async fn it_should_return_error_when_udp_service_was_stopped_after_registration() { + let configuration = Arc::new(configuration::ephemeral()); + + let service = udp::Started::new(&configuration).await; + + let binding = service.bind_address(); + + let registar = service.registar.clone(); + + service.server.stop().await.expect("it should stop udp server"); + + { + let config = configuration.health_check_api.clone(); + let env = Started::new(&config.into(), registar).await; + + let response = get(&format!("http://{}/health_check", env.state.binding)).await; + + assert_eq!(response.status(), 200); + assert_eq!(response.headers().get("content-type").unwrap(), "application/json"); + + let report: Report = response + .json() + .await + .expect("it should be able to get the report from the json"); + + assert_eq!(report.status, Status::Error); + assert_eq!(report.message, "health check failed".to_string()); + + let details = report.details.first().expect("it should have some details"); + + assert_eq!(details.binding, binding); + assert_eq!(details.result, Err("Timed Out".to_string())); + assert_eq!(details.info, format!("checking the udp tracker health check at: {binding}")); + + env.stop().await.expect("it should stop the service"); + } + } } diff --git a/tests/servers/health_check_api/environment.rs b/tests/servers/health_check_api/environment.rs new file mode 100644 index 00000000..9aa3ab16 --- /dev/null +++ b/tests/servers/health_check_api/environment.rs @@ -0,0 +1,91 @@ +use std::net::SocketAddr; +use std::sync::Arc; + +use tokio::sync::oneshot::{self, Sender}; +use tokio::task::JoinHandle; +use torrust_tracker::bootstrap::jobs::Started; +use torrust_tracker::servers::health_check_api::server; +use torrust_tracker::servers::registar::Registar; +use torrust_tracker::servers::signals::{self, Halted}; +use torrust_tracker_configuration::HealthCheckApi; + +#[derive(Debug)] +pub enum Error { + Error(String), +} + +pub struct Running { + pub binding: SocketAddr, + pub halt_task: Sender, + pub task: JoinHandle, +} + +pub struct Stopped { + pub bind_to: SocketAddr, +} + +pub struct Environment { + pub registar: Registar, + pub state: S, +} + +impl Environment { + pub fn new(config: &Arc, registar: Registar) -> Self { + let bind_to = config + .bind_address + .parse::() + .expect("Tracker API bind_address invalid."); + + Self { + registar, + state: Stopped { bind_to }, + } + } + + /// Start the test environment for the Health Check API. + /// It runs the API server. + pub async fn start(self) -> Environment { + let (tx_start, rx_start) = oneshot::channel::(); + let (tx_halt, rx_halt) = tokio::sync::oneshot::channel::(); + + let register = self.registar.entries(); + + let server = tokio::spawn(async move { + server::start(self.state.bind_to, tx_start, rx_halt, register) + .await + .expect("it should start the health check service"); + self.state.bind_to + }); + + let binding = rx_start.await.expect("it should send service binding").address; + + Environment { + registar: self.registar.clone(), + state: Running { + task: server, + halt_task: tx_halt, + binding, + }, + } + } +} + +impl Environment { + pub async fn new(config: &Arc, registar: Registar) -> Self { + Environment::::new(config, registar).start().await + } + + pub async fn stop(self) -> Result, Error> { + self.state + .halt_task + .send(Halted::Normal) + .map_err(|e| Error::Error(e.to_string()))?; + + let bind_to = self.state.task.await.expect("it should shutdown the service"); + + Ok(Environment { + registar: self.registar.clone(), + state: Stopped { bind_to }, + }) + } +} diff --git a/tests/servers/health_check_api/mod.rs b/tests/servers/health_check_api/mod.rs index 89f19a33..9e15c5f6 100644 --- a/tests/servers/health_check_api/mod.rs +++ b/tests/servers/health_check_api/mod.rs @@ -1,3 +1,5 @@ pub mod client; pub mod contract; -pub mod test_environment; +pub mod environment; + +pub type Started = environment::Environment; diff --git a/tests/servers/health_check_api/test_environment.rs b/tests/servers/health_check_api/test_environment.rs deleted file mode 100644 index 18924e10..00000000 --- a/tests/servers/health_check_api/test_environment.rs +++ /dev/null @@ -1,33 +0,0 @@ -use std::net::SocketAddr; - -use tokio::sync::oneshot; -use tokio::task::JoinHandle; -use torrust_tracker::bootstrap::jobs::Started; -use torrust_tracker::servers::health_check_api::server; -use torrust_tracker::servers::registar::ServiceRegistry; -use torrust_tracker_configuration::HealthCheckApi; - -/// Start the test environment for the Health Check API. -/// It runs the API server. -pub async fn start(config: &HealthCheckApi, register: ServiceRegistry) -> (SocketAddr, JoinHandle<()>) { - let bind_addr = config - .bind_address - .parse::() - .expect("Health Check API bind_address invalid."); - - let (tx, rx) = oneshot::channel::(); - - let join_handle = tokio::spawn(async move { - let handle = server::start(bind_addr, tx, register); - if let Ok(()) = handle.await { - panic!("Health Check API server on http://{bind_addr} stopped"); - } - }); - - let bound_addr = match rx.await { - Ok(msg) => msg.address, - Err(e) => panic!("the Health Check API server was dropped: {e}"), - }; - - (bound_addr, join_handle) -} diff --git a/tests/servers/http/environment.rs b/tests/servers/http/environment.rs new file mode 100644 index 00000000..326f4e53 --- /dev/null +++ b/tests/servers/http/environment.rs @@ -0,0 +1,81 @@ +use std::sync::Arc; + +use futures::executor::block_on; +use torrust_tracker::bootstrap::app::initialize_with_configuration; +use torrust_tracker::bootstrap::jobs::make_rust_tls; +use torrust_tracker::core::peer::Peer; +use torrust_tracker::core::Tracker; +use torrust_tracker::servers::http::server::{HttpServer, Launcher, Running, Stopped}; +use torrust_tracker::servers::registar::Registar; +use torrust_tracker::shared::bit_torrent::info_hash::InfoHash; +use torrust_tracker_configuration::{Configuration, HttpTracker}; + +pub struct Environment { + pub config: Arc, + pub tracker: Arc, + pub registar: Registar, + pub server: HttpServer, +} + +impl Environment { + /// Add a torrent to the tracker + pub async fn add_torrent_peer(&self, info_hash: &InfoHash, peer: &Peer) { + self.tracker.update_torrent_with_peer_and_get_stats(info_hash, peer).await; + } +} + +impl Environment { + #[allow(dead_code)] + pub fn new(configuration: &Arc) -> Self { + let tracker = initialize_with_configuration(configuration); + + let config = Arc::new(configuration.http_trackers[0].clone()); + + let bind_to = config + .bind_address + .parse::() + .expect("Tracker API bind_address invalid."); + + let tls = block_on(make_rust_tls(config.ssl_enabled, &config.ssl_cert_path, &config.ssl_key_path)) + .map(|tls| tls.expect("tls config failed")); + + let server = HttpServer::new(Launcher::new(bind_to, tls)); + + Self { + config, + tracker, + registar: Registar::default(), + server, + } + } + + #[allow(dead_code)] + pub async fn start(self) -> Environment { + Environment { + config: self.config, + tracker: self.tracker.clone(), + registar: self.registar.clone(), + server: self.server.start(self.tracker, self.registar.give_form()).await.unwrap(), + } + } +} + +impl Environment { + pub async fn new(configuration: &Arc) -> Self { + Environment::::new(configuration).start().await + } + + pub async fn stop(self) -> Environment { + Environment { + config: self.config, + tracker: self.tracker, + registar: Registar::default(), + + server: self.server.stop().await.unwrap(), + } + } + + pub fn bind_address(&self) -> &std::net::SocketAddr { + &self.server.state.binding + } +} diff --git a/tests/servers/http/mod.rs b/tests/servers/http/mod.rs index cb2885df..65affc43 100644 --- a/tests/servers/http/mod.rs +++ b/tests/servers/http/mod.rs @@ -1,11 +1,14 @@ pub mod asserts; pub mod client; +pub mod environment; pub mod requests; pub mod responses; -pub mod test_environment; pub mod v1; +pub type Started = environment::Environment; + use percent_encoding::NON_ALPHANUMERIC; +use torrust_tracker::servers::http::server; pub type ByteArray20 = [u8; 20]; diff --git a/tests/servers/http/test_environment.rs b/tests/servers/http/test_environment.rs deleted file mode 100644 index 9cab40db..00000000 --- a/tests/servers/http/test_environment.rs +++ /dev/null @@ -1,133 +0,0 @@ -use std::sync::Arc; - -use futures::executor::block_on; -use torrust_tracker::bootstrap::jobs::make_rust_tls; -use torrust_tracker::core::peer::Peer; -use torrust_tracker::core::Tracker; -use torrust_tracker::servers::http::server::{HttpServer, Launcher, RunningHttpServer, StoppedHttpServer}; -use torrust_tracker::servers::registar::Registar; -use torrust_tracker::shared::bit_torrent::info_hash::InfoHash; - -use crate::common::app::setup_with_configuration; - -#[allow(clippy::module_name_repetitions, dead_code)] -pub type StoppedTestEnvironment = TestEnvironment; -#[allow(clippy::module_name_repetitions)] -pub type RunningTestEnvironment = TestEnvironment; - -pub struct TestEnvironment { - pub cfg: Arc, - pub tracker: Arc, - pub state: S, -} - -#[allow(dead_code)] -pub struct Stopped { - http_server: StoppedHttpServer, -} - -pub struct Running { - http_server: RunningHttpServer, -} - -impl TestEnvironment { - /// Add a torrent to the tracker - pub async fn add_torrent_peer(&self, info_hash: &InfoHash, peer: &Peer) { - self.tracker.update_torrent_with_peer_and_get_stats(info_hash, peer).await; - } -} - -impl TestEnvironment { - #[allow(dead_code)] - pub fn new_stopped(cfg: torrust_tracker_configuration::Configuration) -> Self { - let cfg = Arc::new(cfg); - - let tracker = setup_with_configuration(&cfg); - - let config = cfg.http_trackers[0].clone(); - - let bind_to = config - .bind_address - .parse::() - .expect("Tracker API bind_address invalid."); - - let tls = block_on(make_rust_tls(config.ssl_enabled, &config.ssl_cert_path, &config.ssl_key_path)) - .map(|tls| tls.expect("tls config failed")); - - let http_server = HttpServer::new(Launcher::new(bind_to, tls)); - - Self { - cfg, - tracker, - state: Stopped { http_server }, - } - } - - #[allow(dead_code)] - pub async fn start(self) -> TestEnvironment { - TestEnvironment { - cfg: self.cfg, - tracker: self.tracker.clone(), - state: Running { - http_server: self - .state - .http_server - .start(self.tracker, Registar::default().give_form()) - .await - .unwrap(), - }, - } - } - - // #[allow(dead_code)] - // pub fn config(&self) -> &torrust_tracker_configuration::HttpTracker { - // &self.state.http_server.cfg - // } - - // #[allow(dead_code)] - // pub fn config_mut(&mut self) -> &mut torrust_tracker_configuration::HttpTracker { - // &mut self.state.http_server.cfg - // } -} - -impl TestEnvironment { - pub async fn new_running(cfg: torrust_tracker_configuration::Configuration) -> Self { - let test_env = StoppedTestEnvironment::new_stopped(cfg); - - test_env.start().await - } - - pub async fn stop(self) -> TestEnvironment { - TestEnvironment { - cfg: self.cfg, - tracker: self.tracker, - state: Stopped { - http_server: self.state.http_server.stop().await.unwrap(), - }, - } - } - - pub fn bind_address(&self) -> &std::net::SocketAddr { - &self.state.http_server.state.binding - } - - // #[allow(dead_code)] - // pub fn config(&self) -> &torrust_tracker_configuration::HttpTracker { - // &self.state.http_server.cfg - // } -} - -#[allow(clippy::module_name_repetitions, dead_code)] -pub fn stopped_test_environment(cfg: torrust_tracker_configuration::Configuration) -> StoppedTestEnvironment { - TestEnvironment::new_stopped(cfg) -} - -#[allow(clippy::module_name_repetitions)] -pub async fn running_test_environment(cfg: torrust_tracker_configuration::Configuration) -> RunningTestEnvironment { - TestEnvironment::new_running(cfg).await -} - -#[allow(dead_code)] -pub fn http_server(launcher: Launcher) -> StoppedHttpServer { - HttpServer::new(launcher) -} diff --git a/tests/servers/http/v1/contract.rs b/tests/servers/http/v1/contract.rs index e394779a..be285dcd 100644 --- a/tests/servers/http/v1/contract.rs +++ b/tests/servers/http/v1/contract.rs @@ -1,12 +1,12 @@ use torrust_tracker_test_helpers::configuration; -use crate::servers::http::test_environment::running_test_environment; +use crate::servers::http::Started; #[tokio::test] -async fn test_environment_should_be_started_and_stopped() { - let test_env = running_test_environment(configuration::ephemeral()).await; +async fn environment_should_be_started_and_stopped() { + let env = Started::new(&configuration::ephemeral().into()).await; - test_env.stop().await; + env.stop().await; } mod for_all_config_modes { @@ -15,19 +15,19 @@ mod for_all_config_modes { use torrust_tracker_test_helpers::configuration; use crate::servers::http::client::Client; - use crate::servers::http::test_environment::running_test_environment; + use crate::servers::http::Started; #[tokio::test] async fn health_check_endpoint_should_return_ok_if_the_http_tracker_is_running() { - let test_env = running_test_environment(configuration::ephemeral_with_reverse_proxy()).await; + let env = Started::new(&configuration::ephemeral_with_reverse_proxy().into()).await; - let response = Client::new(*test_env.bind_address()).health_check().await; + let response = Client::new(*env.bind_address()).health_check().await; assert_eq!(response.status(), 200); assert_eq!(response.headers().get("content-type").unwrap(), "application/json"); assert_eq!(response.json::().await.unwrap(), Report { status: Status::Ok }); - test_env.stop().await; + env.stop().await; } mod and_running_on_reverse_proxy { @@ -36,37 +36,37 @@ mod for_all_config_modes { use crate::servers::http::asserts::assert_could_not_find_remote_address_on_x_forwarded_for_header_error_response; use crate::servers::http::client::Client; use crate::servers::http::requests::announce::QueryBuilder; - use crate::servers::http::test_environment::running_test_environment; + use crate::servers::http::Started; #[tokio::test] async fn should_fail_when_the_http_request_does_not_include_the_xff_http_request_header() { // If the tracker is running behind a reverse proxy, the peer IP is the // right most IP in the `X-Forwarded-For` HTTP header, which is the IP of the proxy's client. - let test_env = running_test_environment(configuration::ephemeral_with_reverse_proxy()).await; + let env = Started::new(&configuration::ephemeral_with_reverse_proxy().into()).await; let params = QueryBuilder::default().query().params(); - let response = Client::new(*test_env.bind_address()).get(&format!("announce?{params}")).await; + let response = Client::new(*env.bind_address()).get(&format!("announce?{params}")).await; assert_could_not_find_remote_address_on_x_forwarded_for_header_error_response(response).await; - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_fail_when_the_xff_http_request_header_contains_an_invalid_ip() { - let test_env = running_test_environment(configuration::ephemeral_with_reverse_proxy()).await; + let env = Started::new(&configuration::ephemeral_with_reverse_proxy().into()).await; let params = QueryBuilder::default().query().params(); - let response = Client::new(*test_env.bind_address()) + let response = Client::new(*env.bind_address()) .get_with_header(&format!("announce?{params}"), "X-Forwarded-For", "INVALID IP") .await; assert_could_not_find_remote_address_on_x_forwarded_for_header_error_response(response).await; - test_env.stop().await; + env.stop().await; } } @@ -102,60 +102,59 @@ mod for_all_config_modes { }; use crate::servers::http::client::Client; use crate::servers::http::requests::announce::{Compact, QueryBuilder}; - use crate::servers::http::responses; use crate::servers::http::responses::announce::{Announce, CompactPeer, CompactPeerList, DictionaryPeer}; - use crate::servers::http::test_environment::running_test_environment; + use crate::servers::http::{responses, Started}; #[tokio::test] async fn it_should_start_and_stop() { - let test_env = running_test_environment(configuration::ephemeral_mode_public()).await; - test_env.stop().await; + let env = Started::new(&configuration::ephemeral_mode_public().into()).await; + env.stop().await; } #[tokio::test] async fn should_respond_if_only_the_mandatory_fields_are_provided() { - let test_env = running_test_environment(configuration::ephemeral()).await; + let env = Started::new(&configuration::ephemeral().into()).await; let mut params = QueryBuilder::default().query().params(); params.remove_optional_params(); - let response = Client::new(*test_env.bind_address()).get(&format!("announce?{params}")).await; + let response = Client::new(*env.bind_address()).get(&format!("announce?{params}")).await; assert_is_announce_response(response).await; - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_fail_when_the_url_query_component_is_empty() { - let test_env = running_test_environment(configuration::ephemeral()).await; + let env = Started::new(&configuration::ephemeral().into()).await; - let response = Client::new(*test_env.bind_address()).get("announce").await; + let response = Client::new(*env.bind_address()).get("announce").await; assert_missing_query_params_for_announce_request_error_response(response).await; - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_fail_when_url_query_parameters_are_invalid() { - let test_env = running_test_environment(configuration::ephemeral()).await; + let env = Started::new(&configuration::ephemeral().into()).await; let invalid_query_param = "a=b=c"; - let response = Client::new(*test_env.bind_address()) + let response = Client::new(*env.bind_address()) .get(&format!("announce?{invalid_query_param}")) .await; assert_cannot_parse_query_param_error_response(response, "invalid param a=b=c").await; - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_fail_when_a_mandatory_field_is_missing() { - let test_env = running_test_environment(configuration::ephemeral()).await; + let env = Started::new(&configuration::ephemeral().into()).await; // Without `info_hash` param @@ -163,7 +162,7 @@ mod for_all_config_modes { params.info_hash = None; - let response = Client::new(*test_env.bind_address()).get(&format!("announce?{params}")).await; + let response = Client::new(*env.bind_address()).get(&format!("announce?{params}")).await; assert_bad_announce_request_error_response(response, "missing param info_hash").await; @@ -173,7 +172,7 @@ mod for_all_config_modes { params.peer_id = None; - let response = Client::new(*test_env.bind_address()).get(&format!("announce?{params}")).await; + let response = Client::new(*env.bind_address()).get(&format!("announce?{params}")).await; assert_bad_announce_request_error_response(response, "missing param peer_id").await; @@ -183,28 +182,28 @@ mod for_all_config_modes { params.port = None; - let response = Client::new(*test_env.bind_address()).get(&format!("announce?{params}")).await; + let response = Client::new(*env.bind_address()).get(&format!("announce?{params}")).await; assert_bad_announce_request_error_response(response, "missing param port").await; - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_fail_when_the_info_hash_param_is_invalid() { - let test_env = running_test_environment(configuration::ephemeral()).await; + let env = Started::new(&configuration::ephemeral().into()).await; let mut params = QueryBuilder::default().query().params(); for invalid_value in &invalid_info_hashes() { params.set("info_hash", invalid_value); - let response = Client::new(*test_env.bind_address()).get(&format!("announce?{params}")).await; + let response = Client::new(*env.bind_address()).get(&format!("announce?{params}")).await; assert_cannot_parse_query_params_error_response(response, "").await; } - test_env.stop().await; + env.stop().await; } #[tokio::test] @@ -214,22 +213,22 @@ mod for_all_config_modes { // 1. If tracker is NOT running `on_reverse_proxy` from the remote client IP. // 2. If tracker is running `on_reverse_proxy` from `X-Forwarded-For` request HTTP header. - let test_env = running_test_environment(configuration::ephemeral()).await; + let env = Started::new(&configuration::ephemeral().into()).await; let mut params = QueryBuilder::default().query().params(); params.peer_addr = Some("INVALID-IP-ADDRESS".to_string()); - let response = Client::new(*test_env.bind_address()).get(&format!("announce?{params}")).await; + let response = Client::new(*env.bind_address()).get(&format!("announce?{params}")).await; assert_is_announce_response(response).await; - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_fail_when_the_downloaded_param_is_invalid() { - let test_env = running_test_environment(configuration::ephemeral()).await; + let env = Started::new(&configuration::ephemeral().into()).await; let mut params = QueryBuilder::default().query().params(); @@ -238,17 +237,17 @@ mod for_all_config_modes { for invalid_value in invalid_values { params.set("downloaded", invalid_value); - let response = Client::new(*test_env.bind_address()).get(&format!("announce?{params}")).await; + let response = Client::new(*env.bind_address()).get(&format!("announce?{params}")).await; assert_bad_announce_request_error_response(response, "invalid param value").await; } - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_fail_when_the_uploaded_param_is_invalid() { - let test_env = running_test_environment(configuration::ephemeral()).await; + let env = Started::new(&configuration::ephemeral().into()).await; let mut params = QueryBuilder::default().query().params(); @@ -257,17 +256,17 @@ mod for_all_config_modes { for invalid_value in invalid_values { params.set("uploaded", invalid_value); - let response = Client::new(*test_env.bind_address()).get(&format!("announce?{params}")).await; + let response = Client::new(*env.bind_address()).get(&format!("announce?{params}")).await; assert_bad_announce_request_error_response(response, "invalid param value").await; } - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_fail_when_the_peer_id_param_is_invalid() { - let test_env = running_test_environment(configuration::ephemeral()).await; + let env = Started::new(&configuration::ephemeral().into()).await; let mut params = QueryBuilder::default().query().params(); @@ -283,17 +282,17 @@ mod for_all_config_modes { for invalid_value in invalid_values { params.set("peer_id", invalid_value); - let response = Client::new(*test_env.bind_address()).get(&format!("announce?{params}")).await; + let response = Client::new(*env.bind_address()).get(&format!("announce?{params}")).await; assert_bad_announce_request_error_response(response, "invalid param value").await; } - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_fail_when_the_port_param_is_invalid() { - let test_env = running_test_environment(configuration::ephemeral()).await; + let env = Started::new(&configuration::ephemeral().into()).await; let mut params = QueryBuilder::default().query().params(); @@ -302,17 +301,17 @@ mod for_all_config_modes { for invalid_value in invalid_values { params.set("port", invalid_value); - let response = Client::new(*test_env.bind_address()).get(&format!("announce?{params}")).await; + let response = Client::new(*env.bind_address()).get(&format!("announce?{params}")).await; assert_bad_announce_request_error_response(response, "invalid param value").await; } - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_fail_when_the_left_param_is_invalid() { - let test_env = running_test_environment(configuration::ephemeral()).await; + let env = Started::new(&configuration::ephemeral().into()).await; let mut params = QueryBuilder::default().query().params(); @@ -321,17 +320,17 @@ mod for_all_config_modes { for invalid_value in invalid_values { params.set("left", invalid_value); - let response = Client::new(*test_env.bind_address()).get(&format!("announce?{params}")).await; + let response = Client::new(*env.bind_address()).get(&format!("announce?{params}")).await; assert_bad_announce_request_error_response(response, "invalid param value").await; } - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_fail_when_the_event_param_is_invalid() { - let test_env = running_test_environment(configuration::ephemeral()).await; + let env = Started::new(&configuration::ephemeral().into()).await; let mut params = QueryBuilder::default().query().params(); @@ -348,17 +347,17 @@ mod for_all_config_modes { for invalid_value in invalid_values { params.set("event", invalid_value); - let response = Client::new(*test_env.bind_address()).get(&format!("announce?{params}")).await; + let response = Client::new(*env.bind_address()).get(&format!("announce?{params}")).await; assert_bad_announce_request_error_response(response, "invalid param value").await; } - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_fail_when_the_compact_param_is_invalid() { - let test_env = running_test_environment(configuration::ephemeral()).await; + let env = Started::new(&configuration::ephemeral().into()).await; let mut params = QueryBuilder::default().query().params(); @@ -367,19 +366,19 @@ mod for_all_config_modes { for invalid_value in invalid_values { params.set("compact", invalid_value); - let response = Client::new(*test_env.bind_address()).get(&format!("announce?{params}")).await; + let response = Client::new(*env.bind_address()).get(&format!("announce?{params}")).await; assert_bad_announce_request_error_response(response, "invalid param value").await; } - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_return_no_peers_if_the_announced_peer_is_the_first_one() { - let test_env = running_test_environment(configuration::ephemeral_mode_public()).await; + let env = Started::new(&configuration::ephemeral_mode_public().into()).await; - let response = Client::new(*test_env.bind_address()) + let response = Client::new(*env.bind_address()) .announce( &QueryBuilder::default() .with_info_hash(&InfoHash::from_str("9c38422213e30bff212b30c360d26f9a02136422").unwrap()) @@ -387,7 +386,7 @@ mod for_all_config_modes { ) .await; - let announce_policy = test_env.tracker.get_announce_policy(); + let announce_policy = env.tracker.get_announce_policy(); assert_announce_response( response, @@ -401,12 +400,12 @@ mod for_all_config_modes { ) .await; - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_return_the_list_of_previously_announced_peers() { - let test_env = running_test_environment(configuration::ephemeral_mode_public()).await; + let env = Started::new(&configuration::ephemeral_mode_public().into()).await; let info_hash = InfoHash::from_str("9c38422213e30bff212b30c360d26f9a02136422").unwrap(); @@ -416,10 +415,10 @@ mod for_all_config_modes { .build(); // Add the Peer 1 - test_env.add_torrent_peer(&info_hash, &previously_announced_peer).await; + env.add_torrent_peer(&info_hash, &previously_announced_peer).await; // Announce the new Peer 2. This new peer is non included on the response peer list - let response = Client::new(*test_env.bind_address()) + let response = Client::new(*env.bind_address()) .announce( &QueryBuilder::default() .with_info_hash(&info_hash) @@ -428,7 +427,7 @@ mod for_all_config_modes { ) .await; - let announce_policy = test_env.tracker.get_announce_policy(); + let announce_policy = env.tracker.get_announce_policy(); // It should only contain the previously announced peer assert_announce_response( @@ -443,12 +442,12 @@ mod for_all_config_modes { ) .await; - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_return_the_list_of_previously_announced_peers_including_peers_using_ipv4_and_ipv6() { - let test_env = running_test_environment(configuration::ephemeral_mode_public()).await; + let env = Started::new(&configuration::ephemeral_mode_public().into()).await; let info_hash = InfoHash::from_str("9c38422213e30bff212b30c360d26f9a02136422").unwrap(); @@ -457,7 +456,7 @@ mod for_all_config_modes { .with_peer_id(&peer::Id(*b"-qB00000000000000001")) .with_peer_addr(&SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0x69, 0x69, 0x69, 0x69)), 8080)) .build(); - test_env.add_torrent_peer(&info_hash, &peer_using_ipv4).await; + env.add_torrent_peer(&info_hash, &peer_using_ipv4).await; // Announce a peer using IPV6 let peer_using_ipv6 = PeerBuilder::default() @@ -467,10 +466,10 @@ mod for_all_config_modes { 8080, )) .build(); - test_env.add_torrent_peer(&info_hash, &peer_using_ipv6).await; + env.add_torrent_peer(&info_hash, &peer_using_ipv6).await; // Announce the new Peer. - let response = Client::new(*test_env.bind_address()) + let response = Client::new(*env.bind_address()) .announce( &QueryBuilder::default() .with_info_hash(&info_hash) @@ -479,7 +478,7 @@ mod for_all_config_modes { ) .await; - let announce_policy = test_env.tracker.get_announce_policy(); + let announce_policy = env.tracker.get_announce_policy(); // The newly announced peer is not included on the response peer list, // but all the previously announced peers should be included regardless the IP version they are using. @@ -495,18 +494,18 @@ mod for_all_config_modes { ) .await; - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_consider_two_peers_to_be_the_same_when_they_have_the_same_peer_id_even_if_the_ip_is_different() { - let test_env = running_test_environment(configuration::ephemeral_mode_public()).await; + let env = Started::new(&configuration::ephemeral_mode_public().into()).await; let info_hash = InfoHash::from_str("9c38422213e30bff212b30c360d26f9a02136422").unwrap(); let peer = PeerBuilder::default().build(); // Add a peer - test_env.add_torrent_peer(&info_hash, &peer).await; + env.add_torrent_peer(&info_hash, &peer).await; let announce_query = QueryBuilder::default() .with_info_hash(&info_hash) @@ -515,11 +514,11 @@ mod for_all_config_modes { assert_ne!(peer.peer_addr.ip(), announce_query.peer_addr); - let response = Client::new(*test_env.bind_address()).announce(&announce_query).await; + let response = Client::new(*env.bind_address()).announce(&announce_query).await; assert_empty_announce_response(response).await; - test_env.stop().await; + env.stop().await; } #[tokio::test] @@ -527,7 +526,7 @@ mod for_all_config_modes { // Tracker Returns Compact Peer Lists // https://www.bittorrent.org/beps/bep_0023.html - let test_env = running_test_environment(configuration::ephemeral_mode_public()).await; + let env = Started::new(&configuration::ephemeral_mode_public().into()).await; let info_hash = InfoHash::from_str("9c38422213e30bff212b30c360d26f9a02136422").unwrap(); @@ -537,10 +536,10 @@ mod for_all_config_modes { .build(); // Add the Peer 1 - test_env.add_torrent_peer(&info_hash, &previously_announced_peer).await; + env.add_torrent_peer(&info_hash, &previously_announced_peer).await; // Announce the new Peer 2 accepting compact responses - let response = Client::new(*test_env.bind_address()) + let response = Client::new(*env.bind_address()) .announce( &QueryBuilder::default() .with_info_hash(&info_hash) @@ -560,7 +559,7 @@ mod for_all_config_modes { assert_compact_announce_response(response, &expected_response).await; - test_env.stop().await; + env.stop().await; } #[tokio::test] @@ -568,7 +567,7 @@ mod for_all_config_modes { // code-review: the HTTP tracker does not return the compact response by default if the "compact" // param is not provided in the announce URL. The BEP 23 suggest to do so. - let test_env = running_test_environment(configuration::ephemeral_mode_public()).await; + let env = Started::new(&configuration::ephemeral_mode_public().into()).await; let info_hash = InfoHash::from_str("9c38422213e30bff212b30c360d26f9a02136422").unwrap(); @@ -578,12 +577,12 @@ mod for_all_config_modes { .build(); // Add the Peer 1 - test_env.add_torrent_peer(&info_hash, &previously_announced_peer).await; + env.add_torrent_peer(&info_hash, &previously_announced_peer).await; // Announce the new Peer 2 without passing the "compact" param // By default it should respond with the compact peer list // https://www.bittorrent.org/beps/bep_0023.html - let response = Client::new(*test_env.bind_address()) + let response = Client::new(*env.bind_address()) .announce( &QueryBuilder::default() .with_info_hash(&info_hash) @@ -595,7 +594,7 @@ mod for_all_config_modes { assert!(!is_a_compact_announce_response(response).await); - test_env.stop().await; + env.stop().await; } async fn is_a_compact_announce_response(response: Response) -> bool { @@ -606,19 +605,19 @@ mod for_all_config_modes { #[tokio::test] async fn should_increase_the_number_of_tcp4_connections_handled_in_statistics() { - let test_env = running_test_environment(configuration::ephemeral_mode_public()).await; + let env = Started::new(&configuration::ephemeral_mode_public().into()).await; - Client::new(*test_env.bind_address()) + Client::new(*env.bind_address()) .announce(&QueryBuilder::default().query()) .await; - let stats = test_env.tracker.get_stats().await; + let stats = env.tracker.get_stats().await; assert_eq!(stats.tcp4_connections_handled, 1); drop(stats); - test_env.stop().await; + env.stop().await; } #[tokio::test] @@ -630,28 +629,28 @@ mod for_all_config_modes { return; // we cannot bind to a ipv6 socket, so we will skip this test } - let test_env = running_test_environment(configuration::ephemeral_ipv6()).await; + let env = Started::new(&configuration::ephemeral_ipv6().into()).await; - Client::bind(*test_env.bind_address(), IpAddr::from_str("::1").unwrap()) + Client::bind(*env.bind_address(), IpAddr::from_str("::1").unwrap()) .announce(&QueryBuilder::default().query()) .await; - let stats = test_env.tracker.get_stats().await; + let stats = env.tracker.get_stats().await; assert_eq!(stats.tcp6_connections_handled, 1); drop(stats); - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_not_increase_the_number_of_tcp6_connections_handled_if_the_client_is_not_using_an_ipv6_ip() { // The tracker ignores the peer address in the request param. It uses the client remote ip address. - let test_env = running_test_environment(configuration::ephemeral_mode_public()).await; + let env = Started::new(&configuration::ephemeral_mode_public().into()).await; - Client::new(*test_env.bind_address()) + Client::new(*env.bind_address()) .announce( &QueryBuilder::default() .with_peer_addr(&IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1))) @@ -659,30 +658,30 @@ mod for_all_config_modes { ) .await; - let stats = test_env.tracker.get_stats().await; + let stats = env.tracker.get_stats().await; assert_eq!(stats.tcp6_connections_handled, 0); drop(stats); - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_increase_the_number_of_tcp4_announce_requests_handled_in_statistics() { - let test_env = running_test_environment(configuration::ephemeral_mode_public()).await; + let env = Started::new(&configuration::ephemeral_mode_public().into()).await; - Client::new(*test_env.bind_address()) + Client::new(*env.bind_address()) .announce(&QueryBuilder::default().query()) .await; - let stats = test_env.tracker.get_stats().await; + let stats = env.tracker.get_stats().await; assert_eq!(stats.tcp4_announces_handled, 1); drop(stats); - test_env.stop().await; + env.stop().await; } #[tokio::test] @@ -694,28 +693,28 @@ mod for_all_config_modes { return; // we cannot bind to a ipv6 socket, so we will skip this test } - let test_env = running_test_environment(configuration::ephemeral_ipv6()).await; + let env = Started::new(&configuration::ephemeral_ipv6().into()).await; - Client::bind(*test_env.bind_address(), IpAddr::from_str("::1").unwrap()) + Client::bind(*env.bind_address(), IpAddr::from_str("::1").unwrap()) .announce(&QueryBuilder::default().query()) .await; - let stats = test_env.tracker.get_stats().await; + let stats = env.tracker.get_stats().await; assert_eq!(stats.tcp6_announces_handled, 1); drop(stats); - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_not_increase_the_number_of_tcp6_announce_requests_handled_if_the_client_is_not_using_an_ipv6_ip() { // The tracker ignores the peer address in the request param. It uses the client remote ip address. - let test_env = running_test_environment(configuration::ephemeral_mode_public()).await; + let env = Started::new(&configuration::ephemeral_mode_public().into()).await; - Client::new(*test_env.bind_address()) + Client::new(*env.bind_address()) .announce( &QueryBuilder::default() .with_peer_addr(&IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1))) @@ -723,18 +722,18 @@ mod for_all_config_modes { ) .await; - let stats = test_env.tracker.get_stats().await; + let stats = env.tracker.get_stats().await; assert_eq!(stats.tcp6_announces_handled, 0); drop(stats); - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_assign_to_the_peer_ip_the_remote_client_ip_instead_of_the_peer_address_in_the_request_param() { - let test_env = running_test_environment(configuration::ephemeral_mode_public()).await; + let env = Started::new(&configuration::ephemeral_mode_public().into()).await; let info_hash = InfoHash::from_str("9c38422213e30bff212b30c360d26f9a02136422").unwrap(); let client_ip = local_ip().unwrap(); @@ -745,19 +744,19 @@ mod for_all_config_modes { .query(); { - let client = Client::bind(*test_env.bind_address(), client_ip); + let client = Client::bind(*env.bind_address(), client_ip); let status = client.announce(&announce_query).await.status(); assert_eq!(status, StatusCode::OK); } - let peers = test_env.tracker.get_torrent_peers(&info_hash).await; + let peers = env.tracker.get_torrent_peers(&info_hash).await; let peer_addr = peers[0].peer_addr; assert_eq!(peer_addr.ip(), client_ip); assert_ne!(peer_addr.ip(), IpAddr::from_str("2.2.2.2").unwrap()); - test_env.stop().await; + env.stop().await; } #[tokio::test] @@ -768,11 +767,8 @@ mod for_all_config_modes { client <-> tracker <-> Internet 127.0.0.1 external_ip = "2.137.87.41" */ - - let test_env = running_test_environment(configuration::ephemeral_with_external_ip( - IpAddr::from_str("2.137.87.41").unwrap(), - )) - .await; + let env = + Started::new(&configuration::ephemeral_with_external_ip(IpAddr::from_str("2.137.87.41").unwrap()).into()).await; let info_hash = InfoHash::from_str("9c38422213e30bff212b30c360d26f9a02136422").unwrap(); let loopback_ip = IpAddr::from_str("127.0.0.1").unwrap(); @@ -784,19 +780,19 @@ mod for_all_config_modes { .query(); { - let client = Client::bind(*test_env.bind_address(), client_ip); + let client = Client::bind(*env.bind_address(), client_ip); let status = client.announce(&announce_query).await.status(); assert_eq!(status, StatusCode::OK); } - let peers = test_env.tracker.get_torrent_peers(&info_hash).await; + let peers = env.tracker.get_torrent_peers(&info_hash).await; let peer_addr = peers[0].peer_addr; - assert_eq!(peer_addr.ip(), test_env.tracker.get_maybe_external_ip().unwrap()); + assert_eq!(peer_addr.ip(), env.tracker.get_maybe_external_ip().unwrap()); assert_ne!(peer_addr.ip(), IpAddr::from_str("2.2.2.2").unwrap()); - test_env.stop().await; + env.stop().await; } #[tokio::test] @@ -808,9 +804,10 @@ mod for_all_config_modes { ::1 external_ip = "2345:0425:2CA1:0000:0000:0567:5673:23b5" */ - let test_env = running_test_environment(configuration::ephemeral_with_external_ip( - IpAddr::from_str("2345:0425:2CA1:0000:0000:0567:5673:23b5").unwrap(), - )) + let env = Started::new( + &configuration::ephemeral_with_external_ip(IpAddr::from_str("2345:0425:2CA1:0000:0000:0567:5673:23b5").unwrap()) + .into(), + ) .await; let info_hash = InfoHash::from_str("9c38422213e30bff212b30c360d26f9a02136422").unwrap(); @@ -823,19 +820,19 @@ mod for_all_config_modes { .query(); { - let client = Client::bind(*test_env.bind_address(), client_ip); + let client = Client::bind(*env.bind_address(), client_ip); let status = client.announce(&announce_query).await.status(); assert_eq!(status, StatusCode::OK); } - let peers = test_env.tracker.get_torrent_peers(&info_hash).await; + let peers = env.tracker.get_torrent_peers(&info_hash).await; let peer_addr = peers[0].peer_addr; - assert_eq!(peer_addr.ip(), test_env.tracker.get_maybe_external_ip().unwrap()); + assert_eq!(peer_addr.ip(), env.tracker.get_maybe_external_ip().unwrap()); assert_ne!(peer_addr.ip(), IpAddr::from_str("2.2.2.2").unwrap()); - test_env.stop().await; + env.stop().await; } #[tokio::test] @@ -847,14 +844,14 @@ mod for_all_config_modes { 145.254.214.256 X-Forwarded-For = 145.254.214.256 on_reverse_proxy = true 145.254.214.256 */ - let test_env = running_test_environment(configuration::ephemeral_with_reverse_proxy()).await; + let env = Started::new(&configuration::ephemeral_with_reverse_proxy().into()).await; let info_hash = InfoHash::from_str("9c38422213e30bff212b30c360d26f9a02136422").unwrap(); let announce_query = QueryBuilder::default().with_info_hash(&info_hash).query(); { - let client = Client::new(*test_env.bind_address()); + let client = Client::new(*env.bind_address()); let status = client .announce_with_header( &announce_query, @@ -867,12 +864,12 @@ mod for_all_config_modes { assert_eq!(status, StatusCode::OK); } - let peers = test_env.tracker.get_torrent_peers(&info_hash).await; + let peers = env.tracker.get_torrent_peers(&info_hash).await; let peer_addr = peers[0].peer_addr; assert_eq!(peer_addr.ip(), IpAddr::from_str("150.172.238.178").unwrap()); - test_env.stop().await; + env.stop().await; } } @@ -901,56 +898,54 @@ mod for_all_config_modes { assert_scrape_response, }; use crate::servers::http::client::Client; - use crate::servers::http::requests; use crate::servers::http::requests::scrape::QueryBuilder; use crate::servers::http::responses::scrape::{self, File, ResponseBuilder}; - use crate::servers::http::test_environment::running_test_environment; + use crate::servers::http::{requests, Started}; //#[tokio::test] #[allow(dead_code)] async fn should_fail_when_the_request_is_empty() { - let test_env = running_test_environment(configuration::ephemeral_mode_public()).await; - let response = Client::new(*test_env.bind_address()).get("scrape").await; + let env = Started::new(&configuration::ephemeral_mode_public().into()).await; + let response = Client::new(*env.bind_address()).get("scrape").await; assert_missing_query_params_for_scrape_request_error_response(response).await; - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_fail_when_the_info_hash_param_is_invalid() { - let test_env = running_test_environment(configuration::ephemeral_mode_public()).await; + let env = Started::new(&configuration::ephemeral_mode_public().into()).await; let mut params = QueryBuilder::default().query().params(); for invalid_value in &invalid_info_hashes() { params.set_one_info_hash_param(invalid_value); - let response = Client::new(*test_env.bind_address()).get(&format!("announce?{params}")).await; + let response = Client::new(*env.bind_address()).get(&format!("announce?{params}")).await; assert_cannot_parse_query_params_error_response(response, "").await; } - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_return_the_file_with_the_incomplete_peer_when_there_is_one_peer_with_bytes_pending_to_download() { - let test_env = running_test_environment(configuration::ephemeral_mode_public()).await; + let env = Started::new(&configuration::ephemeral_mode_public().into()).await; let info_hash = InfoHash::from_str("9c38422213e30bff212b30c360d26f9a02136422").unwrap(); - test_env - .add_torrent_peer( - &info_hash, - &PeerBuilder::default() - .with_peer_id(&peer::Id(*b"-qB00000000000000001")) - .with_bytes_pending_to_download(1) - .build(), - ) - .await; + env.add_torrent_peer( + &info_hash, + &PeerBuilder::default() + .with_peer_id(&peer::Id(*b"-qB00000000000000001")) + .with_bytes_pending_to_download(1) + .build(), + ) + .await; - let response = Client::new(*test_env.bind_address()) + let response = Client::new(*env.bind_address()) .scrape( &requests::scrape::QueryBuilder::default() .with_one_info_hash(&info_hash) @@ -971,26 +966,25 @@ mod for_all_config_modes { assert_scrape_response(response, &expected_scrape_response).await; - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_return_the_file_with_the_complete_peer_when_there_is_one_peer_with_no_bytes_pending_to_download() { - let test_env = running_test_environment(configuration::ephemeral_mode_public()).await; + let env = Started::new(&configuration::ephemeral_mode_public().into()).await; let info_hash = InfoHash::from_str("9c38422213e30bff212b30c360d26f9a02136422").unwrap(); - test_env - .add_torrent_peer( - &info_hash, - &PeerBuilder::default() - .with_peer_id(&peer::Id(*b"-qB00000000000000001")) - .with_no_bytes_pending_to_download() - .build(), - ) - .await; + env.add_torrent_peer( + &info_hash, + &PeerBuilder::default() + .with_peer_id(&peer::Id(*b"-qB00000000000000001")) + .with_no_bytes_pending_to_download() + .build(), + ) + .await; - let response = Client::new(*test_env.bind_address()) + let response = Client::new(*env.bind_address()) .scrape( &requests::scrape::QueryBuilder::default() .with_one_info_hash(&info_hash) @@ -1011,16 +1005,16 @@ mod for_all_config_modes { assert_scrape_response(response, &expected_scrape_response).await; - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_return_a_file_with_zeroed_values_when_there_are_no_peers() { - let test_env = running_test_environment(configuration::ephemeral_mode_public()).await; + let env = Started::new(&configuration::ephemeral_mode_public().into()).await; let info_hash = InfoHash::from_str("9c38422213e30bff212b30c360d26f9a02136422").unwrap(); - let response = Client::new(*test_env.bind_address()) + let response = Client::new(*env.bind_address()) .scrape( &requests::scrape::QueryBuilder::default() .with_one_info_hash(&info_hash) @@ -1030,17 +1024,17 @@ mod for_all_config_modes { assert_scrape_response(response, &scrape::Response::with_one_file(info_hash.bytes(), File::zeroed())).await; - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_accept_multiple_infohashes() { - let test_env = running_test_environment(configuration::ephemeral_mode_public()).await; + let env = Started::new(&configuration::ephemeral_mode_public().into()).await; let info_hash1 = InfoHash::from_str("9c38422213e30bff212b30c360d26f9a02136422").unwrap(); let info_hash2 = InfoHash::from_str("3b245504cf5f11bbdbe1201cea6a6bf45aee1bc0").unwrap(); - let response = Client::new(*test_env.bind_address()) + let response = Client::new(*env.bind_address()) .scrape( &requests::scrape::QueryBuilder::default() .add_info_hash(&info_hash1) @@ -1056,16 +1050,16 @@ mod for_all_config_modes { assert_scrape_response(response, &expected_scrape_response).await; - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_increase_the_number_ot_tcp4_scrape_requests_handled_in_statistics() { - let test_env = running_test_environment(configuration::ephemeral_mode_public()).await; + let env = Started::new(&configuration::ephemeral_mode_public().into()).await; let info_hash = InfoHash::from_str("9c38422213e30bff212b30c360d26f9a02136422").unwrap(); - Client::new(*test_env.bind_address()) + Client::new(*env.bind_address()) .scrape( &requests::scrape::QueryBuilder::default() .with_one_info_hash(&info_hash) @@ -1073,13 +1067,13 @@ mod for_all_config_modes { ) .await; - let stats = test_env.tracker.get_stats().await; + let stats = env.tracker.get_stats().await; assert_eq!(stats.tcp4_scrapes_handled, 1); drop(stats); - test_env.stop().await; + env.stop().await; } #[tokio::test] @@ -1091,11 +1085,11 @@ mod for_all_config_modes { return; // we cannot bind to a ipv6 socket, so we will skip this test } - let test_env = running_test_environment(configuration::ephemeral_ipv6()).await; + let env = Started::new(&configuration::ephemeral_ipv6().into()).await; let info_hash = InfoHash::from_str("9c38422213e30bff212b30c360d26f9a02136422").unwrap(); - Client::bind(*test_env.bind_address(), IpAddr::from_str("::1").unwrap()) + Client::bind(*env.bind_address(), IpAddr::from_str("::1").unwrap()) .scrape( &requests::scrape::QueryBuilder::default() .with_one_info_hash(&info_hash) @@ -1103,13 +1097,13 @@ mod for_all_config_modes { ) .await; - let stats = test_env.tracker.get_stats().await; + let stats = env.tracker.get_stats().await; assert_eq!(stats.tcp6_scrapes_handled, 1); drop(stats); - test_env.stop().await; + env.stop().await; } } } @@ -1125,42 +1119,41 @@ mod configured_as_whitelisted { use crate::servers::http::asserts::{assert_is_announce_response, assert_torrent_not_in_whitelist_error_response}; use crate::servers::http::client::Client; use crate::servers::http::requests::announce::QueryBuilder; - use crate::servers::http::test_environment::running_test_environment; + use crate::servers::http::Started; #[tokio::test] async fn should_fail_if_the_torrent_is_not_in_the_whitelist() { - let test_env = running_test_environment(configuration::ephemeral_mode_whitelisted()).await; + let env = Started::new(&configuration::ephemeral_mode_whitelisted().into()).await; let info_hash = InfoHash::from_str("9c38422213e30bff212b30c360d26f9a02136422").unwrap(); - let response = Client::new(*test_env.bind_address()) + let response = Client::new(*env.bind_address()) .announce(&QueryBuilder::default().with_info_hash(&info_hash).query()) .await; assert_torrent_not_in_whitelist_error_response(response).await; - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_allow_announcing_a_whitelisted_torrent() { - let test_env = running_test_environment(configuration::ephemeral_mode_whitelisted()).await; + let env = Started::new(&configuration::ephemeral_mode_whitelisted().into()).await; let info_hash = InfoHash::from_str("9c38422213e30bff212b30c360d26f9a02136422").unwrap(); - test_env - .tracker + env.tracker .add_torrent_to_whitelist(&info_hash) .await .expect("should add the torrent to the whitelist"); - let response = Client::new(*test_env.bind_address()) + let response = Client::new(*env.bind_address()) .announce(&QueryBuilder::default().with_info_hash(&info_hash).query()) .await; assert_is_announce_response(response).await; - test_env.stop().await; + env.stop().await; } } @@ -1174,27 +1167,25 @@ mod configured_as_whitelisted { use crate::servers::http::asserts::assert_scrape_response; use crate::servers::http::client::Client; - use crate::servers::http::requests; use crate::servers::http::responses::scrape::{File, ResponseBuilder}; - use crate::servers::http::test_environment::running_test_environment; + use crate::servers::http::{requests, Started}; #[tokio::test] async fn should_return_the_zeroed_file_when_the_requested_file_is_not_whitelisted() { - let test_env = running_test_environment(configuration::ephemeral_mode_whitelisted()).await; + let env = Started::new(&configuration::ephemeral_mode_whitelisted().into()).await; let info_hash = InfoHash::from_str("9c38422213e30bff212b30c360d26f9a02136422").unwrap(); - test_env - .add_torrent_peer( - &info_hash, - &PeerBuilder::default() - .with_peer_id(&peer::Id(*b"-qB00000000000000001")) - .with_bytes_pending_to_download(1) - .build(), - ) - .await; + env.add_torrent_peer( + &info_hash, + &PeerBuilder::default() + .with_peer_id(&peer::Id(*b"-qB00000000000000001")) + .with_bytes_pending_to_download(1) + .build(), + ) + .await; - let response = Client::new(*test_env.bind_address()) + let response = Client::new(*env.bind_address()) .scrape( &requests::scrape::QueryBuilder::default() .with_one_info_hash(&info_hash) @@ -1206,32 +1197,30 @@ mod configured_as_whitelisted { assert_scrape_response(response, &expected_scrape_response).await; - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_return_the_file_stats_when_the_requested_file_is_whitelisted() { - let test_env = running_test_environment(configuration::ephemeral_mode_whitelisted()).await; + let env = Started::new(&configuration::ephemeral_mode_whitelisted().into()).await; let info_hash = InfoHash::from_str("9c38422213e30bff212b30c360d26f9a02136422").unwrap(); - test_env - .add_torrent_peer( - &info_hash, - &PeerBuilder::default() - .with_peer_id(&peer::Id(*b"-qB00000000000000001")) - .with_bytes_pending_to_download(1) - .build(), - ) - .await; + env.add_torrent_peer( + &info_hash, + &PeerBuilder::default() + .with_peer_id(&peer::Id(*b"-qB00000000000000001")) + .with_bytes_pending_to_download(1) + .build(), + ) + .await; - test_env - .tracker + env.tracker .add_torrent_to_whitelist(&info_hash) .await .expect("should add the torrent to the whitelist"); - let response = Client::new(*test_env.bind_address()) + let response = Client::new(*env.bind_address()) .scrape( &requests::scrape::QueryBuilder::default() .with_one_info_hash(&info_hash) @@ -1252,7 +1241,7 @@ mod configured_as_whitelisted { assert_scrape_response(response, &expected_scrape_response).await; - test_env.stop().await; + env.stop().await; } } } @@ -1270,45 +1259,45 @@ mod configured_as_private { use crate::servers::http::asserts::{assert_authentication_error_response, assert_is_announce_response}; use crate::servers::http::client::Client; use crate::servers::http::requests::announce::QueryBuilder; - use crate::servers::http::test_environment::running_test_environment; + use crate::servers::http::Started; #[tokio::test] async fn should_respond_to_authenticated_peers() { - let test_env = running_test_environment(configuration::ephemeral_mode_private()).await; + let env = Started::new(&configuration::ephemeral_mode_private().into()).await; - let expiring_key = test_env.tracker.generate_auth_key(Duration::from_secs(60)).await.unwrap(); + let expiring_key = env.tracker.generate_auth_key(Duration::from_secs(60)).await.unwrap(); - let response = Client::authenticated(*test_env.bind_address(), expiring_key.key()) + let response = Client::authenticated(*env.bind_address(), expiring_key.key()) .announce(&QueryBuilder::default().query()) .await; assert_is_announce_response(response).await; - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_fail_if_the_peer_has_not_provided_the_authentication_key() { - let test_env = running_test_environment(configuration::ephemeral_mode_private()).await; + let env = Started::new(&configuration::ephemeral_mode_private().into()).await; let info_hash = InfoHash::from_str("9c38422213e30bff212b30c360d26f9a02136422").unwrap(); - let response = Client::new(*test_env.bind_address()) + let response = Client::new(*env.bind_address()) .announce(&QueryBuilder::default().with_info_hash(&info_hash).query()) .await; assert_authentication_error_response(response).await; - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_fail_if_the_key_query_param_cannot_be_parsed() { - let test_env = running_test_environment(configuration::ephemeral_mode_private()).await; + let env = Started::new(&configuration::ephemeral_mode_private().into()).await; let invalid_key = "INVALID_KEY"; - let response = Client::new(*test_env.bind_address()) + let response = Client::new(*env.bind_address()) .get(&format!( "announce/{invalid_key}?info_hash=%81%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00&peer_addr=2.137.87.41&downloaded=0&uploaded=0&peer_id=-qB00000000000000001&port=17548&left=0&event=completed&compact=0" )) @@ -1319,18 +1308,18 @@ mod configured_as_private { #[tokio::test] async fn should_fail_if_the_peer_cannot_be_authenticated_with_the_provided_key() { - let test_env = running_test_environment(configuration::ephemeral_mode_private()).await; + let env = Started::new(&configuration::ephemeral_mode_private().into()).await; // The tracker does not have this key let unregistered_key = Key::from_str("YZSl4lMZupRuOpSRC3krIKR5BPB14nrJ").unwrap(); - let response = Client::authenticated(*test_env.bind_address(), unregistered_key) + let response = Client::authenticated(*env.bind_address(), unregistered_key) .announce(&QueryBuilder::default().query()) .await; assert_authentication_error_response(response).await; - test_env.stop().await; + env.stop().await; } } @@ -1347,17 +1336,16 @@ mod configured_as_private { use crate::servers::http::asserts::{assert_authentication_error_response, assert_scrape_response}; use crate::servers::http::client::Client; - use crate::servers::http::requests; use crate::servers::http::responses::scrape::{File, ResponseBuilder}; - use crate::servers::http::test_environment::running_test_environment; + use crate::servers::http::{requests, Started}; #[tokio::test] async fn should_fail_if_the_key_query_param_cannot_be_parsed() { - let test_env = running_test_environment(configuration::ephemeral_mode_private()).await; + let env = Started::new(&configuration::ephemeral_mode_private().into()).await; let invalid_key = "INVALID_KEY"; - let response = Client::new(*test_env.bind_address()) + let response = Client::new(*env.bind_address()) .get(&format!( "scrape/{invalid_key}?info_hash=%3B%24U%04%CF%5F%11%BB%DB%E1%20%1C%EAjk%F4Z%EE%1B%C0" )) @@ -1368,21 +1356,20 @@ mod configured_as_private { #[tokio::test] async fn should_return_the_zeroed_file_when_the_client_is_not_authenticated() { - let test_env = running_test_environment(configuration::ephemeral_mode_private()).await; + let env = Started::new(&configuration::ephemeral_mode_private().into()).await; let info_hash = InfoHash::from_str("9c38422213e30bff212b30c360d26f9a02136422").unwrap(); - test_env - .add_torrent_peer( - &info_hash, - &PeerBuilder::default() - .with_peer_id(&peer::Id(*b"-qB00000000000000001")) - .with_bytes_pending_to_download(1) - .build(), - ) - .await; + env.add_torrent_peer( + &info_hash, + &PeerBuilder::default() + .with_peer_id(&peer::Id(*b"-qB00000000000000001")) + .with_bytes_pending_to_download(1) + .build(), + ) + .await; - let response = Client::new(*test_env.bind_address()) + let response = Client::new(*env.bind_address()) .scrape( &requests::scrape::QueryBuilder::default() .with_one_info_hash(&info_hash) @@ -1394,28 +1381,27 @@ mod configured_as_private { assert_scrape_response(response, &expected_scrape_response).await; - test_env.stop().await; + env.stop().await; } #[tokio::test] async fn should_return_the_real_file_stats_when_the_client_is_authenticated() { - let test_env = running_test_environment(configuration::ephemeral_mode_private()).await; + let env = Started::new(&configuration::ephemeral_mode_private().into()).await; let info_hash = InfoHash::from_str("9c38422213e30bff212b30c360d26f9a02136422").unwrap(); - test_env - .add_torrent_peer( - &info_hash, - &PeerBuilder::default() - .with_peer_id(&peer::Id(*b"-qB00000000000000001")) - .with_bytes_pending_to_download(1) - .build(), - ) - .await; + env.add_torrent_peer( + &info_hash, + &PeerBuilder::default() + .with_peer_id(&peer::Id(*b"-qB00000000000000001")) + .with_bytes_pending_to_download(1) + .build(), + ) + .await; - let expiring_key = test_env.tracker.generate_auth_key(Duration::from_secs(60)).await.unwrap(); + let expiring_key = env.tracker.generate_auth_key(Duration::from_secs(60)).await.unwrap(); - let response = Client::authenticated(*test_env.bind_address(), expiring_key.key()) + let response = Client::authenticated(*env.bind_address(), expiring_key.key()) .scrape( &requests::scrape::QueryBuilder::default() .with_one_info_hash(&info_hash) @@ -1436,7 +1422,7 @@ mod configured_as_private { assert_scrape_response(response, &expected_scrape_response).await; - test_env.stop().await; + env.stop().await; } #[tokio::test] @@ -1444,23 +1430,22 @@ mod configured_as_private { // There is not authentication error // code-review: should this really be this way? - let test_env = running_test_environment(configuration::ephemeral_mode_private()).await; + let env = Started::new(&configuration::ephemeral_mode_private().into()).await; let info_hash = InfoHash::from_str("9c38422213e30bff212b30c360d26f9a02136422").unwrap(); - test_env - .add_torrent_peer( - &info_hash, - &PeerBuilder::default() - .with_peer_id(&peer::Id(*b"-qB00000000000000001")) - .with_bytes_pending_to_download(1) - .build(), - ) - .await; + env.add_torrent_peer( + &info_hash, + &PeerBuilder::default() + .with_peer_id(&peer::Id(*b"-qB00000000000000001")) + .with_bytes_pending_to_download(1) + .build(), + ) + .await; let false_key: Key = "YZSl4lMZupRuOpSRC3krIKR5BPB14nrJ".parse().unwrap(); - let response = Client::authenticated(*test_env.bind_address(), false_key) + let response = Client::authenticated(*env.bind_address(), false_key) .scrape( &requests::scrape::QueryBuilder::default() .with_one_info_hash(&info_hash) @@ -1472,7 +1457,7 @@ mod configured_as_private { assert_scrape_response(response, &expected_scrape_response).await; - test_env.stop().await; + env.stop().await; } } } diff --git a/tests/servers/udp/contract.rs b/tests/servers/udp/contract.rs index b16a47cd..9ac58519 100644 --- a/tests/servers/udp/contract.rs +++ b/tests/servers/udp/contract.rs @@ -11,7 +11,7 @@ use torrust_tracker::shared::bit_torrent::tracker::udp::MAX_PACKET_SIZE; use torrust_tracker_test_helpers::configuration; use crate::servers::udp::asserts::is_error_response; -use crate::servers::udp::test_environment::running_test_environment; +use crate::servers::udp::Started; fn empty_udp_request() -> [u8; MAX_PACKET_SIZE] { [0; MAX_PACKET_SIZE] @@ -36,9 +36,9 @@ async fn send_connection_request(transaction_id: TransactionId, client: &UdpTrac #[tokio::test] async fn should_return_a_bad_request_response_when_the_client_sends_an_empty_request() { - let test_env = running_test_environment(configuration::ephemeral()).await; + let env = Started::new(&configuration::ephemeral().into()).await; - let client = new_udp_client_connected(&test_env.bind_address().to_string()).await; + let client = new_udp_client_connected(&env.bind_address().to_string()).await; client.send(&empty_udp_request()).await; @@ -55,13 +55,13 @@ mod receiving_a_connection_request { use torrust_tracker_test_helpers::configuration; use crate::servers::udp::asserts::is_connect_response; - use crate::servers::udp::test_environment::running_test_environment; + use crate::servers::udp::Started; #[tokio::test] async fn should_return_a_connect_response() { - let test_env = running_test_environment(configuration::ephemeral()).await; + let env = Started::new(&configuration::ephemeral().into()).await; - let client = new_udp_tracker_client_connected(&test_env.bind_address().to_string()).await; + let client = new_udp_tracker_client_connected(&env.bind_address().to_string()).await; let connect_request = ConnectRequest { transaction_id: TransactionId(123), @@ -87,13 +87,13 @@ mod receiving_an_announce_request { use crate::servers::udp::asserts::is_ipv4_announce_response; use crate::servers::udp::contract::send_connection_request; - use crate::servers::udp::test_environment::running_test_environment; + use crate::servers::udp::Started; #[tokio::test] async fn should_return_an_announce_response() { - let test_env = running_test_environment(configuration::ephemeral()).await; + let env = Started::new(&configuration::ephemeral().into()).await; - let client = new_udp_tracker_client_connected(&test_env.bind_address().to_string()).await; + let client = new_udp_tracker_client_connected(&env.bind_address().to_string()).await; let connection_id = send_connection_request(TransactionId(123), &client).await; @@ -129,13 +129,13 @@ mod receiving_an_scrape_request { use crate::servers::udp::asserts::is_scrape_response; use crate::servers::udp::contract::send_connection_request; - use crate::servers::udp::test_environment::running_test_environment; + use crate::servers::udp::Started; #[tokio::test] async fn should_return_a_scrape_response() { - let test_env = running_test_environment(configuration::ephemeral()).await; + let env = Started::new(&configuration::ephemeral().into()).await; - let client = new_udp_tracker_client_connected(&test_env.bind_address().to_string()).await; + let client = new_udp_tracker_client_connected(&env.bind_address().to_string()).await; let connection_id = send_connection_request(TransactionId(123), &client).await; diff --git a/tests/servers/udp/environment.rs b/tests/servers/udp/environment.rs new file mode 100644 index 00000000..26a47987 --- /dev/null +++ b/tests/servers/udp/environment.rs @@ -0,0 +1,78 @@ +use std::net::SocketAddr; +use std::sync::Arc; + +use torrust_tracker::bootstrap::app::initialize_with_configuration; +use torrust_tracker::core::peer::Peer; +use torrust_tracker::core::Tracker; +use torrust_tracker::servers::registar::Registar; +use torrust_tracker::servers::udp::server::{Launcher, Running, Stopped, UdpServer}; +use torrust_tracker::shared::bit_torrent::info_hash::InfoHash; +use torrust_tracker_configuration::{Configuration, UdpTracker}; + +pub struct Environment { + pub config: Arc, + pub tracker: Arc, + pub registar: Registar, + pub server: UdpServer, +} + +impl Environment { + /// Add a torrent to the tracker + #[allow(dead_code)] + pub async fn add_torrent(&self, info_hash: &InfoHash, peer: &Peer) { + self.tracker.update_torrent_with_peer_and_get_stats(info_hash, peer).await; + } +} + +impl Environment { + #[allow(dead_code)] + pub fn new(configuration: &Arc) -> Self { + let tracker = initialize_with_configuration(configuration); + + let config = Arc::new(configuration.udp_trackers[0].clone()); + + let bind_to = config + .bind_address + .parse::() + .expect("Tracker API bind_address invalid."); + + let server = UdpServer::new(Launcher::new(bind_to)); + + Self { + config, + tracker, + registar: Registar::default(), + server, + } + } + + #[allow(dead_code)] + pub async fn start(self) -> Environment { + Environment { + config: self.config, + tracker: self.tracker.clone(), + registar: self.registar.clone(), + server: self.server.start(self.tracker, self.registar.give_form()).await.unwrap(), + } + } +} + +impl Environment { + pub async fn new(configuration: &Arc) -> Self { + Environment::::new(configuration).start().await + } + + #[allow(dead_code)] + pub async fn stop(self) -> Environment { + Environment { + config: self.config, + tracker: self.tracker, + registar: Registar::default(), + server: self.server.stop().await.unwrap(), + } + } + + pub fn bind_address(&self) -> SocketAddr { + self.server.state.binding + } +} diff --git a/tests/servers/udp/mod.rs b/tests/servers/udp/mod.rs index 4759350d..b13b8224 100644 --- a/tests/servers/udp/mod.rs +++ b/tests/servers/udp/mod.rs @@ -1,3 +1,7 @@ +use torrust_tracker::servers::udp::server; + pub mod asserts; pub mod contract; -pub mod test_environment; +pub mod environment; + +pub type Started = environment::Environment; diff --git a/tests/servers/udp/test_environment.rs b/tests/servers/udp/test_environment.rs deleted file mode 100644 index f272b6dd..00000000 --- a/tests/servers/udp/test_environment.rs +++ /dev/null @@ -1,110 +0,0 @@ -use std::net::SocketAddr; -use std::sync::Arc; - -use torrust_tracker::core::peer::Peer; -use torrust_tracker::core::Tracker; -use torrust_tracker::servers::registar::Registar; -use torrust_tracker::servers::udp::server::{Launcher, RunningUdpServer, StoppedUdpServer, UdpServer}; -use torrust_tracker::shared::bit_torrent::info_hash::InfoHash; - -use crate::common::app::setup_with_configuration; - -#[allow(clippy::module_name_repetitions, dead_code)] -pub type StoppedTestEnvironment = TestEnvironment; -#[allow(clippy::module_name_repetitions)] -pub type RunningTestEnvironment = TestEnvironment; - -pub struct TestEnvironment { - pub cfg: Arc, - pub tracker: Arc, - pub state: S, -} - -#[allow(dead_code)] -pub struct Stopped { - udp_server: StoppedUdpServer, -} - -pub struct Running { - udp_server: RunningUdpServer, -} - -impl TestEnvironment { - /// Add a torrent to the tracker - #[allow(dead_code)] - pub async fn add_torrent(&self, info_hash: &InfoHash, peer: &Peer) { - self.tracker.update_torrent_with_peer_and_get_stats(info_hash, peer).await; - } -} - -impl TestEnvironment { - #[allow(dead_code)] - pub fn new_stopped(cfg: torrust_tracker_configuration::Configuration) -> Self { - let cfg = Arc::new(cfg); - - let tracker = setup_with_configuration(&cfg); - - let udp_cfg = cfg.udp_trackers[0].clone(); - - let bind_to = udp_cfg - .bind_address - .parse::() - .expect("Tracker API bind_address invalid."); - - let udp_server = udp_server(Launcher::new(bind_to)); - - Self { - cfg, - tracker, - state: Stopped { udp_server }, - } - } - - #[allow(dead_code)] - pub async fn start(self) -> TestEnvironment { - let register = &Registar::default(); - - TestEnvironment { - cfg: self.cfg, - tracker: self.tracker.clone(), - state: Running { - udp_server: self.state.udp_server.start(self.tracker, register.give_form()).await.unwrap(), - }, - } - } -} - -impl TestEnvironment { - pub async fn new_running(cfg: torrust_tracker_configuration::Configuration) -> Self { - StoppedTestEnvironment::new_stopped(cfg).start().await - } - - #[allow(dead_code)] - pub async fn stop(self) -> TestEnvironment { - TestEnvironment { - cfg: self.cfg, - tracker: self.tracker, - state: Stopped { - udp_server: self.state.udp_server.stop().await.unwrap(), - }, - } - } - - pub fn bind_address(&self) -> SocketAddr { - self.state.udp_server.state.binding - } -} - -#[allow(clippy::module_name_repetitions, dead_code)] -pub fn stopped_test_environment(cfg: torrust_tracker_configuration::Configuration) -> StoppedTestEnvironment { - TestEnvironment::new_stopped(cfg) -} - -#[allow(clippy::module_name_repetitions)] -pub async fn running_test_environment(cfg: torrust_tracker_configuration::Configuration) -> RunningTestEnvironment { - TestEnvironment::new_running(cfg).await -} - -pub fn udp_server(launcher: Launcher) -> StoppedUdpServer { - UdpServer::new(launcher) -}