-
Notifications
You must be signed in to change notification settings - Fork 20
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge #129: Integration tests scaffolding
6d5e002 test: isolated environments for integration testing (Jose Celano) 2211871 refactor: extract app from main (Jose Celano) 89e544e feat: server port assigned by OS with port 0 (Jose Celano) Pull request description: Changes needed to run tests with independent app instances running on different ports. ACKs for top commit: josecelano: ACK 6d5e002 Tree-SHA512: 3f3731cc7b27042198f7dfeec6c30f7374481005bd4eeb70a45e1405576641234f7dc3b96bf8811b220867ad6e7b6292049be5c6e7807b1803925297a98ca3ba
- Loading branch information
Showing
16 changed files
with
415 additions
and
121 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
use std::net::SocketAddr; | ||
use std::sync::Arc; | ||
|
||
use actix_cors::Cors; | ||
use actix_web::dev::Server; | ||
use actix_web::{middleware, web, App, HttpServer}; | ||
use log::info; | ||
|
||
use crate::auth::AuthorizationService; | ||
use crate::bootstrap::logging; | ||
use crate::common::AppData; | ||
use crate::config::Configuration; | ||
use crate::databases::database::connect_database; | ||
use crate::mailer::MailerService; | ||
use crate::routes; | ||
use crate::tracker::TrackerService; | ||
|
||
pub struct Running { | ||
pub api_server: Server, | ||
pub socket_address: SocketAddr, | ||
pub tracker_data_importer_handle: tokio::task::JoinHandle<()>, | ||
} | ||
|
||
pub async fn run(configuration: Configuration) -> Running { | ||
logging::setup(); | ||
|
||
let cfg = Arc::new(configuration); | ||
|
||
// Get configuration settings needed to build the app dependencies and | ||
// services: main API server and tracker torrents importer. | ||
|
||
let settings = cfg.settings.read().await; | ||
|
||
let database_connect_url = settings.database.connect_url.clone(); | ||
let database_torrent_info_update_interval = settings.database.torrent_info_update_interval; | ||
let net_port = settings.net.port; | ||
|
||
// IMPORTANT: drop settings before starting server to avoid read locks that | ||
// leads to requests hanging. | ||
drop(settings); | ||
|
||
// Build app dependencies | ||
|
||
let database = Arc::new(connect_database(&database_connect_url).await.expect("Database error.")); | ||
let auth = Arc::new(AuthorizationService::new(cfg.clone(), database.clone())); | ||
let tracker_service = Arc::new(TrackerService::new(cfg.clone(), database.clone())); | ||
let mailer_service = Arc::new(MailerService::new(cfg.clone()).await); | ||
|
||
// Build app container | ||
|
||
let app_data = Arc::new(AppData::new( | ||
cfg.clone(), | ||
database.clone(), | ||
auth.clone(), | ||
tracker_service.clone(), | ||
mailer_service, | ||
)); | ||
|
||
// Start repeating task to import tracker torrent data and updating | ||
// seeders and leechers info. | ||
|
||
let weak_tracker_service = Arc::downgrade(&tracker_service); | ||
|
||
let tracker_data_importer_handle = tokio::spawn(async move { | ||
let interval = std::time::Duration::from_secs(database_torrent_info_update_interval); | ||
let mut interval = tokio::time::interval(interval); | ||
interval.tick().await; // first tick is immediate... | ||
loop { | ||
interval.tick().await; | ||
if let Some(tracker) = weak_tracker_service.upgrade() { | ||
let _ = tracker.update_torrents().await; | ||
} else { | ||
break; | ||
} | ||
} | ||
}); | ||
|
||
// Start main API server | ||
|
||
// todo: get IP from settings | ||
let ip = "0.0.0.0".to_string(); | ||
|
||
let server = HttpServer::new(move || { | ||
App::new() | ||
.wrap(Cors::permissive()) | ||
.app_data(web::Data::new(app_data.clone())) | ||
.wrap(middleware::Logger::default()) | ||
.configure(routes::init_routes) | ||
}) | ||
.bind((ip, net_port)) | ||
.expect("can't bind server to socket address"); | ||
|
||
let socket_address = server.addrs()[0]; | ||
|
||
let running_server = server.run(); | ||
|
||
let starting_message = format!("Listening on http://{}", socket_address); | ||
info!("{}", starting_message); | ||
// Logging could be disabled or redirected to file. So print to stdout too. | ||
println!("{}", starting_message); | ||
|
||
Running { | ||
api_server: running_server, | ||
socket_address, | ||
tracker_data_importer_handle, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,93 +1,11 @@ | ||
use std::env; | ||
use std::sync::Arc; | ||
|
||
use actix_cors::Cors; | ||
use actix_web::{middleware, web, App, HttpServer}; | ||
use torrust_index_backend::auth::AuthorizationService; | ||
use torrust_index_backend::bootstrap::logging; | ||
use torrust_index_backend::common::AppData; | ||
use torrust_index_backend::config::{Configuration, CONFIG_ENV_VAR_NAME, CONFIG_PATH}; | ||
use torrust_index_backend::databases::database::connect_database; | ||
use torrust_index_backend::mailer::MailerService; | ||
use torrust_index_backend::routes; | ||
use torrust_index_backend::tracker::TrackerService; | ||
use torrust_index_backend::app; | ||
use torrust_index_backend::bootstrap::config::init_configuration; | ||
|
||
#[actix_web::main] | ||
async fn main() -> std::io::Result<()> { | ||
async fn main() -> Result<(), std::io::Error> { | ||
let configuration = init_configuration().await; | ||
|
||
logging::setup(); | ||
|
||
let cfg = Arc::new(configuration); | ||
|
||
let settings = cfg.settings.read().await; | ||
|
||
let database = Arc::new( | ||
connect_database(&settings.database.connect_url) | ||
.await | ||
.expect("Database error."), | ||
); | ||
|
||
let auth = Arc::new(AuthorizationService::new(cfg.clone(), database.clone())); | ||
let tracker_service = Arc::new(TrackerService::new(cfg.clone(), database.clone())); | ||
let mailer_service = Arc::new(MailerService::new(cfg.clone()).await); | ||
let app_data = Arc::new(AppData::new( | ||
cfg.clone(), | ||
database.clone(), | ||
auth.clone(), | ||
tracker_service.clone(), | ||
mailer_service.clone(), | ||
)); | ||
|
||
let interval = settings.database.torrent_info_update_interval; | ||
let weak_tracker_service = Arc::downgrade(&tracker_service); | ||
|
||
// repeating task, update all seeders and leechers info | ||
tokio::spawn(async move { | ||
let interval = std::time::Duration::from_secs(interval); | ||
let mut interval = tokio::time::interval(interval); | ||
interval.tick().await; // first tick is immediate... | ||
loop { | ||
interval.tick().await; | ||
if let Some(tracker) = weak_tracker_service.upgrade() { | ||
let _ = tracker.update_torrents().await; | ||
} else { | ||
break; | ||
} | ||
} | ||
}); | ||
|
||
let port = settings.net.port; | ||
|
||
drop(settings); | ||
|
||
println!("Listening on http://0.0.0.0:{}", port); | ||
|
||
HttpServer::new(move || { | ||
App::new() | ||
.wrap(Cors::permissive()) | ||
.app_data(web::Data::new(app_data.clone())) | ||
.wrap(middleware::Logger::default()) | ||
.configure(routes::init_routes) | ||
}) | ||
.bind(("0.0.0.0", port))? | ||
.run() | ||
.await | ||
} | ||
|
||
async fn init_configuration() -> Configuration { | ||
if env::var(CONFIG_ENV_VAR_NAME).is_ok() { | ||
println!("Loading configuration from env var `{}`", CONFIG_ENV_VAR_NAME); | ||
|
||
Configuration::load_from_env_var(CONFIG_ENV_VAR_NAME).unwrap() | ||
} else { | ||
println!("Loading configuration from config file `{}`", CONFIG_PATH); | ||
let app = app::run(configuration).await; | ||
|
||
match Configuration::load_from_file().await { | ||
Ok(config) => config, | ||
Err(error) => { | ||
panic!("{}", error) | ||
} | ||
} | ||
} | ||
app.api_server.await | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
use std::env; | ||
|
||
pub const CONFIG_PATH: &str = "./config.toml"; | ||
pub const CONFIG_ENV_VAR_NAME: &str = "TORRUST_IDX_BACK_CONFIG"; | ||
|
||
use crate::config::Configuration; | ||
|
||
/// Initialize configuration from file or env var. | ||
/// | ||
/// # Panics | ||
/// | ||
/// Will panic if configuration is not found or cannot be parsed | ||
pub async fn init_configuration() -> Configuration { | ||
if env::var(CONFIG_ENV_VAR_NAME).is_ok() { | ||
println!("Loading configuration from env var `{}`", CONFIG_ENV_VAR_NAME); | ||
|
||
Configuration::load_from_env_var(CONFIG_ENV_VAR_NAME).unwrap() | ||
} else { | ||
println!("Loading configuration from config file `{}`", CONFIG_PATH); | ||
|
||
match Configuration::load_from_file(CONFIG_PATH).await { | ||
Ok(config) => config, | ||
Err(error) => { | ||
panic!("{}", error) | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
pub mod config; | ||
pub mod logging; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.