Commit dec2c4ee authored by Nick Mathewson's avatar Nick Mathewson 🤹
Browse files

Make test_with_all_runtimes cover _all_ the runtimes.

This took some refactoring, so that I wouldn't need to define 9
different versions of the function.  It also required that we change
the behavior of test_with_all_runtimes slightly, so that it asserts
on _any_ failure rather than asserting on most but returning Err()
for others.  That in turn required changes to a few of its callers.

There's probably a better way to do all of this macro business, but
this is the best I could find.
parent 30b3818a
Loading
Loading
Loading
Loading
+27 −10
Original line number Diff line number Diff line
@@ -83,6 +83,20 @@ impl AsyncStdNativeTlsRuntime {
    pub fn current() -> IoResult<Self> {
        Self::create()
    }

    /// Helper to run a single test function in a freshly created runtime.
    ///
    /// # Panics
    ///
    /// Panics if we can't create this runtime.
    pub fn run_test<P, F, O>(func: P) -> O
    where
        P: FnOnce(Self) -> F,
        F: futures::Future<Output = O>,
    {
        let runtime = Self::create().expect("Failed to create runtime");
        runtime.clone().block_on(func(runtime))
    }
}

#[cfg(feature = "rustls")]
@@ -108,15 +122,18 @@ impl AsyncStdRustlsRuntime {
    pub fn current() -> IoResult<Self> {
        Self::create()
    }
}

/// Run a test function using a freshly created async_std runtime.
#[cfg(any(feature = "native-tls", feature = "rustls"))]
pub fn test_with_runtime<P, F, O>(func: P) -> O
    /// Helper to run a single test function in a freshly created runtime.
    ///
    /// # Panics
    ///
    /// Panics if we can't create this runtime.
    pub fn run_test<P, F, O>(func: P) -> O
    where
    P: FnOnce(PreferredRuntime) -> F,
        P: FnOnce(Self) -> F,
        F: futures::Future<Output = O>,
    {
    let runtime = PreferredRuntime::create().expect("Couldn't get global async_std runtime?");
        let runtime = Self::create().expect("Failed to create runtime");
        runtime.clone().block_on(func(runtime))
    }
}
+69 −46
Original line number Diff line number Diff line
@@ -250,7 +250,8 @@ pub fn create_runtime() -> std::io::Result<impl Runtime> {

/// Helpers for test_with_all_runtimes
pub mod testing__ {
    /// A trait for an object that might represent a test failure.
    /// A trait for an object that might represent a test failure, or which
    /// might just be `().
    pub trait TestOutcome {
        /// Abort if the test has failed.
        fn check_ok(&self);
@@ -258,65 +259,88 @@ pub mod testing__ {
    impl TestOutcome for () {
        fn check_ok(&self) {}
    }
    impl<T, E> TestOutcome for Result<T, E> {
    impl<E: std::fmt::Debug> TestOutcome for Result<(), E> {
        fn check_ok(&self) {
            assert!(self.is_ok());
            self.as_ref().expect("Test failure");
        }
    }
}

/// Run a test closure, passing as argument every supported runtime.
///
/// (This is a macro so that it can repeat the closure as two separate
/// expressions, so it can take on two different types, if needed.)
/// Helper: define a macro that expands a token tree iff a pair of features are
/// both present.
macro_rules! declare_conditional_macro {
    ( $(#[$meta:meta])* macro $name:ident = ($f1:expr, $f2:expr) ) => {
        $( #[$meta] )*
        #[cfg(all(feature=$f1, feature=$f2))]
        #[macro_export]
#[cfg(all(
    any(feature = "native-tls", feature = "rustls"),
    feature = "tokio",
    feature = "async-std"
))]
macro_rules! test_with_all_runtimes {
    ( $fn:expr ) => {{
        use $crate::testing__::TestOutcome;
        $crate::tokio::test_with_runtime($fn).check_ok();
        $crate::async_std::test_with_runtime($fn)
    }};
        macro_rules! $name {
            ($tt:tt) => {
                $tt
            };
        }

/// Run a test closure, passing as argument every supported runtime.
        $( #[$meta] )*
        #[cfg(not(all(feature=$f1, feature=$f2)))]
        #[macro_export]
#[cfg(all(
    any(feature = "native-tls", feature = "rustls"),
    feature = "tokio",
    not(feature = "async-std")
))]
macro_rules! test_with_all_runtimes {
    ( $fn:expr ) => {{
        $crate::tokio::test_with_runtime($fn)
    }};
        macro_rules! $name {
            ($tt:tt) => {};
        }

        // Needed so that we can access this macro at this path, both within the
        // crate and without.
        pub use $name;
    };
}

/// Defines macros that will expand when certain runtimes are available.
pub mod cond {
    declare_conditional_macro! {
        /// Expand a token tree if the TokioNativeTlsRuntime is available.
        macro if_tokio_native_tls_present = ("tokio", "native-tls")
    }
    declare_conditional_macro! {
        /// Expand a token tree if the TokioRustlsRuntime is available.
        macro if_tokio_rustls_present = ("tokio", "rustls")
    }
    declare_conditional_macro! {
        /// Expand a token tree if the TokioNativeTlsRuntime is available.
        macro if_async_std_native_tls_present = ("async-std", "native-tls")
    }
    declare_conditional_macro! {
        /// Expand a token tree if the TokioNativeTlsRuntime is available.
        macro if_async_std_rustls_present = ("async-std", "rustls")
    }
}

/// Run a test closure, passing as argument every supported runtime.
///
/// (This is a macro so that it can repeat the closure as multiple separate
/// expressions, so it can take on two different types, if needed.)
#[macro_export]
#[cfg(all(
    any(feature = "native-tls", feature = "rustls"),
    not(feature = "tokio"),
    feature = "async-std"
    any(feature = "tokio", feature = "async-std"),
))]
macro_rules! test_with_all_runtimes {
    ( $fn:expr ) => {{
        $crate::async_std::test_with_runtime($fn)
    }};
}
        use $crate::cond::*;
        use $crate::testing__::TestOutcome;
        // We have to do this outcome-checking business rather than just using
        // the ? operator or calling expect() because some of the closures that
        // we use this macro with return (), and some return Result.

