diff --git a/src/backend/mod.rs b/src/backend/mod.rs index fa1b61c..386f253 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -51,7 +51,7 @@ use leptos::prelude::*; use leptos_axum::{generate_route_list, LeptosRoutes}; use log::info; use std::net::SocketAddr; -use tokio::net::TcpListener; +use tokio::{net::TcpListener, sync::oneshot}; use tower_http::cors::CorsLayer; use tower_layer::Layer; @@ -68,7 +68,11 @@ const MIGRATIONS: EmbeddedMigrations = embed_migrations!("migrations"); const FEDERATION_ROUTES_PREFIX: &str = "/federation_routes"; -pub async fn start(config: IbisConfig, override_hostname: Option) -> MyResult<()> { +pub async fn start( + config: IbisConfig, + override_hostname: Option, + notify_start: Option>, +) -> MyResult<()> { let manager = ConnectionManager::::new(&config.database.connection_url); let db_pool = Pool::builder() .max_size(config.database.pool_size) @@ -118,6 +122,9 @@ pub async fn start(config: IbisConfig, override_hostname: Option) -> info!("Listening on {}", &addr); let listener = TcpListener::bind(&addr).await?; + if let Some(notify_start) = notify_start { + notify_start.send(()).expect("send oneshot"); + } axum::serve(listener, app_with_middleware.into_make_service()).await?; Ok(()) diff --git a/src/frontend/app.rs b/src/frontend/app.rs index 066a7ae..97f7814 100644 --- a/src/frontend/app.rs +++ b/src/frontend/app.rs @@ -66,7 +66,7 @@ impl DefaultResource for Resource { } pub fn shell(options: LeptosOptions) -> impl IntoView { view! { - + diff --git a/src/main.rs b/src/main.rs index 54c63c2..cf8baf5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,6 +16,6 @@ pub async fn main() -> ibis::backend::error::MyResult<()> { .init(); let ibis_config = IbisConfig::read()?; - ibis::backend::start(ibis_config, None).await?; + ibis::backend::start(ibis_config, None, None).await?; Ok(()) } diff --git a/tests/common.rs b/tests/common.rs index 44a6770..1eee138 100644 --- a/tests/common.rs +++ b/tests/common.rs @@ -16,17 +16,19 @@ use std::{ ops::Deref, process::{Command, Stdio}, sync::{ - atomic::{AtomicI32, Ordering}, + atomic::{AtomicI32, AtomicUsize, Ordering}, Once, }, - thread::{sleep, spawn}, + thread::{available_parallelism, sleep, spawn}, time::Duration, }; -use tokio::{join, task::JoinHandle}; +use tokio::{join, sync::oneshot, task::JoinHandle}; use tracing::log::LevelFilter; pub struct TestData(pub IbisInstance, pub IbisInstance, pub IbisInstance); +static ACTIVE_TESTS: AtomicUsize = AtomicUsize::new(0); + impl TestData { pub async fn start(article_approval: bool) -> Self { static INIT: Once = Once::new(); @@ -42,8 +44,12 @@ impl TestData { static COUNTER: AtomicI32 = AtomicI32::new(0); let current_run = COUNTER.fetch_add(1, Ordering::Relaxed); - // Give each test a moment to start its postgres databases - sleep(Duration::from_millis(current_run as u64 * 2000)); + // Limit number of parallel test runs based on number of cpu cores + let cores = available_parallelism().unwrap().get(); + while ACTIVE_TESTS.load(Ordering::Acquire) >= cores { + sleep(Duration::from_millis(1000)); + } + ACTIVE_TESTS.fetch_add(1, Ordering::AcqRel); let first_port = 8100 + (current_run * 3); let port_alpha = first_port; @@ -76,6 +82,7 @@ impl TestData { for j in [alpha.stop(), beta.stop(), gamma.stop()] { j.join().unwrap(); } + ACTIVE_TESTS.fetch_sub(1, Ordering::AcqRel); Ok(()) } } @@ -133,13 +140,14 @@ impl IbisInstance { }; let client = ClientBuilder::new().cookie_store(true).build().unwrap(); let api_client = ApiClient::new(client, Some(domain)); + let (tx, rx) = oneshot::channel::<()>(); let handle = tokio::task::spawn(async move { - start(config, Some(hostname.parse().unwrap())) + start(config, Some(hostname.parse().unwrap()), Some(tx)) .await .unwrap(); }); - // wait a moment for the backend to start - tokio::time::sleep(Duration::from_millis(5000)).await; + // wait for the backend to start + rx.await.unwrap(); let form = RegisterUserForm { username: username.to_string(), password: "hunter2".to_string(),