From d6c679af19ba116534573fc6e8e3c430472c74e4 Mon Sep 17 00:00:00 2001 From: Ingvar Stepanyan Date: Sat, 31 Aug 2024 22:52:28 +0100 Subject: [PATCH] Allow parallel tests --- src/lib.rs | 1 - src/macros.rs | 54 +++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 39 insertions(+), 16 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index ce45951..bb57607 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -453,7 +453,6 @@ mod test_utils { }) } - #[instrument(level = "error", skip(self))] pub(crate) async fn test_device_type(&self, ty: DeviceType) -> eyre::Result<()> { let api_path = &self.api_path; diff --git a/src/macros.rs b/src/macros.rs index 8e48cae..9c3a769 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -395,26 +395,50 @@ macro_rules! rpc_mod { } #[cfg(test)] - #[tokio::test] - async fn test_passthrough_devices() -> eyre::Result<()> { - let env = $crate::test_utils::PassthroughTestEnv::try_new().await?; - - let mut failed = 0_usize; - let mut total = 0_usize; + mod test_passthrough { + use std::sync::{Arc, Weak}; + use tokio::sync::Mutex; + use $crate::test_utils::PassthroughTestEnv; + use super::DeviceType; + + // Note: the static variable should only contain a Weak copy, otherwise the test environment + // would never be dropped, and we want it to be dropped at the end of the last strong copy + // (last running test). + static TEST_ENV: Mutex> = Mutex::const_new(Weak::new()); + + /// Get the shared test environment with an incremented refcount. + /// + /// If one is already available - which should happen when running tests in parallel - then just acquire a refcounted copy. + /// If not, put a new one in place. + /// + /// This way, each test increases the refcount at start and decreases it at the end, so whichever happens to run last, + /// kills the simulator running in the background. + /// + /// This is a workaround for Rust test framework not having an "after all" hook. + async fn acquire_test_env() -> eyre::Result> { + let mut lock = TEST_ENV.lock().await; + + Ok(match lock.upgrade() { + Some(env) => env, + None => { + let env = Arc::new(PassthroughTestEnv::try_new().await?); + *lock = Arc::downgrade(&env); + env + } + }) + } $( #[cfg(feature = $path)] - { - if env.test_device_type(DeviceType::$trait_name).await.is_err() { - failed += 1; - } - total += 1; + #[tokio::test] + #[allow(non_snake_case)] + async fn $trait_name() -> eyre::Result<()> { + acquire_test_env() + .await? + .test_device_type(DeviceType::$trait_name) + .await } )* - - eyre::ensure!(failed == 0, "{failed}/{total} devices have failed ConformU checks"); - - Ok(()) } }; }