/// Run a test closure, passing as argument one supported runtime.
///
/// (Always prefers tokio if present.)
#[macro_export]
#[cfg(feature = "tokio")]
macro_rules! test_with_one_runtime {
    ( $fn:expr ) => {{
        $crate::tokio::test_with_runtime($fn)
        if_tokio_native_tls_present! {{
           $crate::tokio::TokioNativeTlsRuntime::run_test($fn).check_ok();
        }}
        if_tokio_rustls_present! {{
            $crate::tokio::TokioRustlsRuntime::run_test($fn).check_ok();
        }}
        if_async_std_native_tls_present! {{
            $crate::async_std::AsyncStdNativeTlsRuntime::run_test($fn).check_ok();
        }}
        if_async_std_rustls_present! {{
            $crate::async_std::AsyncStdRustlsRuntime::run_test($fn).check_ok();
        }}
    }};
}

@@ -326,11 +350,10 @@ macro_rules! test_with_one_runtime {
#[macro_export]
#[cfg(all(
    any(feature = "native-tls", feature = "rustls"),
    not(feature = "tokio"),
    feature = "async-std"
    any(feature = "tokio", feature = "async-std"),
))]
macro_rules! test_with_one_runtime {
    ( $fn:expr ) => {{
        $crate::async_std::test_with_runtime($fn)
        $crate::PreferredRuntime::run_test($fn)
    }};
}
+2 −3
Original line number Diff line number Diff line
@@ -50,7 +50,7 @@ mod test {
    use std::sync::atomic::{AtomicBool, Ordering};

    #[test]
    fn test_yield() -> std::io::Result<()> {
    fn test_yield() {
        test_with_all_runtimes!(|_| async {
            let b = AtomicBool::new(false);
            use Ordering::SeqCst;
@@ -81,7 +81,6 @@ mod test {
                }
            );
            std::io::Result::Ok(())
        })?;
        Ok(())
        });
    }
}
+28 −15
Original line number Diff line number Diff line
@@ -115,6 +115,20 @@ impl TokioNativeTlsRuntime {
    pub fn current() -> IoResult<Self> {
        Ok(current_handle()?.into())
    }

    /// Helper to run a single test function in a freshly created runtime.
    ///
    /// # Panics
    ///
    /// Panics if we can't create this runtime.
    pub fn run_test<P, F, O>(func: P) -> O
    where
        P: FnOnce(Self) -> F,
        F: futures::Future<Output = O>,
    {
        let runtime = Self::create().expect("Failed to create runtime");
        runtime.clone().block_on(func(runtime))
    }
}

