Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Add async test helper to timeout and provide a task_executor automatically #6651

Merged
30 commits merged into from
Aug 12, 2020
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
476c881
Initial commit
cecton Jul 14, 2020
8117934
Add async test helper to timeout and provide a task_executor automati…
cecton Jul 14, 2020
ce5ea42
Merge commit 056879f376c46154847927928511c6fd127bef28 (no conflict)
cecton Jul 22, 2020
34c0f23
Merge commit aa36bf284178daaea56399fedf5fcae8b9e282bc (conflicts)
cecton Jul 22, 2020
544c1d2
Merge commit 64d4a4da2a62b59bf4f0212174149c31292b62e7 (no conflict)
cecton Jul 22, 2020
2796798
simplify error message to avoid difference between CI and locally
cecton Jul 22, 2020
a0535f7
forgot env var
cecton Jul 22, 2020
b86cc8e
Use runtime env var instead of build env var
cecton Jul 22, 2020
6b2f66f
Rename variable to SUBSTRATE_TEST_TIMEOUT
cecton Jul 22, 2020
2a47de6
CLEANUP
cecton Jul 22, 2020
24a165b
Apply suggestions from code review
cecton Jul 22, 2020
0507b2f
Merge commit edb48cfdd90e2658017e696a33ae566c7e0940a4 (no conflict)
cecton Jul 23, 2020
f173c1c
Re-export from test-utils
cecton Jul 24, 2020
8e45871
Default value to 120
cecton Jul 24, 2020
b7e1b1d
fix wrong crate in ci
cecton Jul 24, 2020
a200f34
Revert "Default value to 120"
cecton Jul 24, 2020
c157c22
Fix version
cecton Aug 6, 2020
d074de0
WIP
cecton Aug 6, 2020
f0c0e7f
WIP
cecton Aug 6, 2020
3a5d4f0
WIP
cecton Aug 6, 2020
40d1804
remove feature flag
cecton Aug 6, 2020
a8c62ff
fix missing dependency
cecton Aug 7, 2020
82ceab0
CLEANUP
cecton Aug 7, 2020
badbec3
fix test
cecton Aug 7, 2020
a9d03e1
Removed autotests=false
cecton Aug 12, 2020
c7c3e52
Some doc...
cecton Aug 12, 2020
78037b8
Apply suggestions from code review
cecton Aug 12, 2020
0587d76
WIP
cecton Aug 12, 2020
e4b9ff1
WIP
cecton Aug 12, 2020
948c64c
Update test-utils/src/lib.rs
bkchr Aug 12, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@ test-linux-stable: &test-linux
script:
# this job runs all tests in former runtime-benchmarks, frame-staking and wasmtime tests
- time cargo test --workspace --locked --release --verbose --features runtime-benchmarks --manifest-path bin/node/cli/Cargo.toml
- WASM_BUILD_NO_COLOR=1 SUBSTRATE_TEST_TIMEOUT=1 time cargo test -p substrate-test-utils --release --verbose --locked -- --ignored timeout
- sccache -s

unleash-check:
Expand Down Expand Up @@ -621,7 +622,7 @@ deploy-kubernetes-alerting-rules:
RULES: .maintain/monitoring/alerting-rules/alerting-rules.yaml
script:
- echo "deploying prometheus alerting rules"
- kubectl -n ${NAMESPACE} patch prometheusrule ${PROMETHEUSRULE}
- kubectl -n ${NAMESPACE} patch prometheusrule ${PROMETHEUSRULE}
--type=merge --patch "$(sed 's/^/ /;1s/^/spec:\n/' ${RULES})"
only:
refs:
Expand Down
32 changes: 32 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -171,9 +171,11 @@ members = [
"primitives/utils",
"primitives/wasm-interface",
"test-utils/client",
"test-utils/derive",
"test-utils/runtime",
"test-utils/runtime/client",
"test-utils/runtime/transaction-pool",
"test-utils/test-crate",
"utils/browser",
"utils/build-script-utils",
"utils/fork-tree",
Expand Down
9 changes: 9 additions & 0 deletions test-utils/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,12 @@ repository = "https://github.com/paritytech/substrate/"

[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

[dependencies]
futures = { version = "0.3.1", features = ["compat"] }
substrate-test-utils-derive = { path = "./derive" }
tokio = { version = "0.2.13", features = ["macros"] }

[dev-dependencies]
sc-service = { path = "../client/service" }
trybuild = { version = "1.0", features = ["diff"] }
16 changes: 16 additions & 0 deletions test-utils/derive/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[package]
name = "substrate-test-utils-derive"
mihir-ghl marked this conversation as resolved.
Show resolved Hide resolved
version = "0.8.0-rc4"
cecton marked this conversation as resolved.
Show resolved Hide resolved
authors = ["Parity Technologies <admin@parity.io>"]
edition = "2018"
license = "Apache-2.0"
homepage = "https://substrate.dev"
repository = "https://github.com/paritytech/substrate/"

[dependencies]
quote = "1.0.6"
syn = { version = "1.0.33", features = ["full"] }
proc-macro-crate = "0.1.4"

[lib]
proc-macro = true
107 changes: 107 additions & 0 deletions test-utils/derive/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
// 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::{Span, TokenStream};
use proc_macro_crate::crate_name;
use quote::quote;
use std::env;

#[proc_macro_attribute]
pub fn test(args: TokenStream, item: TokenStream) -> TokenStream {
impl_test(args, item)
}

fn impl_test(args: TokenStream, item: TokenStream) -> 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 Err(syn::Error::new_spanned(&sig, msg));
}
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 Err(syn::Error::new_spanned(&sig, msg));
}
};

