summaryrefslogtreecommitdiffstats
path: root/tokio-macros
diff options
context:
space:
mode:
authorJon Gjengset <jon@thesquareplanet.com>2019-10-02 13:58:34 -0400
committerCarl Lerche <me@carllerche.com>2019-10-02 10:58:34 -0700
commitc78c9168d7d9e7dce4b3ab5426a68a9787bae147 (patch)
treeb29230c04de47ec982bd253a07b5b3f8b81fb2ff /tokio-macros
parent9e1eef829a3b4b41f25df726916d7f39aaf9145d (diff)
macros: allow selecting runtime in tokio::test attr (#1620)
In the past, it was not possible to choose to use the multi-threaded tokio `Runtime` in tests, which meant that any test that transitively used `executor::threadpool::blocking` would fail with ``` 'blocking' annotation used from outside the context of a thread pool ``` This patch adds a runtime annotation attribute to `#[tokio::test]` just like `#[tokio::main]` has, which lets users opt in to the threadpool runtime over `current_thread` (the default).
Diffstat (limited to 'tokio-macros')
-rw-r--r--tokio-macros/src/lib.rs74
1 files changed, 58 insertions, 16 deletions
diff --git a/tokio-macros/src/lib.rs b/tokio-macros/src/lib.rs
index 07adfa0d..24a52021 100644
--- a/tokio-macros/src/lib.rs
+++ b/tokio-macros/src/lib.rs
@@ -18,6 +18,12 @@ extern crate proc_macro;
use proc_macro::TokenStream;
use quote::quote;
+enum RuntimeType {
+ Single,
+ Multi,
+ Auto,
+}
+
/// Marks async function to be executed by selected runtime.
///
/// ## Options:
@@ -50,12 +56,6 @@ use quote::quote;
#[proc_macro_attribute]
#[cfg(not(test))] // Work around for rust-lang/rust#62127
pub fn main(args: TokenStream, item: TokenStream) -> TokenStream {
- enum RuntimeType {
- Single,
- Multi,
- Auto,
- }
-
let input = syn::parse_macro_input!(item as syn::ItemFn);
let args = syn::parse_macro_input!(args as syn::AttributeArgs);
@@ -90,7 +90,7 @@ pub fn main(args: TokenStream, item: TokenStream) -> TokenStream {
"multi_thread" => runtime = RuntimeType::Multi,
"single_thread" => runtime = RuntimeType::Single,
name => {
- let msg = format!("Unknown attribute {} is specified", name);
+ let msg = format!("Unknown attribute {} is specified; expected `single_thread` or `multi_thread`", name);
return syn::Error::new_spanned(path, msg).to_compile_error().into();
}
}
@@ -124,9 +124,23 @@ pub fn main(args: TokenStream, item: TokenStream) -> TokenStream {
/// Marks async function to be executed by runtime, suitable to test enviornment
///
-/// Uses `current_thread` runtime.
+/// ## Options:
+///
+/// - `single_thread` - Uses `current_thread`. Used by default.
+/// - `multi_thread` - Uses multi-threaded runtime.
+///
+/// ## Usage
+///
+/// ### Select runtime
+///
+/// ```no_run
+/// #[tokio::test(multi_thread)]
+/// async fn my_test() {
+/// assert!(true);
+/// }
+/// ```
///
-/// # Examples
+/// ### Using default
///
/// ```no_run
/// #[tokio::test]
@@ -137,7 +151,7 @@ pub fn main(args: TokenStream, item: TokenStream) -> TokenStream {
#[proc_macro_attribute]
pub fn test(args: TokenStream, item: TokenStream) -> TokenStream {
let input = syn::parse_macro_input!(item as syn::ItemFn);
- let _ = syn::parse_macro_input!(args as syn::parse::Nothing);
+ let args = syn::parse_macro_input!(args as syn::AttributeArgs);
let ret = &input.sig.output;
let name = &input.sig.ident;
@@ -165,13 +179,41 @@ pub fn test(args: TokenStream, item: TokenStream) -> TokenStream {
.into();
}
- let result = quote! {
- #[test]
- #(#attrs)*
- fn #name() #ret {
- let mut rt = tokio::runtime::current_thread::Runtime::new().unwrap();
- rt.block_on(async { #body })
+ let mut runtime = RuntimeType::Auto;
+
+ for arg in args {
+ if let syn::NestedMeta::Meta(syn::Meta::Path(path)) = arg {
+ let ident = path.get_ident();
+ if ident.is_none() {
+ let msg = "Must have specified ident";
+ return syn::Error::new_spanned(path, msg).to_compile_error().into();
+ }
+ match ident.unwrap().to_string().to_lowercase().as_str() {
+ "multi_thread" => runtime = RuntimeType::Multi,
+ "single_thread" => runtime = RuntimeType::Single,
+ name => {
+ let msg = format!("Unknown attribute {} is specified; expected `single_thread` or `multi_thread`", name);
+ return syn::Error::new_spanned(path, msg).to_compile_error().into();
+ }
+ }
}
+ }
+
+ let result = match runtime {
+ RuntimeType::Multi => quote! {
+ #[test]
+ #(#attrs)*
+ fn #name() #ret {
+ tokio::runtime::Runtime::new().unwrap().block_on(async { #body })
+ }
+ },
+ RuntimeType::Single | RuntimeType::Auto => quote! {
+ #[test]
+ #(#attrs)*
+ fn #name() #ret {
+ tokio::runtime::current_thread::Runtime::new().unwrap().block_on(async { #body })
+ }
+ },
};
result.into()