diff --git a/packages/tracker-core/src/core_tests.rs b/packages/tracker-core/src/core_tests.rs index f6b47acd0..ac99770d4 100644 --- a/packages/tracker-core/src/core_tests.rs +++ b/packages/tracker-core/src/core_tests.rs @@ -5,8 +5,12 @@ use std::sync::Arc; use aquatic_udp_protocol::{AnnounceEvent, NumberOfBytes, PeerId}; use bittorrent_primitives::info_hash::InfoHash; use torrust_tracker_configuration::Configuration; +#[cfg(test)] +use torrust_tracker_configuration::Core; use torrust_tracker_primitives::peer::Peer; use torrust_tracker_primitives::DurationSinceUnixEpoch; +#[cfg(test)] +use torrust_tracker_test_helpers::configuration::ephemeral_sqlite_database; use super::announce_handler::AnnounceHandler; use super::databases::setup::initialize_database; @@ -103,3 +107,20 @@ pub fn initialize_handlers(config: &Configuration) -> (Arc, Arc (announce_handler, scrape_handler) } + +/// # Panics +/// +/// Will panic if the temporary file path is not a valid UFT string. +#[cfg(test)] +#[must_use] +pub fn ephemeral_configuration_for_listed_tracker() -> Core { + let mut config = Core { + listed: true, + ..Default::default() + }; + + let temp_file = ephemeral_sqlite_database(); + temp_file.to_str().unwrap().clone_into(&mut config.database.path); + + config +} diff --git a/packages/tracker-core/src/whitelist/authorization.rs b/packages/tracker-core/src/whitelist/authorization.rs index 285f6613e..cb5f4acbf 100644 --- a/packages/tracker-core/src/whitelist/authorization.rs +++ b/packages/tracker-core/src/whitelist/authorization.rs @@ -61,33 +61,107 @@ impl WhitelistAuthorization { #[cfg(test)] mod tests { - mod configured_as_whitelisted { + mod the_whitelist_authorization_for_announce_and_scrape_actions { + use std::sync::Arc; + + use torrust_tracker_configuration::Core; + + use crate::whitelist::authorization::WhitelistAuthorization; + use crate::whitelist::repository::in_memory::InMemoryWhitelist; + + fn initialize_whitelist_authorization_with(config: &Core) -> Arc { + let (whitelist_authorization, _in_memory_whitelist) = + initialize_whitelist_authorization_and_dependencies_with(config); + whitelist_authorization + } + + fn initialize_whitelist_authorization_and_dependencies_with( + config: &Core, + ) -> (Arc, Arc) { + let in_memory_whitelist = Arc::new(InMemoryWhitelist::default()); + let whitelist_authorization = Arc::new(WhitelistAuthorization::new(config, &in_memory_whitelist.clone())); + + (whitelist_authorization, in_memory_whitelist) + } + + mod when_the_tacker_is_configured_as_listed { + + use torrust_tracker_configuration::Core; - mod handling_authorization { use crate::core_tests::sample_info_hash; - use crate::whitelist::whitelist_tests::initialize_whitelist_services_for_listed_tracker; + use crate::error::Error; + use crate::whitelist::authorization::tests::the_whitelist_authorization_for_announce_and_scrape_actions::{ + initialize_whitelist_authorization_and_dependencies_with, initialize_whitelist_authorization_with, + }; + + fn configuration_for_listed_tracker() -> Core { + Core { + listed: true, + ..Default::default() + } + } #[tokio::test] - async fn it_should_authorize_the_announce_and_scrape_actions_on_whitelisted_torrents() { - let (whitelist_authorization, whitelist_manager) = initialize_whitelist_services_for_listed_tracker(); + async fn should_authorize_a_whitelisted_infohash() { + let (whitelist_authorization, in_memory_whitelist) = + initialize_whitelist_authorization_and_dependencies_with(&configuration_for_listed_tracker()); let info_hash = sample_info_hash(); - let result = whitelist_manager.add_torrent_to_whitelist(&info_hash).await; - assert!(result.is_ok()); + let _unused = in_memory_whitelist.add(&info_hash).await; let result = whitelist_authorization.authorize(&info_hash).await; + assert!(result.is_ok()); } #[tokio::test] - async fn it_should_not_authorize_the_announce_and_scrape_actions_on_not_whitelisted_torrents() { - let (whitelist_authorization, _whitelist_manager) = initialize_whitelist_services_for_listed_tracker(); + async fn should_not_authorize_a_non_whitelisted_infohash() { + let whitelist_authorization = initialize_whitelist_authorization_with(&configuration_for_listed_tracker()); + + let result = whitelist_authorization.authorize(&sample_info_hash()).await; + + assert!(matches!(result.unwrap_err(), Error::TorrentNotWhitelisted { .. })); + } + } + + mod when_the_tacker_is_not_configured_as_listed { + + use torrust_tracker_configuration::Core; + + use crate::core_tests::sample_info_hash; + use crate::whitelist::authorization::tests::the_whitelist_authorization_for_announce_and_scrape_actions::{ + initialize_whitelist_authorization_and_dependencies_with, initialize_whitelist_authorization_with, + }; + + fn configuration_for_non_listed_tracker() -> Core { + Core { + listed: false, + ..Default::default() + } + } + + #[tokio::test] + async fn should_authorize_a_whitelisted_infohash() { + let (whitelist_authorization, in_memory_whitelist) = + initialize_whitelist_authorization_and_dependencies_with(&configuration_for_non_listed_tracker()); let info_hash = sample_info_hash(); + let _unused = in_memory_whitelist.add(&info_hash).await; + let result = whitelist_authorization.authorize(&info_hash).await; - assert!(result.is_err()); + + assert!(result.is_ok()); + } + + #[tokio::test] + async fn should_also_authorize_a_non_whitelisted_infohash() { + let whitelist_authorization = initialize_whitelist_authorization_with(&configuration_for_non_listed_tracker()); + + let result = whitelist_authorization.authorize(&sample_info_hash()).await; + + assert!(result.is_ok()); } } } diff --git a/packages/tracker-core/src/whitelist/manager.rs b/packages/tracker-core/src/whitelist/manager.rs index c78a59470..e1cd2f89e 100644 --- a/packages/tracker-core/src/whitelist/manager.rs +++ b/packages/tracker-core/src/whitelist/manager.rs @@ -48,30 +48,6 @@ impl WhitelistManager { Ok(()) } - /// It removes a torrent from the whitelist in the database. - /// - /// # Errors - /// - /// Will return a `database::Error` if unable to remove the `info_hash` from the whitelist database. - pub fn remove_torrent_from_database_whitelist(&self, info_hash: &InfoHash) -> Result<(), databases::error::Error> { - self.database_whitelist.remove(info_hash) - } - - /// It adds a torrent from the whitelist in memory. - pub async fn add_torrent_to_memory_whitelist(&self, info_hash: &InfoHash) -> bool { - self.in_memory_whitelist.add(info_hash).await - } - - /// It removes a torrent from the whitelist in memory. - pub async fn remove_torrent_from_memory_whitelist(&self, info_hash: &InfoHash) -> bool { - self.in_memory_whitelist.remove(info_hash).await - } - - /// It checks if a torrent is whitelisted. - pub async fn is_info_hash_whitelisted(&self, info_hash: &InfoHash) -> bool { - self.in_memory_whitelist.contains(info_hash).await - } - /// It loads the whitelist from the database. /// /// # Errors @@ -95,17 +71,41 @@ mod tests { use std::sync::Arc; - use torrust_tracker_test_helpers::configuration; + use torrust_tracker_configuration::Core; + use crate::core_tests::ephemeral_configuration_for_listed_tracker; + use crate::databases::setup::initialize_database; + use crate::databases::Database; use crate::whitelist::manager::WhitelistManager; - use crate::whitelist::whitelist_tests::initialize_whitelist_services; + use crate::whitelist::repository::in_memory::InMemoryWhitelist; + use crate::whitelist::repository::persisted::DatabaseWhitelist; - fn initialize_whitelist_manager_for_whitelisted_tracker() -> Arc { - let config = configuration::ephemeral_listed(); + struct WhitelistManagerDeps { + pub _database: Arc>, + pub database_whitelist: Arc, + pub in_memory_whitelist: Arc, + } - let (_whitelist_authorization, whitelist_manager) = initialize_whitelist_services(&config); + fn initialize_whitelist_manager_for_whitelisted_tracker() -> (Arc, Arc) { + let config = ephemeral_configuration_for_listed_tracker(); + initialize_whitelist_manager_and_deps(&config) + } - whitelist_manager + fn initialize_whitelist_manager_and_deps(config: &Core) -> (Arc, Arc) { + let database = initialize_database(config); + let database_whitelist = Arc::new(DatabaseWhitelist::new(database.clone())); + let in_memory_whitelist = Arc::new(InMemoryWhitelist::default()); + + let whitelist_manager = Arc::new(WhitelistManager::new(database_whitelist.clone(), in_memory_whitelist.clone())); + + ( + whitelist_manager, + Arc::new(WhitelistManagerDeps { + _database: database, + database_whitelist, + in_memory_whitelist, + }), + ) } mod configured_as_whitelisted { @@ -116,18 +116,19 @@ mod tests { #[tokio::test] async fn it_should_add_a_torrent_to_the_whitelist() { - let whitelist_manager = initialize_whitelist_manager_for_whitelisted_tracker(); + let (whitelist_manager, services) = initialize_whitelist_manager_for_whitelisted_tracker(); let info_hash = sample_info_hash(); whitelist_manager.add_torrent_to_whitelist(&info_hash).await.unwrap(); - assert!(whitelist_manager.is_info_hash_whitelisted(&info_hash).await); + assert!(services.in_memory_whitelist.contains(&info_hash).await); + assert!(services.database_whitelist.load_from_database().unwrap().contains(&info_hash)); } #[tokio::test] async fn it_should_remove_a_torrent_from_the_whitelist() { - let whitelist_manager = initialize_whitelist_manager_for_whitelisted_tracker(); + let (whitelist_manager, services) = initialize_whitelist_manager_for_whitelisted_tracker(); let info_hash = sample_info_hash(); @@ -135,7 +136,8 @@ mod tests { whitelist_manager.remove_torrent_from_whitelist(&info_hash).await.unwrap(); - assert!(!whitelist_manager.is_info_hash_whitelisted(&info_hash).await); + assert!(!services.in_memory_whitelist.contains(&info_hash).await); + assert!(!services.database_whitelist.load_from_database().unwrap().contains(&info_hash)); } mod persistence { @@ -144,19 +146,15 @@ mod tests { #[tokio::test] async fn it_should_load_the_whitelist_from_the_database() { - let whitelist_manager = initialize_whitelist_manager_for_whitelisted_tracker(); + let (whitelist_manager, services) = initialize_whitelist_manager_for_whitelisted_tracker(); let info_hash = sample_info_hash(); - whitelist_manager.add_torrent_to_whitelist(&info_hash).await.unwrap(); - - whitelist_manager.remove_torrent_from_memory_whitelist(&info_hash).await; - - assert!(!whitelist_manager.is_info_hash_whitelisted(&info_hash).await); + services.database_whitelist.add(&info_hash).unwrap(); whitelist_manager.load_whitelist_from_database().await.unwrap(); - assert!(whitelist_manager.is_info_hash_whitelisted(&info_hash).await); + assert!(services.in_memory_whitelist.contains(&info_hash).await); } } } diff --git a/packages/tracker-core/src/whitelist/repository/persisted.rs b/packages/tracker-core/src/whitelist/repository/persisted.rs index c3c4a2601..5101b5e35 100644 --- a/packages/tracker-core/src/whitelist/repository/persisted.rs +++ b/packages/tracker-core/src/whitelist/repository/persisted.rs @@ -60,3 +60,79 @@ impl DatabaseWhitelist { self.database.load_whitelist() } } + +#[cfg(test)] +mod tests { + mod the_persisted_whitelist_repository { + + use crate::core_tests::{ephemeral_configuration_for_listed_tracker, sample_info_hash}; + use crate::databases::setup::initialize_database; + use crate::whitelist::repository::persisted::DatabaseWhitelist; + + fn initialize_database_whitelist() -> DatabaseWhitelist { + let configuration = ephemeral_configuration_for_listed_tracker(); + let database = initialize_database(&configuration); + DatabaseWhitelist::new(database) + } + + #[test] + fn should_add_a_new_infohash_to_the_list() { + let whitelist = initialize_database_whitelist(); + + let infohash = sample_info_hash(); + + let _result = whitelist.add(&infohash); + + assert_eq!(whitelist.load_from_database().unwrap(), vec!(infohash)); + } + + #[test] + fn should_remove_a_infohash_from_the_list() { + let whitelist = initialize_database_whitelist(); + + let infohash = sample_info_hash(); + + let _result = whitelist.add(&infohash); + + let _result = whitelist.remove(&infohash); + + assert_eq!(whitelist.load_from_database().unwrap(), vec!()); + } + + #[test] + fn should_load_all_infohashes_from_the_database() { + let whitelist = initialize_database_whitelist(); + + let infohash = sample_info_hash(); + + let _result = whitelist.add(&infohash); + + let result = whitelist.load_from_database().unwrap(); + + assert_eq!(result, vec!(infohash)); + } + + #[test] + fn should_not_add_the_same_infohash_to_the_list_twice() { + let whitelist = initialize_database_whitelist(); + + let infohash = sample_info_hash(); + + let _result = whitelist.add(&infohash); + let _result = whitelist.add(&infohash); + + assert_eq!(whitelist.load_from_database().unwrap(), vec!(infohash)); + } + + #[test] + fn should_not_fail_removing_an_infohash_that_is_not_in_the_list() { + let whitelist = initialize_database_whitelist(); + + let infohash = sample_info_hash(); + + let result = whitelist.remove(&infohash); + + assert!(result.is_ok()); + } + } +} diff --git a/src/bootstrap/app.rs b/src/bootstrap/app.rs index e0e81c70c..0236215f2 100644 --- a/src/bootstrap/app.rs +++ b/src/bootstrap/app.rs @@ -141,6 +141,7 @@ pub fn initialize_app_container(configuration: &Configuration) -> AppContainer { scrape_handler, keys_handler, authentication_service, + in_memory_whitelist, whitelist_authorization, ban_service, http_stats_event_sender, diff --git a/src/container.rs b/src/container.rs index 51c55e533..47cc39ed3 100644 --- a/src/container.rs +++ b/src/container.rs @@ -10,6 +10,7 @@ use bittorrent_tracker_core::torrent::repository::in_memory::InMemoryTorrentRepo use bittorrent_tracker_core::torrent::repository::persisted::DatabasePersistentTorrentRepository; use bittorrent_tracker_core::whitelist; use bittorrent_tracker_core::whitelist::manager::WhitelistManager; +use bittorrent_tracker_core::whitelist::repository::in_memory::InMemoryWhitelist; use tokio::sync::RwLock; use torrust_tracker_configuration::{Core, HttpApi, HttpTracker, UdpTracker}; @@ -23,6 +24,7 @@ pub struct AppContainer { pub scrape_handler: Arc, pub keys_handler: Arc, pub authentication_service: Arc, + pub in_memory_whitelist: Arc, pub whitelist_authorization: Arc, pub ban_service: Arc>, pub http_stats_event_sender: Arc>>, diff --git a/tests/servers/api/environment.rs b/tests/servers/api/environment.rs index 61351024d..02d6465e1 100644 --- a/tests/servers/api/environment.rs +++ b/tests/servers/api/environment.rs @@ -4,6 +4,7 @@ use std::sync::Arc; use bittorrent_primitives::info_hash::InfoHash; use bittorrent_tracker_core::authentication::service::AuthenticationService; use bittorrent_tracker_core::databases::Database; +use bittorrent_tracker_core::whitelist::repository::in_memory::InMemoryWhitelist; use futures::executor::block_on; use torrust_tracker_api_client::connection_info::{ConnectionInfo, Origin}; use torrust_tracker_configuration::Configuration; @@ -22,6 +23,7 @@ where pub database: Arc>, pub authentication_service: Arc, + pub in_memory_whitelist: Arc, pub registar: Registar, pub server: ApiServer, @@ -70,6 +72,7 @@ impl Environment { database: app_container.database.clone(), authentication_service: app_container.authentication_service.clone(), + in_memory_whitelist: app_container.in_memory_whitelist.clone(), registar: Registar::default(), server, @@ -84,6 +87,7 @@ impl Environment { database: self.database.clone(), authentication_service: self.authentication_service.clone(), + in_memory_whitelist: self.in_memory_whitelist.clone(), registar: self.registar.clone(), server: self @@ -106,6 +110,7 @@ impl Environment { database: self.database, authentication_service: self.authentication_service, + in_memory_whitelist: self.in_memory_whitelist, registar: Registar::default(), server: self.server.stop().await.unwrap(), diff --git a/tests/servers/api/v1/contract/context/whitelist.rs b/tests/servers/api/v1/contract/context/whitelist.rs index 945cb00b5..ca359650f 100644 --- a/tests/servers/api/v1/contract/context/whitelist.rs +++ b/tests/servers/api/v1/contract/context/whitelist.rs @@ -31,9 +31,8 @@ async fn should_allow_whitelisting_a_torrent() { assert_ok(response).await; assert!( - env.http_api_container - .whitelist_manager - .is_info_hash_whitelisted(&InfoHash::from_str(&info_hash).unwrap()) + env.in_memory_whitelist + .contains(&InfoHash::from_str(&info_hash).unwrap()) .await ); @@ -181,12 +180,7 @@ async fn should_allow_removing_a_torrent_from_the_whitelist() { .await; assert_ok(response).await; - assert!( - !env.http_api_container - .whitelist_manager - .is_info_hash_whitelisted(&info_hash) - .await - ); + assert!(!env.in_memory_whitelist.contains(&info_hash).await); env.stop().await; }