#[cfg(feature = "rustls")]
@@ -148,25 +162,24 @@ impl TokioRustlsRuntime {
    pub fn current() -> IoResult<Self> {
        Ok(current_handle()?.into())
    }
}

/// As `Handle::try_current()`, but return an IoError on failure.
#[cfg(any(feature = "native-tls", feature = "rustls"))]
fn current_handle() -> std::io::Result<tokio_crate::runtime::Handle> {
    tokio_crate::runtime::Handle::try_current().map_err(|e| IoError::new(ErrorKind::Other, e))
}

/// Run a test function using a freshly created tokio runtime.
    /// Helper to run a single test function in a freshly created runtime.
    ///
    /// # Panics
    ///
/// Panics if we can't create a tokio runtime.
#[cfg(any(feature = "native-tls", feature = "rustls"))]
pub fn test_with_runtime<P, F, O>(func: P) -> O
    /// Panics if we can't create this runtime.
    pub fn run_test<P, F, O>(func: P) -> O
    where
    P: FnOnce(PreferredRuntime) -> F,
        P: FnOnce(Self) -> F,
        F: futures::Future<Output = O>,
    {
    let runtime = PreferredRuntime::create().expect("Failed to create a tokio runtime");
        let runtime = Self::create().expect("Failed to create runtime");
        runtime.clone().block_on(func(runtime))
    }
}

/// As `Handle::try_current()`, but return an IoError on failure.
#[cfg(any(feature = "native-tls", feature = "rustls"))]
fn current_handle() -> std::io::Result<tokio_crate::runtime::Handle> {
    tokio_crate::runtime::Handle::try_current().map_err(|e| IoError::new(ErrorKind::Other, e))
}
+10 −8
Original line number Diff line number Diff line
@@ -502,7 +502,7 @@ mod test {
    }

    #[test]
    fn end_to_end() -> IoResult<()> {
    fn end_to_end() {
        test_with_all_runtimes!(|_rt| async {
            let (client1, client2) = client_pair();
            let lis = client2.listen(&"0.0.0.0:99".parse().unwrap()).await?;
@@ -532,7 +532,7 @@ mod test {
            r1?;
            r2?;
            IoResult::Ok(())
        })
        });
    }

    #[test]
@@ -573,7 +573,7 @@ mod test {
    }

    #[test]
    fn listener_stream() -> IoResult<()> {
    fn listener_stream() {
        test_with_all_runtimes!(|_rt| async {
            let (client1, client2) = client_pair();

@@ -602,16 +602,18 @@ mod test {
            r1?;
            r2?;
            IoResult::Ok(())
        })
        });
    }

    #[test]
    fn tls_basics() -> IoResult<()> {
    fn tls_basics() {
        let (client1, client2) = client_pair();
        let cert = b"I am certified for something I assure you.";

        let lis = client2.listen_tls(&"0.0.0.0:0".parse().unwrap(), cert[..].into())?;
        let address = lis.local_addr()?;
        let lis = client2
            .listen_tls(&"0.0.0.0:0".parse().unwrap(), cert[..].into())
            .unwrap();
        let address = lis.local_addr().unwrap();

        test_with_all_runtimes!(|_rt| async {
            let (r1, r2): (IoResult<()>, IoResult<()>) = futures::join!(
@@ -642,6 +644,6 @@ mod test {
            r1?;
            r2?;
            IoResult::Ok(())
        })
        });
    }
}
Loading