-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Add async test helper to timeout and provide a task_executor automatically #6651
Changes from 7 commits
476c881
8117934
ce5ea42
34c0f23
544c1d2
2796798
a0535f7
b86cc8e
6b2f66f
2a47de6
24a165b
0507b2f
f173c1c
8e45871
b7e1b1d
a200f34
c157c22
d074de0
f0c0e7f
3a5d4f0
40d1804
a8c62ff
82ceab0
badbec3
a9d03e1
c7c3e52
78037b8
0587d76
e4b9ff1
948c64c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| [package] | ||
| name = "substrate-test-utils-derive" | ||
| version = "0.8.0-rc4" | ||
cecton marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| authors = ["Parity Technologies <[email protected]>"] | ||
| edition = "2018" | ||
| license = "Apache-2.0" | ||
| homepage = "https://substrate.dev" | ||
| repository = "https://github.com/paritytech/substrate/" | ||
| autotests = false | ||
|
|
||
| [dependencies] | ||
| quote = "1" | ||
gnunicorn marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| syn = { version = "1", default-features = false } | ||
gnunicorn marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| [dev-dependencies] | ||
| tokio = { version = "0.2.13", features = ["macros"] } | ||
| futures = { version = "0.3.1", features = ["compat"] } | ||
| sc-service = { path = "../../client/service" } | ||
| trybuild = { version = "1.0", features = ["diff"] } | ||
|
|
||
| [lib] | ||
| proc-macro = true | ||
|
|
||
| [[test]] | ||
| name = "basic" | ||
| path = "tests/basic.rs" | ||
|
|
||
| [[test]] | ||
| name = "errors" | ||
| path = "tests/errors.rs" | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,101 @@ | ||
| // This file is part of Substrate. | ||
|
|
||
| // Copyright (C) 2020 Parity Technologies (UK) Ltd. | ||
| // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 | ||
|
|
||
| // This program is free software: you can redistribute it and/or modify | ||
| // it under the terms of the GNU General Public License as published by | ||
| // the Free Software Foundation, either version 3 of the License, or | ||
| // (at your option) any later version. | ||
|
|
||
| // This program is distributed in the hope that it will be useful, | ||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| // GNU General Public License for more details. | ||
|
|
||
| // You should have received a copy of the GNU General Public License | ||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. | ||
|
|
||
| use proc_macro::TokenStream; | ||
| use quote::quote; | ||
|
|
||
| #[proc_macro_attribute] | ||
| pub fn test( | ||
| args: proc_macro::TokenStream, | ||
| item: proc_macro::TokenStream, | ||
|
||
| ) -> proc_macro::TokenStream { | ||
| impl_test(args, item) | ||
| } | ||
|
|
||
| fn impl_test( | ||
| args: proc_macro::TokenStream, | ||
| item: proc_macro::TokenStream, | ||
| ) -> proc_macro::TokenStream { | ||
| let input = syn::parse_macro_input!(item as syn::ItemFn); | ||
| let args = syn::parse_macro_input!(args as syn::AttributeArgs); | ||
|
|
||
| parse_knobs(input, args).unwrap_or_else(|e| e.to_compile_error().into()) | ||
| } | ||
|
|
||
| fn parse_knobs( | ||
| mut input: syn::ItemFn, | ||
| args: syn::AttributeArgs, | ||
| ) -> Result<TokenStream, syn::Error> { | ||
| let sig = &mut input.sig; | ||
| let body = &input.block; | ||
| let attrs = &input.attrs; | ||
| let vis = input.vis; | ||
|
|
||
| if sig.inputs.len() != 1 { | ||
| let msg = "the test function accepts only one argument of type sc_service::TaskExecutor"; | ||
| return Ok(syn::Error::new_spanned(&sig, msg).to_compile_error().into()); | ||
cecton marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
| let (task_executor_name, task_executor_type) = match sig.inputs.pop().map(|x| x.into_value()) { | ||
| Some(syn::FnArg::Typed(x)) => (x.pat, x.ty), | ||
| _ => { | ||
| let msg = | ||
| "the test function accepts only one argument of type sc_service::TaskExecutor"; | ||
| return Ok(syn::Error::new_spanned(&sig, msg).to_compile_error().into()); | ||
cecton marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
| }; | ||
|
|
||
| let header = { | ||
| quote! { | ||
| #[tokio::test(#(#args)*)] | ||
| } | ||
| }; | ||
|
|
||
| let result = quote! { | ||
| #header | ||
| #(#attrs)* | ||
| #vis #sig { | ||
| use futures::future::FutureExt; | ||
|
||
|
|
||
| let #task_executor_name: #task_executor_type = (|fut, _| { | ||
| tokio::spawn(fut).map(drop) | ||
| }) | ||
| .into(); | ||
| let timeout_task = tokio::time::delay_for( | ||
| std::time::Duration::from_secs( | ||
| option_env!("INTEGRATION_TEST_ALLOWED_TIME") | ||
gnunicorn marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
gnunicorn marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| .and_then(|x| x.parse().ok()) | ||
| .unwrap_or(600)) | ||
| ).fuse(); | ||
| let actual_test_task = async move { | ||
| #body | ||
| } | ||
| .fuse(); | ||
|
|
||
| futures::pin_mut!(timeout_task, actual_test_task); | ||
|
|
||
| futures::select! { | ||
| _ = timeout_task => { | ||
| panic!("the test took too long"); | ||
cecton marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| }, | ||
| _ = actual_test_task => {}, | ||
| } | ||
| } | ||
| }; | ||
|
|
||
| Ok(result.into()) | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,58 @@ | ||
| // This file is part of Substrate. | ||
|
|
||
| // Copyright (C) 2020 Parity Technologies (UK) Ltd. | ||
| // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 | ||
|
|
||
| // This program is free software: you can redistribute it and/or modify | ||
| // it under the terms of the GNU General Public License as published by | ||
| // the Free Software Foundation, either version 3 of the License, or | ||
| // (at your option) any later version. | ||
|
|
||
| // This program is distributed in the hope that it will be useful, | ||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| // GNU General Public License for more details. | ||
|
|
||
| // You should have received a copy of the GNU General Public License | ||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. | ||
|
|
||
| use sc_service::{TaskExecutor, TaskType}; | ||
|
|
||
| #[substrate_test_utils_derive::test] | ||
| async fn basic_test(_: TaskExecutor) { | ||
| assert!(true); | ||
| } | ||
|
|
||
| #[substrate_test_utils_derive::test] | ||
| #[should_panic(expected = "boo!")] | ||
| async fn panicking_test(_: TaskExecutor) { | ||
| panic!("boo!"); | ||
| } | ||
|
|
||
| #[substrate_test_utils_derive::test(max_threads = 2)] | ||
| async fn basic_test_with_args(_: TaskExecutor) { | ||
| assert!(true); | ||
| } | ||
|
|
||
| #[substrate_test_utils_derive::test] | ||
| async fn rename_argument(ex: TaskExecutor) { | ||
| let ex2 = ex.clone(); | ||
| ex2.spawn(Box::pin(async { () }), TaskType::Blocking); | ||
| assert!(true); | ||
| } | ||
|
|
||
| #[substrate_test_utils_derive::test] | ||
| #[should_panic(expected = "test took too long")] | ||
| // NOTE: enable this test only after setting INTEGRATION_TEST_ALLOWED_TIME to a smaller value | ||
| // | ||
| // INTEGRATION_TEST_ALLOWED_TIME=1 cargo test -- --ignored timeout | ||
| #[ignore] | ||
| async fn timeout(_: TaskExecutor) { | ||
| tokio::time::delay_for(std::time::Duration::from_secs( | ||
| option_env!("INTEGRATION_TEST_ALLOWED_TIME") | ||
| .expect("env var INTEGRATION_TEST_ALLOWED_TIME has been provided by the user") | ||
| .parse::<u64>() | ||
| .unwrap() + 1, | ||
| )) | ||
| .await; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| // This file is part of Substrate. | ||
|
|
||
| // Copyright (C) 2020 Parity Technologies (UK) Ltd. | ||
| // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 | ||
|
|
||
| // This program is free software: you can redistribute it and/or modify | ||
| // it under the terms of the GNU General Public License as published by | ||
| // the Free Software Foundation, either version 3 of the License, or | ||
| // (at your option) any later version. | ||
|
|
||
| // This program is distributed in the hope that it will be useful, | ||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| // GNU General Public License for more details. | ||
|
|
||
| // You should have received a copy of the GNU General Public License | ||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. | ||
|
|
||
| #[test] | ||
| fn substrate_test_utils_derive_trybuild() { | ||
| let t = trybuild::TestCases::new(); | ||
| t.compile_fail("tests/missing-func-parameter.rs"); | ||
| t.compile_fail("tests/too-many-func-parameters.rs"); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| // This file is part of Substrate. | ||
|
|
||
| // Copyright (C) 2020 Parity Technologies (UK) Ltd. | ||
| // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 | ||
|
|
||
| // This program is free software: you can redistribute it and/or modify | ||
| // it under the terms of the GNU General Public License as published by | ||
| // the Free Software Foundation, either version 3 of the License, or | ||
| // (at your option) any later version. | ||
|
|
||
| // This program is distributed in the hope that it will be useful, | ||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| // GNU General Public License for more details. | ||
|
|
||
| // You should have received a copy of the GNU General Public License | ||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. | ||
|
|
||
| #[substrate_test_utils_derive::test] | ||
| async fn missing_func_parameter() { | ||
| assert!(true); | ||
| } | ||
|
|
||
| fn main() {} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| error: the test function accepts only one argument of type sc_service::TaskExecutor | ||
| --> $DIR/missing-func-parameter.rs:20:1 | ||
| | | ||
| 20 | async fn missing_func_parameter() { | ||
| | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| // This file is part of Substrate. | ||
|
|
||
| // Copyright (C) 2020 Parity Technologies (UK) Ltd. | ||
| // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 | ||
|
|
||
| // This program is free software: you can redistribute it and/or modify | ||
| // it under the terms of the GNU General Public License as published by | ||
| // the Free Software Foundation, either version 3 of the License, or | ||
| // (at your option) any later version. | ||
|
|
||
| // This program is distributed in the hope that it will be useful, | ||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| // GNU General Public License for more details. | ||
|
|
||
| // You should have received a copy of the GNU General Public License | ||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. | ||
|
|
||
| #[allow(unused_imports)] | ||
| use sc_service::TaskExecutor; | ||
|
|
||
| #[substrate_test_utils_derive::test] | ||
| async fn too_many_func_parameters(task_executor_1: TaskExecutor, task_executor_2: TaskExecutor) { | ||
| assert!(true); | ||
| } | ||
|
|
||
| fn main() {} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| error: the test function accepts only one argument of type sc_service::TaskExecutor | ||
| --> $DIR/too-many-func-parameters.rs:23:1 | ||
| | | ||
| 23 | async fn too_many_func_parameters(task_executor_1: TaskExecutor, task_executor_2: TaskExecutor) { | ||
| | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
Uh oh!
There was an error while loading. Please reload this page.