let crate_name = if env::var("CARGO_PKG_NAME").unwrap() == "substrate-test-utils" {
syn::Ident::new("substrate_test_utils", Span::call_site().into())
} else {
let crate_name = crate_name("substrate-test-utils")
.map_err(|e| syn::Error::new_spanned(&sig, e))?;

syn::Ident::new(&crate_name, Span::call_site().into())
};

let header = {
quote! {
#[#crate_name::tokio::test(#(#args)*)]
}
};

let result = quote! {
#header
#(#attrs)*
#vis #sig {
use #crate_name::futures::future::FutureExt;

let #task_executor_name: #task_executor_type = (|fut, _| {
#crate_name::tokio::spawn(fut).map(drop)
})
.into();
let timeout_task = #crate_name::tokio::time::delay_for(
std::time::Duration::from_secs(
std::env::var("SUBSTRATE_TEST_TIMEOUT")
.ok()
.and_then(|x| x.parse().ok())
.unwrap_or(600))
).fuse();
let actual_test_task = async move {
#body
}
.fuse();

#crate_name::futures::pin_mut!(timeout_task, actual_test_task);

#crate_name::futures::select! {
_ = timeout_task => {
panic!("the test took too long");
cecton marked this conversation as resolved.
Show resolved Hide resolved
},
_ = actual_test_task => {},
}
}
};

Ok(result.into())
}
21 changes: 21 additions & 0 deletions test-utils/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,27 @@

//! Test utils

#[doc(hidden)]
pub use futures;
/// Marks async function to be executed by an async runtime and provide a `TaskExecutor`, suitable
/// to test environment.
///
/// # Example
cecton marked this conversation as resolved.
Show resolved Hide resolved
///
/// ```
bkchr marked this conversation as resolved.
Show resolved Hide resolved
/// use tokio; // WARNING: you must have tokio in the dependency of your crate to use this macro!
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// use tokio; // WARNING: you must have tokio in the dependency of your crate to use this macro!

This should be documented in the text above!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done 0587d76

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed typo: e4b9ff1

///
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
///

/// #[substrate_test_utils::test]
/// async fn basic_test(task_executor: TaskExecutor) {
/// assert!(true);
/// // create your node in here and use task_executor
/// // then don't forget to gracefully shutdown your node before exit
/// }
/// ```
pub use substrate_test_utils_derive::test;
bkchr marked this conversation as resolved.
Show resolved Hide resolved
#[doc(hidden)]
pub use tokio;

/// Panic when the vectors are different, without taking the order into account.
///
/// # Examples
Expand Down
16 changes: 16 additions & 0 deletions test-utils/test-crate/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[package]
name = "substrate-test-utils-test-crate"
version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
edition = "2018"
license = "Apache-2.0"
homepage = "https://substrate.dev"
repository = "https://github.com/paritytech/substrate/"

[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

[dev-dependencies]
tokio = { version = "0.2.13", features = ["macros"] }
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bkchr I made this test-crate to check if it worked but I found out that tokio relies on the extern name tokio. The rest is fine and working though. I inspired my code from what you provided but I simplified a bit.

(I have not done the generate_crate_access yet!)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure what generate_crate_access is doing/solving. Do you have a small & quick explanation?

test-utils = { path = "..", package = "substrate-test-utils" }
sc-service = { path = "../../client/service" }
25 changes: 25 additions & 0 deletions test-utils/test-crate/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// 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/>.

#[cfg(test)]
#[test_utils::test]
async fn basic_test(_: sc_service::TaskExecutor) {
assert!(true);
}

fn main() {}
58 changes: 58 additions & 0 deletions test-utils/tests/basic.rs
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::test]
async fn basic_test(_: TaskExecutor) {
assert!(true);
}

#[substrate_test_utils::test]
#[should_panic(expected = "boo!")]
async fn panicking_test(_: TaskExecutor) {
panic!("boo!");
}

#[substrate_test_utils::test(max_threads = 2)]
async fn basic_test_with_args(_: TaskExecutor) {
assert!(true);
}

#[substrate_test_utils::test]
async fn rename_argument(ex: TaskExecutor) {
let ex2 = ex.clone();
ex2.spawn(Box::pin(async { () }), TaskType::Blocking);
assert!(true);
}

#[substrate_test_utils::test]
#[should_panic(expected = "test took too long")]
// NOTE: enable this test only after setting SUBSTRATE_TEST_TIMEOUT to a smaller value
//
// SUBSTRATE_TEST_TIMEOUT=1 cargo test -- --ignored timeout
#[ignore]
async fn timeout(_: TaskExecutor) {
tokio::time::delay_for(std::time::Duration::from_secs(
std::env::var("SUBSTRATE_TEST_TIMEOUT")
.expect("env var SUBSTRATE_TEST_TIMEOUT has been provided by the user")
.parse::<u64>()
.unwrap() + 1,
))
.await;
}
24 changes: 24 additions & 0 deletions test-utils/tests/ui.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/>.

#[test]
fn substrate_test_utils_derive_trybuild() {
let t = trybuild::TestCases::new();
t.compile_fail("tests/ui/missing-func-parameter.rs");
t.compile_fail("tests/ui/too-many-func-parameters.rs");
}
24 changes: 24 additions & 0 deletions test-utils/tests/ui/missing-func-parameter.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::test]
async fn missing_func_parameter() {
assert!(true);
}

fn main() {}
Loading