From 649a3030cd64ed0e46ef7a35e456f670792af529 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Mon, 27 Mar 2023 21:33:42 +0300 Subject: [PATCH 01/13] testing: Baseline Signed-off-by: Alexandru Vasile --- testing/integration-tests/src/utils/node_proc.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/testing/integration-tests/src/utils/node_proc.rs b/testing/integration-tests/src/utils/node_proc.rs index 717e99aefd..8c1fc88c3f 100644 --- a/testing/integration-tests/src/utils/node_proc.rs +++ b/testing/integration-tests/src/utils/node_proc.rs @@ -45,6 +45,7 @@ where tracing::error!("{}", err); return Err(err); } + Ok(()) } From dca6252217ce73c4f39e4abc8f13b621af9d5518 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Mon, 27 Mar 2023 21:17:09 +0300 Subject: [PATCH 02/13] tests: Cache metadata and runtime version between runs Signed-off-by: Alexandru Vasile --- Cargo.lock | 1 + testing/integration-tests/Cargo.toml | 1 + .../integration-tests/src/utils/node_proc.rs | 71 ++++++++++++++++++- 3 files changed, 71 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7d4e821a7f..3b10629386 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1540,6 +1540,7 @@ dependencies = [ "frame-metadata", "futures", "hex", + "lazy_static", "parity-scale-codec", "regex", "scale-info", diff --git a/testing/integration-tests/Cargo.toml b/testing/integration-tests/Cargo.toml index f4f14b72b6..418f372a98 100644 --- a/testing/integration-tests/Cargo.toml +++ b/testing/integration-tests/Cargo.toml @@ -35,3 +35,4 @@ tracing = "0.1.34" tracing-subscriber = "0.3.11" wabt = "0.10.0" which = "4.4.0" +lazy_static = "1.4.0" diff --git a/testing/integration-tests/src/utils/node_proc.rs b/testing/integration-tests/src/utils/node_proc.rs index 8c1fc88c3f..6e77827db5 100644 --- a/testing/integration-tests/src/utils/node_proc.rs +++ b/testing/integration-tests/src/utils/node_proc.rs @@ -2,13 +2,20 @@ // This file is dual-licensed as Apache-2.0 or GPL-3.0. // see LICENSE for license details. +use futures::future; +use lazy_static::lazy_static; use sp_keyring::AccountKeyring; use std::{ ffi::{OsStr, OsString}, io::{BufRead, BufReader, Read}, process, + sync::{Arc, Mutex}, +}; +use subxt::{ + client::default_rpc_client, + rpc::{types::RuntimeVersion, Rpc}, + Config, Metadata, OnlineClient, SubstrateConfig, }; -use subxt::{Config, OnlineClient}; /// Spawn a local substrate node for testing subxt. pub struct TestNodeProcess { @@ -78,6 +85,58 @@ impl TestNodeProcessBuilder { self } + async fn fetch_cache_data(ws_url: String) -> Result<(RuntimeVersion, Metadata), String> { + let rpc_client = default_rpc_client(ws_url) + .await + .map_err(|err| format!("Cannot build default rpc client: {:?}", err))?; + + let rpc = Rpc::::new(Arc::new(rpc_client)); + + let (runtime_version, metadata) = + future::join(rpc.runtime_version(None), rpc.metadata(None)).await; + Ok(( + runtime_version.map_err(|err| format!("Cannot fetch runtime version: {:?}", err))?, + metadata.map_err(|err| format!("Cannot fetch metadata {:?}", err))?, + )) + } + + async fn get_cache( + ws_url: String, + ) -> Result<(R::Hash, RuntimeVersion, Metadata), String> { + lazy_static! { + // Cannot place the `::Hash` associated type from the outer function into the static mutex cache. + static ref CACHE: Mutex> = Mutex::new(None); + } + + let mut cache = CACHE + .lock() + .map_err(|err| format!("Cannot lock cache data: {:?}", err))?; + + let rpc_client = default_rpc_client(ws_url.clone()) + .await + .expect("Cannot build default rpc client"); + + let rpc = Rpc::::new(Arc::new(rpc_client)); + + // Fetch the genesis hash to avoid a `mem::transmute`, or to limit the `TestNodeProcess` to `SubstrateConfig` only. + let genesis = rpc + .genesis_hash() + .await + .map_err(|err| format!("Cannot fetch genesis: {:?}", err))?; + + match &mut *cache { + Some((runtime, metadata)) => Ok((genesis, runtime.clone(), metadata.clone())), + None => { + let (runtime_version, metadata) = + TestNodeProcessBuilder::fetch_cache_data(ws_url).await?; + + *cache = Some((runtime_version.clone(), metadata.clone())); + + Ok((genesis, runtime_version, metadata)) + } + } + } + /// Spawn the substrate node at the given path, and wait for rpc to be initialized. pub async fn spawn(&self) -> Result, String> where @@ -112,8 +171,16 @@ impl TestNodeProcessBuilder { let ws_port = find_substrate_port_from_output(stderr); let ws_url = format!("ws://127.0.0.1:{ws_port}"); + let (genesis, runtime, metadata) = + TestNodeProcessBuilder::get_cache::(ws_url.clone()).await?; + + let rpc_client = default_rpc_client(ws_url.clone()) + .await + .map_err(|err| err.to_string())?; + // Connect to the node with a subxt client: - let client = OnlineClient::from_url(ws_url.clone()).await; + let client = + OnlineClient::from_rpc_client_with(genesis, runtime, metadata, Arc::new(rpc_client)); match client { Ok(client) => Ok(TestNodeProcess { proc, client }), Err(err) => { From f227a33f4b8d9f02e3272c0161710c7f26f37ed0 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Mon, 27 Mar 2023 22:28:12 +0300 Subject: [PATCH 03/13] testing: Async-aware mutex Signed-off-by: Alexandru Vasile --- testing/integration-tests/src/utils/node_proc.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/testing/integration-tests/src/utils/node_proc.rs b/testing/integration-tests/src/utils/node_proc.rs index 6e77827db5..e2288aad5d 100644 --- a/testing/integration-tests/src/utils/node_proc.rs +++ b/testing/integration-tests/src/utils/node_proc.rs @@ -9,13 +9,14 @@ use std::{ ffi::{OsStr, OsString}, io::{BufRead, BufReader, Read}, process, - sync::{Arc, Mutex}, + sync::Arc, }; use subxt::{ client::default_rpc_client, rpc::{types::RuntimeVersion, Rpc}, Config, Metadata, OnlineClient, SubstrateConfig, }; +use tokio::sync::Mutex; /// Spawn a local substrate node for testing subxt. pub struct TestNodeProcess { @@ -108,9 +109,7 @@ impl TestNodeProcessBuilder { static ref CACHE: Mutex> = Mutex::new(None); } - let mut cache = CACHE - .lock() - .map_err(|err| format!("Cannot lock cache data: {:?}", err))?; + let mut cache = CACHE.lock().await; let rpc_client = default_rpc_client(ws_url.clone()) .await From ff81fae37cd72a5c038822d838071b2d236588e4 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Tue, 28 Mar 2023 15:01:21 +0300 Subject: [PATCH 04/13] testing: Use `SubstrateConfig` as default for testing Signed-off-by: Alexandru Vasile --- .../integration-tests/src/utils/context.rs | 4 +- .../integration-tests/src/utils/node_proc.rs | 91 ++++++++----------- 2 files changed, 40 insertions(+), 55 deletions(-) diff --git a/testing/integration-tests/src/utils/context.rs b/testing/integration-tests/src/utils/context.rs index 980295269f..8144916884 100644 --- a/testing/integration-tests/src/utils/context.rs +++ b/testing/integration-tests/src/utils/context.rs @@ -24,12 +24,12 @@ pub async fn test_context_with(key: AccountKeyring) -> TestContext { let proc = TestContext::build(path.as_str()) .with_authority(key) - .spawn::() + .spawn() .await; proc.unwrap() } -pub type TestContext = TestNodeProcess; +pub type TestContext = TestNodeProcess; pub async fn test_context() -> TestContext { test_context_with(AccountKeyring::Alice).await diff --git a/testing/integration-tests/src/utils/node_proc.rs b/testing/integration-tests/src/utils/node_proc.rs index e2288aad5d..0344fc5ae7 100644 --- a/testing/integration-tests/src/utils/node_proc.rs +++ b/testing/integration-tests/src/utils/node_proc.rs @@ -13,30 +13,24 @@ use std::{ }; use subxt::{ client::default_rpc_client, - rpc::{types::RuntimeVersion, Rpc}, + rpc::{types::RuntimeVersion, Rpc, RpcClientT}, Config, Metadata, OnlineClient, SubstrateConfig, }; use tokio::sync::Mutex; /// Spawn a local substrate node for testing subxt. -pub struct TestNodeProcess { +pub struct TestNodeProcess { proc: process::Child, - client: OnlineClient, + client: OnlineClient, } -impl Drop for TestNodeProcess -where - R: Config, -{ +impl Drop for TestNodeProcess { fn drop(&mut self) { let _ = self.kill(); } } -impl TestNodeProcess -where - R: Config, -{ +impl TestNodeProcess { /// Construct a builder for spawning a test node process. pub fn build(program: S) -> TestNodeProcessBuilder where @@ -58,7 +52,7 @@ where } /// Returns the subxt client connected to the running node. - pub fn client(&self) -> OnlineClient { + pub fn client(&self) -> OnlineClient { self.client.clone() } } @@ -86,50 +80,43 @@ impl TestNodeProcessBuilder { self } - async fn fetch_cache_data(ws_url: String) -> Result<(RuntimeVersion, Metadata), String> { - let rpc_client = default_rpc_client(ws_url) - .await - .map_err(|err| format!("Cannot build default rpc client: {:?}", err))?; - - let rpc = Rpc::::new(Arc::new(rpc_client)); - - let (runtime_version, metadata) = - future::join(rpc.runtime_version(None), rpc.metadata(None)).await; + async fn fetch_cache_data( + rpc_client: Arc, + ) -> Result<(::Hash, RuntimeVersion, Metadata), String> { + let rpc = Rpc::::new(rpc_client); + + let (genesis_hash, runtime_version, metadata) = future::join3( + rpc.genesis_hash(), + rpc.runtime_version(None), + rpc.metadata(None), + ) + .await; Ok(( + genesis_hash.map_err(|err| format!("Cannot fetch genesis: {:?}", err))?, runtime_version.map_err(|err| format!("Cannot fetch runtime version: {:?}", err))?, metadata.map_err(|err| format!("Cannot fetch metadata {:?}", err))?, )) } - async fn get_cache( - ws_url: String, - ) -> Result<(R::Hash, RuntimeVersion, Metadata), String> { + async fn get_cache( + rpc_client: Arc, + ) -> Result<(::Hash, RuntimeVersion, Metadata), String> { lazy_static! { - // Cannot place the `::Hash` associated type from the outer function into the static mutex cache. - static ref CACHE: Mutex> = Mutex::new(None); + static ref CACHE: Mutex::Hash, RuntimeVersion, Metadata)>> = + Mutex::new(None); } let mut cache = CACHE.lock().await; - let rpc_client = default_rpc_client(ws_url.clone()) - .await - .expect("Cannot build default rpc client"); - - let rpc = Rpc::::new(Arc::new(rpc_client)); - - // Fetch the genesis hash to avoid a `mem::transmute`, or to limit the `TestNodeProcess` to `SubstrateConfig` only. - let genesis = rpc - .genesis_hash() - .await - .map_err(|err| format!("Cannot fetch genesis: {:?}", err))?; - match &mut *cache { - Some((runtime, metadata)) => Ok((genesis, runtime.clone(), metadata.clone())), + Some((genesis, runtime, metadata)) => { + Ok((genesis.clone(), runtime.clone(), metadata.clone())) + } None => { - let (runtime_version, metadata) = - TestNodeProcessBuilder::fetch_cache_data(ws_url).await?; + let (genesis, runtime_version, metadata) = + TestNodeProcessBuilder::fetch_cache_data(rpc_client).await?; - *cache = Some((runtime_version.clone(), metadata.clone())); + *cache = Some((genesis.clone(), runtime_version.clone(), metadata.clone())); Ok((genesis, runtime_version, metadata)) } @@ -137,10 +124,7 @@ impl TestNodeProcessBuilder { } /// Spawn the substrate node at the given path, and wait for rpc to be initialized. - pub async fn spawn(&self) -> Result, String> - where - R: Config, - { + pub async fn spawn(&self) -> Result { let mut cmd = process::Command::new(&self.node_path); cmd.env("RUST_LOG", "info") .arg("--dev") @@ -170,16 +154,17 @@ impl TestNodeProcessBuilder { let ws_port = find_substrate_port_from_output(stderr); let ws_url = format!("ws://127.0.0.1:{ws_port}"); - let (genesis, runtime, metadata) = - TestNodeProcessBuilder::get_cache::(ws_url.clone()).await?; + let rpc_client = Arc::new( + default_rpc_client(ws_url.clone()) + .await + .map_err(|err| err.to_string())?, + ); - let rpc_client = default_rpc_client(ws_url.clone()) - .await - .map_err(|err| err.to_string())?; + let (genesis, runtime, metadata) = + TestNodeProcessBuilder::get_cache(rpc_client.clone()).await?; // Connect to the node with a subxt client: - let client = - OnlineClient::from_rpc_client_with(genesis, runtime, metadata, Arc::new(rpc_client)); + let client = OnlineClient::from_rpc_client_with(genesis, runtime, metadata, rpc_client); match client { Ok(client) => Ok(TestNodeProcess { proc, client }), Err(err) => { From 641e1e3cf728e63e5dd33fdad4a19be4ed801a3f Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Tue, 28 Mar 2023 15:17:16 +0300 Subject: [PATCH 05/13] testing: Implement `TestContextShared` for shared substrate binaries Signed-off-by: Alexandru Vasile --- .../integration-tests/src/utils/context.rs | 46 +++++++++++++++++-- 1 file changed, 42 insertions(+), 4 deletions(-) diff --git a/testing/integration-tests/src/utils/context.rs b/testing/integration-tests/src/utils/context.rs index 8144916884..c2166869a9 100644 --- a/testing/integration-tests/src/utils/context.rs +++ b/testing/integration-tests/src/utils/context.rs @@ -3,14 +3,18 @@ // see LICENSE for license details. pub(crate) use crate::{node_runtime, TestNodeProcess}; - +use futures::lock::Mutex; +use lazy_static::lazy_static; use sp_core::sr25519::Pair; use sp_keyring::AccountKeyring; -use subxt::{tx::PairSigner, SubstrateConfig}; +use subxt::{tx::PairSigner, OnlineClient, SubstrateConfig}; /// substrate node should be installed on the $PATH const SUBSTRATE_NODE_PATH: &str = "substrate"; +/// Test context that spawns a dedicated substrate binary. +pub type TestContext = TestNodeProcess; + pub async fn test_context_with(key: AccountKeyring) -> TestContext { let path = std::env::var("SUBSTRATE_NODE_PATH").unwrap_or_else(|_| { if which::which(SUBSTRATE_NODE_PATH).is_err() { @@ -29,12 +33,46 @@ pub async fn test_context_with(key: AccountKeyring) -> TestContext { proc.unwrap() } -pub type TestContext = TestNodeProcess; - +/// Create a test context that spawns a dedicated substrate binary. pub async fn test_context() -> TestContext { test_context_with(AccountKeyring::Alice).await } +/// Test context that shares a single substrate binary. +pub struct TestContextShared { + client: OnlineClient, +} + +impl TestContextShared { + /// Returns the subxt client connected to the running node. + pub fn client(&self) -> OnlineClient { + self.client.clone() + } +} + +/// Create a test context that shares the substrate binary. +pub async fn test_context_shared() -> TestContextShared { + lazy_static! { + static ref CACHE: Mutex> = Mutex::new(None); + } + + let mut cache = CACHE.lock().await; + match &mut *cache { + Some(test_context) => TestContextShared { + client: test_context.client(), + }, + None => { + let test_context = test_context_with(AccountKeyring::Alice).await; + let shared = TestContextShared { + client: test_context.client(), + }; + + *cache = Some(test_context); + shared + } + } +} + pub fn pair_signer(pair: Pair) -> PairSigner { PairSigner::new(pair) } From f8d9a40f91664f31232d66bc772c11c14016f3b8 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Tue, 28 Mar 2023 18:18:02 +0300 Subject: [PATCH 06/13] testing: Shared substrate binary for testing Signed-off-by: Alexandru Vasile --- subxt/src/rpc/rpc_client.rs | 2 +- testing/integration-tests/src/blocks/mod.rs | 20 ++--- testing/integration-tests/src/client/mod.rs | 84 +++++++++---------- .../integration-tests/src/frame/balances.rs | 22 ++--- .../integration-tests/src/frame/staking.rs | 34 ++++---- testing/integration-tests/src/frame/sudo.rs | 17 ++-- testing/integration-tests/src/frame/system.rs | 10 +-- .../integration-tests/src/frame/timestamp.rs | 6 +- .../src/metadata/validation.rs | 27 +++--- testing/integration-tests/src/storage/mod.rs | 14 ++-- .../integration-tests/src/utils/context.rs | 27 ++++-- .../integration-tests/src/utils/node_proc.rs | 20 +++-- 12 files changed, 148 insertions(+), 135 deletions(-) diff --git a/subxt/src/rpc/rpc_client.rs b/subxt/src/rpc/rpc_client.rs index a23483258c..2d89e7c8cf 100644 --- a/subxt/src/rpc/rpc_client.rs +++ b/subxt/src/rpc/rpc_client.rs @@ -9,7 +9,7 @@ use serde::{de::DeserializeOwned, Serialize}; use serde_json::value::RawValue; use std::{pin::Pin, sync::Arc, task::Poll}; -/// A concrete wrapper around an [`RpcClientT`] which exposes the udnerlying interface via some +/// A concrete wrapper around an [`RpcClientT`] which exposes the underlying interface via some /// higher level methods that make it a little easier to work with. /// /// Wrapping [`RpcClientT`] in this way is simply a way to expose this additional functionality diff --git a/testing/integration-tests/src/blocks/mod.rs b/testing/integration-tests/src/blocks/mod.rs index ae25594d76..1db2bfa2ea 100644 --- a/testing/integration-tests/src/blocks/mod.rs +++ b/testing/integration-tests/src/blocks/mod.rs @@ -2,7 +2,7 @@ // This file is dual-licensed as Apache-2.0 or GPL-3.0. // see LICENSE for license details. -use crate::test_context; +use crate::test_context_shared; use codec::{Compact, Decode}; use frame_metadata::RuntimeMetadataPrefixed; use futures::StreamExt; @@ -10,8 +10,8 @@ use futures::StreamExt; // Check that we can subscribe to non-finalized blocks. #[tokio::test] async fn non_finalized_headers_subscription() -> Result<(), subxt::Error> { - let ctx = test_context().await; - let api = ctx.client(); + let ctx = test_context_shared().await; + let api = ctx.client().await; let mut sub = api.blocks().subscribe_best().await?; @@ -29,8 +29,8 @@ async fn non_finalized_headers_subscription() -> Result<(), subxt::Error> { // Check that we can subscribe to finalized blocks. #[tokio::test] async fn finalized_headers_subscription() -> Result<(), subxt::Error> { - let ctx = test_context().await; - let api = ctx.client(); + let ctx = test_context_shared().await; + let api = ctx.client().await; let mut sub = api.blocks().subscribe_finalized().await?; @@ -46,8 +46,8 @@ async fn finalized_headers_subscription() -> Result<(), subxt::Error> { #[tokio::test] async fn missing_block_headers_will_be_filled_in() -> Result<(), subxt::Error> { - let ctx = test_context().await; - let api = ctx.client(); + let ctx = test_context_shared().await; + let api = ctx.client().await; // Manually subscribe to the next 6 finalized block headers, but deliberately // filter out some in the middle so we get back b _ _ b _ b. This guarantees @@ -66,7 +66,7 @@ async fn missing_block_headers_will_be_filled_in() -> Result<(), subxt::Error> { // This should spot any gaps in the middle and fill them back in. let all_finalized_blocks = subxt::blocks::subscribe_to_block_headers_filling_in_gaps( - ctx.client(), + ctx.client().await, None, some_finalized_blocks, ); @@ -93,8 +93,8 @@ async fn missing_block_headers_will_be_filled_in() -> Result<(), subxt::Error> { // Check that we can subscribe to non-finalized blocks. #[tokio::test] async fn runtime_api_call() -> Result<(), subxt::Error> { - let ctx = test_context().await; - let api = ctx.client(); + let ctx = test_context_shared().await; + let api = ctx.client().await; let mut sub = api.blocks().subscribe_best().await?; diff --git a/testing/integration-tests/src/client/mod.rs b/testing/integration-tests/src/client/mod.rs index 0baf465a92..24aab0a049 100644 --- a/testing/integration-tests/src/client/mod.rs +++ b/testing/integration-tests/src/client/mod.rs @@ -3,7 +3,7 @@ // see LICENSE for license details. use crate::{ - pair_signer, test_context, test_context_with, + pair_signer, test_context, test_context_shared, test_context_with, utils::{node_runtime, wait_for_blocks}, }; use assert_matches::assert_matches; @@ -45,14 +45,14 @@ async fn insert_key() { #[tokio::test] async fn fetch_block_hash() { - let ctx = test_context().await; - ctx.client().rpc().block_hash(None).await.unwrap(); + let ctx = test_context_shared().await; + ctx.client().await.rpc().block_hash(None).await.unwrap(); } #[tokio::test] async fn fetch_block() { - let ctx = test_context().await; - let api = ctx.client(); + let ctx = test_context_shared().await; + let api = ctx.client().await; let block_hash = api.rpc().block_hash(None).await.unwrap(); api.rpc().block(block_hash).await.unwrap(); @@ -60,8 +60,8 @@ async fn fetch_block() { #[tokio::test] async fn fetch_read_proof() { - let ctx = test_context().await; - let api = ctx.client(); + let ctx = test_context_shared().await; + let api = ctx.client().await; let block_hash = api.rpc().block_hash(None).await.unwrap(); api.rpc() @@ -78,8 +78,8 @@ async fn fetch_read_proof() { #[tokio::test] async fn chain_subscribe_all_blocks() { - let ctx = test_context().await; - let api = ctx.client(); + let ctx = test_context_shared().await; + let api = ctx.client().await; let mut blocks = api.rpc().subscribe_all_block_headers().await.unwrap(); blocks.next().await.unwrap().unwrap(); @@ -87,8 +87,8 @@ async fn chain_subscribe_all_blocks() { #[tokio::test] async fn chain_subscribe_best_blocks() { - let ctx = test_context().await; - let api = ctx.client(); + let ctx = test_context_shared().await; + let api = ctx.client().await; let mut blocks = api.rpc().subscribe_best_block_headers().await.unwrap(); blocks.next().await.unwrap().unwrap(); @@ -96,8 +96,8 @@ async fn chain_subscribe_best_blocks() { #[tokio::test] async fn chain_subscribe_finalized_blocks() { - let ctx = test_context().await; - let api = ctx.client(); + let ctx = test_context_shared().await; + let api = ctx.client().await; let mut blocks = api.rpc().subscribe_finalized_block_headers().await.unwrap(); blocks.next().await.unwrap().unwrap(); @@ -105,8 +105,8 @@ async fn chain_subscribe_finalized_blocks() { #[tokio::test] async fn fetch_keys() { - let ctx = test_context().await; - let api = ctx.client(); + let ctx = test_context_shared().await; + let api = ctx.client().await; let addr = node_runtime::storage().system().account_root(); let keys = api @@ -122,8 +122,8 @@ async fn fetch_keys() { #[tokio::test] async fn test_iter() { - let ctx = test_context().await; - let api = ctx.client(); + let ctx = test_context_shared().await; + let api = ctx.client().await; let addr = node_runtime::storage().system().account_root(); let mut iter = api @@ -143,8 +143,8 @@ async fn test_iter() { #[tokio::test] async fn fetch_system_info() { - let ctx = test_context().await; - let api = ctx.client(); + let ctx = test_context_shared().await; + let api = ctx.client().await; assert_eq!(api.rpc().system_chain().await.unwrap(), "Development"); assert_eq!(api.rpc().system_name().await.unwrap(), "Substrate Node"); @@ -153,8 +153,8 @@ async fn fetch_system_info() { #[tokio::test] async fn dry_run_passes() { - let ctx = test_context().await; - let api = ctx.client(); + let ctx = test_context_shared().await; + let api = ctx.client().await; let alice = pair_signer(AccountKeyring::Alice.pair()); let bob = pair_signer(AccountKeyring::Bob.pair()); @@ -248,8 +248,8 @@ async fn dry_run_result_is_substrate_compatible() { // We really just connect to a node to get some valid metadata to help us // decode Dispatch Errors. - let ctx = test_context().await; - let api = ctx.client(); + let ctx = test_context_shared().await; + let api = ctx.client().await; let pairs = vec![ // All ok @@ -293,8 +293,8 @@ async fn dry_run_result_is_substrate_compatible() { #[tokio::test] async fn external_signing() { - let ctx = test_context().await; - let api = ctx.client(); + let ctx = test_context_shared().await; + let api = ctx.client().await; let alice = pair_signer(AccountKeyring::Alice.pair()); // Create a partial extrinsic. We can get the signer payload at this point, to be @@ -352,8 +352,8 @@ async fn submit_large_extrinsic() { #[tokio::test] async fn unsigned_extrinsic_is_same_shape_as_polkadotjs() { - let ctx = test_context().await; - let api = ctx.client(); + let ctx = test_context_shared().await; + let api = ctx.client().await; let tx = node_runtime::tx().balances().transfer( pair_signer(AccountKeyring::Alice.pair()) @@ -384,8 +384,8 @@ async fn unsigned_extrinsic_is_same_shape_as_polkadotjs() { #[tokio::test] async fn rpc_state_call() { - let ctx = test_context().await; - let api = ctx.client(); + let ctx = test_context_shared().await; + let api = ctx.client().await; // Call into the runtime of the chain to get the Metadata. let metadata_bytes = api @@ -410,8 +410,8 @@ async fn rpc_state_call() { #[tokio::test] async fn chainhead_unstable_follow() { - let ctx = test_context().await; - let api = ctx.client(); + let ctx = test_context_shared().await; + let api = ctx.client().await; // Check subscription with runtime updates set on false. let mut blocks = api.rpc().chainhead_unstable_follow(false).await.unwrap(); @@ -431,7 +431,7 @@ async fn chainhead_unstable_follow() { let event = blocks.next().await.unwrap().unwrap(); // The initialized event should contain the finalized block hash. let finalized_block_hash = api.rpc().finalized_head().await.unwrap(); - let runtime_version = ctx.client().runtime_version(); + let runtime_version = api.runtime_version(); assert_matches!( event, @@ -446,8 +446,8 @@ async fn chainhead_unstable_follow() { #[tokio::test] async fn chainhead_unstable_body() { - let ctx = test_context().await; - let api = ctx.client(); + let ctx = test_context_shared().await; + let api = ctx.client().await; let mut blocks = api.rpc().chainhead_unstable_follow(false).await.unwrap(); let event = blocks.next().await.unwrap().unwrap(); @@ -477,8 +477,8 @@ async fn chainhead_unstable_body() { #[tokio::test] async fn chainhead_unstable_header() { - let ctx = test_context().await; - let api = ctx.client(); + let ctx = test_context_shared().await; + let api = ctx.client().await; let mut blocks = api.rpc().chainhead_unstable_follow(false).await.unwrap(); let event = blocks.next().await.unwrap().unwrap(); @@ -503,8 +503,8 @@ async fn chainhead_unstable_header() { #[tokio::test] async fn chainhead_unstable_storage() { - let ctx = test_context().await; - let api = ctx.client(); + let ctx = test_context_shared().await; + let api = ctx.client().await; let mut blocks = api.rpc().chainhead_unstable_follow(false).await.unwrap(); let event = blocks.next().await.unwrap().unwrap(); @@ -530,8 +530,8 @@ async fn chainhead_unstable_storage() { #[tokio::test] async fn chainhead_unstable_call() { - let ctx = test_context().await; - let api = ctx.client(); + let ctx = test_context_shared().await; + let api = ctx.client().await; let mut blocks = api.rpc().chainhead_unstable_follow(true).await.unwrap(); let event = blocks.next().await.unwrap().unwrap(); @@ -559,8 +559,8 @@ async fn chainhead_unstable_call() { #[tokio::test] async fn chainhead_unstable_unpin() { - let ctx = test_context().await; - let api = ctx.client(); + let ctx = test_context_shared().await; + let api = ctx.client().await; let mut blocks = api.rpc().chainhead_unstable_follow(true).await.unwrap(); let event = blocks.next().await.unwrap().unwrap(); diff --git a/testing/integration-tests/src/frame/balances.rs b/testing/integration-tests/src/frame/balances.rs index 747f964437..eba1ec6b5d 100644 --- a/testing/integration-tests/src/frame/balances.rs +++ b/testing/integration-tests/src/frame/balances.rs @@ -4,7 +4,7 @@ use crate::{ node_runtime::{self, balances, runtime_types, system}, - pair_signer, test_context, + pair_signer, test_context, test_context_shared, }; use codec::Decode; use sp_core::Pair; @@ -242,8 +242,8 @@ async fn multiple_transfers_work_nonce_incremented() -> Result<(), subxt::Error> #[tokio::test] async fn storage_total_issuance() { - let ctx = test_context().await; - let api = ctx.client(); + let ctx = test_context_shared().await; + let api = ctx.client().await; let addr = node_runtime::storage().balances().total_issuance(); let total_issuance = api @@ -262,8 +262,8 @@ async fn storage_balance_lock() -> Result<(), subxt::Error> { let bob_signer = pair_signer(AccountKeyring::Bob.pair()); let bob: AccountId32 = AccountKeyring::Bob.to_account_id().into(); let charlie: AccountId32 = AccountKeyring::Charlie.to_account_id().into(); - let ctx = test_context().await; - let api = ctx.client(); + let ctx = test_context_shared().await; + let api = ctx.client().await; let tx = node_runtime::tx().staking().bond( charlie.into(), @@ -306,8 +306,8 @@ async fn transfer_error() { let alice_addr = alice.account_id().clone().into(); let hans = pair_signer(Pair::generate().0); let hans_address = hans.account_id().clone().into(); - let ctx = test_context().await; - let api = ctx.client(); + let ctx = test_context_shared().await; + let api = ctx.client().await; let to_hans_tx = node_runtime::tx() .balances() @@ -347,8 +347,8 @@ async fn transfer_error() { async fn transfer_implicit_subscription() { let alice = pair_signer(AccountKeyring::Alice.pair()); let bob: AccountId32 = AccountKeyring::Bob.to_account_id().into(); - let ctx = test_context().await; - let api = ctx.client(); + let ctx = test_context_shared().await; + let api = ctx.client().await; let to_bob_tx = node_runtime::tx() .balances() @@ -378,8 +378,8 @@ async fn transfer_implicit_subscription() { #[tokio::test] async fn constant_existential_deposit() { - let ctx = test_context().await; - let api = ctx.client(); + let ctx = test_context_shared().await; + let api = ctx.client().await; // get and decode constant manually via metadata: let metadata = api.metadata(); diff --git a/testing/integration-tests/src/frame/staking.rs b/testing/integration-tests/src/frame/staking.rs index fa198c4366..e1316f0718 100644 --- a/testing/integration-tests/src/frame/staking.rs +++ b/testing/integration-tests/src/frame/staking.rs @@ -11,7 +11,7 @@ use crate::{ }, staking, }, - pair_signer, test_context, + pair_signer, test_context, test_context_shared, }; use assert_matches::assert_matches; use sp_core::{sr25519, Pair}; @@ -32,8 +32,8 @@ fn default_validator_prefs() -> ValidatorPrefs { #[tokio::test] async fn validate_with_controller_account() { - let ctx = test_context().await; - let api = ctx.client(); + let ctx = test_context_shared().await; + let api = ctx.client().await; let alice = pair_signer(AccountKeyring::Alice.pair()); @@ -52,8 +52,8 @@ async fn validate_with_controller_account() { #[tokio::test] async fn validate_not_possible_for_stash_account() -> Result<(), Error> { - let ctx = test_context().await; - let api = ctx.client(); + let ctx = test_context_shared().await; + let api = ctx.client().await; let alice_stash = pair_signer(get_from_seed("Alice//stash")); @@ -77,8 +77,8 @@ async fn validate_not_possible_for_stash_account() -> Result<(), Error> { #[tokio::test] async fn nominate_with_controller_account() { - let ctx = test_context().await; - let api = ctx.client(); + let ctx = test_context_shared().await; + let api = ctx.client().await; let alice = pair_signer(AccountKeyring::Alice.pair()); let bob = pair_signer(AccountKeyring::Bob.pair()); @@ -98,8 +98,8 @@ async fn nominate_with_controller_account() { #[tokio::test] async fn nominate_not_possible_for_stash_account() -> Result<(), Error> { - let ctx = test_context().await; - let api = ctx.client(); + let ctx = test_context_shared().await; + let api = ctx.client().await; let alice_stash = pair_signer(get_from_seed("Alice//stash")); let bob = pair_signer(AccountKeyring::Bob.pair()); @@ -182,8 +182,8 @@ async fn chill_works_for_controller_only() -> Result<(), Error> { #[tokio::test] async fn tx_bond() -> Result<(), Error> { - let ctx = test_context().await; - let api = ctx.client(); + let ctx = test_context_shared().await; + let api = ctx.client().await; let alice = pair_signer(AccountKeyring::Alice.pair()); @@ -219,8 +219,8 @@ async fn tx_bond() -> Result<(), Error> { #[tokio::test] async fn storage_history_depth() -> Result<(), Error> { - let ctx = test_context().await; - let api = ctx.client(); + let ctx = test_context_shared().await; + let api = ctx.client().await; let history_depth_addr = node_runtime::constants().staking().history_depth(); let history_depth = api.constants().at(&history_depth_addr)?; assert_eq!(history_depth, 84); @@ -229,8 +229,8 @@ async fn storage_history_depth() -> Result<(), Error> { #[tokio::test] async fn storage_current_era() -> Result<(), Error> { - let ctx = test_context().await; - let api = ctx.client(); + let ctx = test_context_shared().await; + let api = ctx.client().await; let current_era_addr = node_runtime::storage().staking().current_era(); let _current_era = api .storage() @@ -244,8 +244,8 @@ async fn storage_current_era() -> Result<(), Error> { #[tokio::test] async fn storage_era_reward_points() -> Result<(), Error> { - let ctx = test_context().await; - let api = ctx.client(); + let ctx = test_context_shared().await; + let api = ctx.client().await; let reward_points_addr = node_runtime::storage().staking().eras_reward_points(0); let current_era_result = api .storage() diff --git a/testing/integration-tests/src/frame/sudo.rs b/testing/integration-tests/src/frame/sudo.rs index 257ec46266..938be1ca8c 100644 --- a/testing/integration-tests/src/frame/sudo.rs +++ b/testing/integration-tests/src/frame/sudo.rs @@ -21,10 +21,11 @@ async fn test_sudo() -> Result<(), subxt::Error> { let api = ctx.client(); let alice = pair_signer(AccountKeyring::Alice.pair()); - let bob = AccountKeyring::Bob.to_account_id().into(); + let bob: subxt::utils::MultiAddress<::subxt::utils::AccountId32, u32> = + AccountKeyring::Bob.to_account_id().into(); let call = Call::Balances(BalancesCall::transfer { - dest: bob, + dest: bob.clone(), value: 10_000, }); let tx = node_runtime::tx().sudo().sudo(call); @@ -38,17 +39,8 @@ async fn test_sudo() -> Result<(), subxt::Error> { .has::()?; assert!(found_event); - Ok(()) -} - -#[tokio::test] -async fn test_sudo_unchecked_weight() -> Result<(), subxt::Error> { - let ctx = test_context().await; - let api = ctx.client(); - - let alice = pair_signer(AccountKeyring::Alice.pair()); - let bob = AccountKeyring::Bob.to_account_id().into(); + // Test sudo with unchecked weight let call = Call::Balances(BalancesCall::transfer { dest: bob, value: 10_000, @@ -70,5 +62,6 @@ async fn test_sudo_unchecked_weight() -> Result<(), subxt::Error> { .has::()?; assert!(found_event); + Ok(()) } diff --git a/testing/integration-tests/src/frame/system.rs b/testing/integration-tests/src/frame/system.rs index 9c149c5557..249ba95dc1 100644 --- a/testing/integration-tests/src/frame/system.rs +++ b/testing/integration-tests/src/frame/system.rs @@ -4,15 +4,15 @@ use crate::{ node_runtime::{self, system}, - pair_signer, test_context, + pair_signer, test_context_shared, }; use assert_matches::assert_matches; use sp_keyring::AccountKeyring; #[tokio::test] async fn storage_account() -> Result<(), subxt::Error> { - let ctx = test_context().await; - let api = ctx.client(); + let ctx = test_context_shared().await; + let api = ctx.client().await; let alice = pair_signer(AccountKeyring::Alice.pair()); @@ -31,8 +31,8 @@ async fn storage_account() -> Result<(), subxt::Error> { #[tokio::test] async fn tx_remark_with_event() -> Result<(), subxt::Error> { - let ctx = test_context().await; - let api = ctx.client(); + let ctx = test_context_shared().await; + let api = ctx.client().await; let alice = pair_signer(AccountKeyring::Alice.pair()); diff --git a/testing/integration-tests/src/frame/timestamp.rs b/testing/integration-tests/src/frame/timestamp.rs index 115d9f620f..ddbdeb1a33 100644 --- a/testing/integration-tests/src/frame/timestamp.rs +++ b/testing/integration-tests/src/frame/timestamp.rs @@ -2,12 +2,12 @@ // This file is dual-licensed as Apache-2.0 or GPL-3.0. // see LICENSE for license details. -use crate::{node_runtime, test_context}; +use crate::{node_runtime, test_context_shared}; #[tokio::test] async fn storage_get_current_timestamp() { - let ctx = test_context().await; - let api = ctx.client(); + let ctx = test_context_shared().await; + let api = ctx.client().await; let timestamp = api .storage() diff --git a/testing/integration-tests/src/metadata/validation.rs b/testing/integration-tests/src/metadata/validation.rs index 1e29f5c74d..dd00cf1e2d 100644 --- a/testing/integration-tests/src/metadata/validation.rs +++ b/testing/integration-tests/src/metadata/validation.rs @@ -2,7 +2,7 @@ // This file is dual-licensed as Apache-2.0 or GPL-3.0. // see LICENSE for license details. -use crate::{node_runtime, test_context, TestContext}; +use crate::{node_runtime, test_context_shared, TestContextShared}; use frame_metadata::{ ExtrinsicMetadata, PalletCallMetadata, PalletMetadata, PalletStorageMetadata, RuntimeMetadataPrefixed, RuntimeMetadataV14, StorageEntryMetadata, StorageEntryModifier, @@ -16,22 +16,19 @@ use subxt::{Metadata, OfflineClient, SubstrateConfig}; async fn metadata_to_api( metadata: RuntimeMetadataV14, - ctx: &TestContext, + ctx: &TestContextShared, ) -> OfflineClient { let prefixed = RuntimeMetadataPrefixed::from(metadata); let metadata = Metadata::try_from(prefixed).unwrap(); + let api = ctx.client().await; - OfflineClient::new( - ctx.client().genesis_hash(), - ctx.client().runtime_version(), - metadata, - ) + OfflineClient::new(api.genesis_hash(), api.runtime_version(), metadata) } #[tokio::test] async fn full_metadata_check() { - let ctx = test_context().await; - let api = ctx.client(); + let ctx = test_context_shared().await; + let api = ctx.client().await; // Runtime metadata is identical to the metadata used during API generation. assert!(node_runtime::validate_codegen(&api).is_ok()); @@ -50,8 +47,8 @@ async fn full_metadata_check() { #[tokio::test] async fn constant_values_are_not_validated() { - let ctx = test_context().await; - let api = ctx.client(); + let ctx = test_context_shared().await; + let api = ctx.client().await; let deposit_addr = node_runtime::constants().balances().existential_deposit(); @@ -106,8 +103,8 @@ fn pallets_to_metadata(pallets: Vec) -> RuntimeMetadataV14 { #[tokio::test] async fn calls_check() { - let ctx = test_context().await; - let api = ctx.client(); + let ctx = test_context_shared().await; + let api = ctx.client().await; let unbond_tx = node_runtime::tx().staking().unbond(123_456_789_012_345); let withdraw_unbonded_addr = node_runtime::tx().staking().withdraw_unbonded(10); @@ -192,8 +189,8 @@ async fn calls_check() { #[tokio::test] async fn storage_check() { - let ctx = test_context().await; - let api = ctx.client(); + let ctx = test_context_shared().await; + let api = ctx.client().await; let tx_count_addr = node_runtime::storage().system().extrinsic_count(); let tx_len_addr = node_runtime::storage().system().all_extrinsics_len(); diff --git a/testing/integration-tests/src/storage/mod.rs b/testing/integration-tests/src/storage/mod.rs index 0c6a5939a8..3df816863b 100644 --- a/testing/integration-tests/src/storage/mod.rs +++ b/testing/integration-tests/src/storage/mod.rs @@ -2,14 +2,14 @@ // This file is dual-licensed as Apache-2.0 or GPL-3.0. // see LICENSE for license details. -use crate::{node_runtime, pair_signer, test_context, utils::wait_for_blocks}; +use crate::{node_runtime, pair_signer, test_context, test_context_shared, utils::wait_for_blocks}; use sp_keyring::AccountKeyring; use subxt::utils::AccountId32; #[tokio::test] async fn storage_plain_lookup() -> Result<(), subxt::Error> { - let ctx = test_context().await; - let api = ctx.client(); + let ctx = test_context_shared().await; + let api = ctx.client().await; // Look up a plain value. Wait long enough that we don't get the genesis block data, // because it may have no storage associated with it. @@ -65,8 +65,8 @@ async fn storage_n_mapish_key_is_properly_created() -> Result<(), subxt::Error> use codec::Encode; use node_runtime::runtime_types::sp_core::crypto::KeyTypeId; - let ctx = test_context().await; - let api = ctx.client(); + let ctx = test_context_shared().await; + let api = ctx.client().await; // This is what the generated code hashes a `session().key_owner(..)` key into: let actual_key = node_runtime::storage() @@ -92,8 +92,8 @@ async fn storage_n_mapish_key_is_properly_created() -> Result<(), subxt::Error> #[tokio::test] async fn storage_n_map_storage_lookup() -> Result<(), subxt::Error> { - let ctx = test_context().await; - let api = ctx.client(); + let ctx = test_context_shared().await; + let api = ctx.client().await; // Boilerplate; we create a new asset class with ID 99, and then // we "approveTransfer" of some of this asset class. This gives us an diff --git a/testing/integration-tests/src/utils/context.rs b/testing/integration-tests/src/utils/context.rs index c2166869a9..87446d4eb9 100644 --- a/testing/integration-tests/src/utils/context.rs +++ b/testing/integration-tests/src/utils/context.rs @@ -2,12 +2,16 @@ // This file is dual-licensed as Apache-2.0 or GPL-3.0. // see LICENSE for license details. +use std::sync::Arc; + pub(crate) use crate::{node_runtime, TestNodeProcess}; use futures::lock::Mutex; use lazy_static::lazy_static; use sp_core::sr25519::Pair; use sp_keyring::AccountKeyring; -use subxt::{tx::PairSigner, OnlineClient, SubstrateConfig}; +use subxt::{client::default_rpc_client, tx::PairSigner, OnlineClient, SubstrateConfig}; + +use super::node_proc::TestNodeProcessBuilder; /// substrate node should be installed on the $PATH const SUBSTRATE_NODE_PATH: &str = "substrate"; @@ -40,13 +44,24 @@ pub async fn test_context() -> TestContext { /// Test context that shares a single substrate binary. pub struct TestContextShared { - client: OnlineClient, + url: String, } impl TestContextShared { /// Returns the subxt client connected to the running node. - pub fn client(&self) -> OnlineClient { - self.client.clone() + pub async fn client(&self) -> OnlineClient { + let rpc_client = Arc::new( + default_rpc_client(self.url.clone()) + .await + .expect("Cannot create RPC client for testing"), + ); + + let (genesis, runtime, metadata) = TestNodeProcessBuilder::get_cache(rpc_client.clone()) + .await + .expect("Cannot obtain caching for testing"); + + OnlineClient::from_rpc_client_with(genesis, runtime, metadata, rpc_client) + .expect("Cannot create subxt client for testing") } } @@ -59,12 +74,12 @@ pub async fn test_context_shared() -> TestContextShared { let mut cache = CACHE.lock().await; match &mut *cache { Some(test_context) => TestContextShared { - client: test_context.client(), + url: test_context.url(), }, None => { let test_context = test_context_with(AccountKeyring::Alice).await; let shared = TestContextShared { - client: test_context.client(), + url: test_context.url(), }; *cache = Some(test_context); diff --git a/testing/integration-tests/src/utils/node_proc.rs b/testing/integration-tests/src/utils/node_proc.rs index 0344fc5ae7..faec5493de 100644 --- a/testing/integration-tests/src/utils/node_proc.rs +++ b/testing/integration-tests/src/utils/node_proc.rs @@ -22,6 +22,7 @@ use tokio::sync::Mutex; pub struct TestNodeProcess { proc: process::Child, client: OnlineClient, + ws_url: String, } impl Drop for TestNodeProcess { @@ -55,6 +56,11 @@ impl TestNodeProcess { pub fn client(&self) -> OnlineClient { self.client.clone() } + + /// Returns the server URL that the client is connected to. + pub fn url(&self) -> String { + self.ws_url.clone() + } } /// Construct a test node process. @@ -98,7 +104,7 @@ impl TestNodeProcessBuilder { )) } - async fn get_cache( + pub async fn get_cache( rpc_client: Arc, ) -> Result<(::Hash, RuntimeVersion, Metadata), String> { lazy_static! { @@ -109,14 +115,12 @@ impl TestNodeProcessBuilder { let mut cache = CACHE.lock().await; match &mut *cache { - Some((genesis, runtime, metadata)) => { - Ok((genesis.clone(), runtime.clone(), metadata.clone())) - } + Some((genesis, runtime, metadata)) => Ok((*genesis, runtime.clone(), metadata.clone())), None => { let (genesis, runtime_version, metadata) = TestNodeProcessBuilder::fetch_cache_data(rpc_client).await?; - *cache = Some((genesis.clone(), runtime_version.clone(), metadata.clone())); + *cache = Some((*genesis, runtime_version.clone(), metadata.clone())); Ok((genesis, runtime_version, metadata)) } @@ -166,7 +170,11 @@ impl TestNodeProcessBuilder { // Connect to the node with a subxt client: let client = OnlineClient::from_rpc_client_with(genesis, runtime, metadata, rpc_client); match client { - Ok(client) => Ok(TestNodeProcess { proc, client }), + Ok(client) => Ok(TestNodeProcess { + proc, + client, + ws_url: ws_url.clone(), + }), Err(err) => { let err = format!("Failed to connect to node rpc at {ws_url}: {err}"); tracing::error!("{}", err); From 7db4f40435787f549e62528052888fc98de31873 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Tue, 28 Mar 2023 18:41:37 +0300 Subject: [PATCH 07/13] testing: Increase retry number Signed-off-by: Alexandru Vasile --- testing/test-runtime/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/test-runtime/build.rs b/testing/test-runtime/build.rs index c86bc0e86a..a87d6a77b0 100644 --- a/testing/test-runtime/build.rs +++ b/testing/test-runtime/build.rs @@ -44,7 +44,7 @@ async fn run() { // Download metadata from binary; retry until successful, or a limit is hit. let metadata_bytes: subxt::rpc::types::Bytes = { - const MAX_RETRIES: usize = 6; + const MAX_RETRIES: usize = 10; let mut retries = 0; loop { From 321b88afd75b9dd2dcbfa413b9a7e4c640e252de Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Tue, 28 Mar 2023 18:46:02 +0300 Subject: [PATCH 08/13] Fix cargo check Signed-off-by: Alexandru Vasile --- testing/integration-tests/src/utils/node_proc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/integration-tests/src/utils/node_proc.rs b/testing/integration-tests/src/utils/node_proc.rs index faec5493de..c252e92377 100644 --- a/testing/integration-tests/src/utils/node_proc.rs +++ b/testing/integration-tests/src/utils/node_proc.rs @@ -120,7 +120,7 @@ impl TestNodeProcessBuilder { let (genesis, runtime_version, metadata) = TestNodeProcessBuilder::fetch_cache_data(rpc_client).await?; - *cache = Some((*genesis, runtime_version.clone(), metadata.clone())); + *cache = Some((genesis, runtime_version.clone(), metadata.clone())); Ok((genesis, runtime_version, metadata)) } From cf1b3c3da2f42e2de2ec65d0ea983c417e914058 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Tue, 28 Mar 2023 19:22:13 +0300 Subject: [PATCH 09/13] ci: Use cargo-nextest Signed-off-by: Alexandru Vasile --- .github/workflows/rust.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index cc8e99fae8..df8a9b85fb 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -132,14 +132,14 @@ jobs: toolchain: stable override: true + - name: Install latest nextest release + uses: taiki-e/install-action@nextest + - name: Rust Cache uses: Swatinem/rust-cache@6fd3edff6979b79f87531400ad694fb7f2c84b1f # v2.2.1 - name: Cargo test - uses: actions-rs/cargo@v1.0.3 - with: - command: test - args: --all-targets --workspace + run: cargo nextest run --workspace clippy: name: Cargo clippy From 645048dab0699768bf73a42fc34e6fb48a297ee7 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Wed, 29 Mar 2023 14:23:39 +0300 Subject: [PATCH 10/13] testing: Use dedicated binaries for frame::balances Signed-off-by: Alexandru Vasile --- .../integration-tests/src/frame/balances.rs | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/testing/integration-tests/src/frame/balances.rs b/testing/integration-tests/src/frame/balances.rs index eba1ec6b5d..747f964437 100644 --- a/testing/integration-tests/src/frame/balances.rs +++ b/testing/integration-tests/src/frame/balances.rs @@ -4,7 +4,7 @@ use crate::{ node_runtime::{self, balances, runtime_types, system}, - pair_signer, test_context, test_context_shared, + pair_signer, test_context, }; use codec::Decode; use sp_core::Pair; @@ -242,8 +242,8 @@ async fn multiple_transfers_work_nonce_incremented() -> Result<(), subxt::Error> #[tokio::test] async fn storage_total_issuance() { - let ctx = test_context_shared().await; - let api = ctx.client().await; + let ctx = test_context().await; + let api = ctx.client(); let addr = node_runtime::storage().balances().total_issuance(); let total_issuance = api @@ -262,8 +262,8 @@ async fn storage_balance_lock() -> Result<(), subxt::Error> { let bob_signer = pair_signer(AccountKeyring::Bob.pair()); let bob: AccountId32 = AccountKeyring::Bob.to_account_id().into(); let charlie: AccountId32 = AccountKeyring::Charlie.to_account_id().into(); - let ctx = test_context_shared().await; - let api = ctx.client().await; + let ctx = test_context().await; + let api = ctx.client(); let tx = node_runtime::tx().staking().bond( charlie.into(), @@ -306,8 +306,8 @@ async fn transfer_error() { let alice_addr = alice.account_id().clone().into(); let hans = pair_signer(Pair::generate().0); let hans_address = hans.account_id().clone().into(); - let ctx = test_context_shared().await; - let api = ctx.client().await; + let ctx = test_context().await; + let api = ctx.client(); let to_hans_tx = node_runtime::tx() .balances() @@ -347,8 +347,8 @@ async fn transfer_error() { async fn transfer_implicit_subscription() { let alice = pair_signer(AccountKeyring::Alice.pair()); let bob: AccountId32 = AccountKeyring::Bob.to_account_id().into(); - let ctx = test_context_shared().await; - let api = ctx.client().await; + let ctx = test_context().await; + let api = ctx.client(); let to_bob_tx = node_runtime::tx() .balances() @@ -378,8 +378,8 @@ async fn transfer_implicit_subscription() { #[tokio::test] async fn constant_existential_deposit() { - let ctx = test_context_shared().await; - let api = ctx.client().await; + let ctx = test_context().await; + let api = ctx.client(); // get and decode constant manually via metadata: let metadata = api.metadata(); From c7459f425b05090e8d811973dbd30f185338c861 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Wed, 29 Mar 2023 14:48:44 +0300 Subject: [PATCH 11/13] testing: Adjust tests Signed-off-by: Alexandru Vasile --- testing/integration-tests/src/frame/staking.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/testing/integration-tests/src/frame/staking.rs b/testing/integration-tests/src/frame/staking.rs index e1316f0718..d9333753b2 100644 --- a/testing/integration-tests/src/frame/staking.rs +++ b/testing/integration-tests/src/frame/staking.rs @@ -32,8 +32,8 @@ fn default_validator_prefs() -> ValidatorPrefs { #[tokio::test] async fn validate_with_controller_account() { - let ctx = test_context_shared().await; - let api = ctx.client().await; + let ctx = test_context().await; + let api = ctx.client(); let alice = pair_signer(AccountKeyring::Alice.pair()); @@ -182,8 +182,8 @@ async fn chill_works_for_controller_only() -> Result<(), Error> { #[tokio::test] async fn tx_bond() -> Result<(), Error> { - let ctx = test_context_shared().await; - let api = ctx.client().await; + let ctx = test_context().await; + let api = ctx.client(); let alice = pair_signer(AccountKeyring::Alice.pair()); From e0d3e758335737c5d9f2cda015730567bfe38f7c Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Wed, 29 Mar 2023 15:18:59 +0300 Subject: [PATCH 12/13] Revert "testing: Adjust tests" This reverts commit c7459f425b05090e8d811973dbd30f185338c861. Revert "testing: Use dedicated binaries for frame::balances" This reverts commit 645048dab0699768bf73a42fc34e6fb48a297ee7. Revert "ci: Use cargo-nextest" This reverts commit cf1b3c3da2f42e2de2ec65d0ea983c417e914058. Revert "Fix cargo check" This reverts commit 321b88afd75b9dd2dcbfa413b9a7e4c640e252de. Revert "testing: Increase retry number" This reverts commit 7db4f40435787f549e62528052888fc98de31873. Revert "testing: Shared substrate binary for testing" This reverts commit f8d9a40f91664f31232d66bc772c11c14016f3b8. Revert "testing: Implement `TestContextShared` for shared substrate binaries" This reverts commit 641e1e3cf728e63e5dd33fdad4a19be4ed801a3f. Revert "testing: Use `SubstrateConfig` as default for testing" This reverts commit ff81fae37cd72a5c038822d838071b2d236588e4. Revert "testing: Async-aware mutex" This reverts commit f227a33f4b8d9f02e3272c0161710c7f26f37ed0. Revert "tests: Cache metadata and runtime version between runs" This reverts commit dca6252217ce73c4f39e4abc8f13b621af9d5518. --- .github/workflows/rust.yml | 8 +- Cargo.lock | 1 - subxt/src/rpc/rpc_client.rs | 2 +- testing/integration-tests/Cargo.toml | 1 - testing/integration-tests/src/blocks/mod.rs | 20 ++-- testing/integration-tests/src/client/mod.rs | 84 ++++++++-------- .../integration-tests/src/frame/staking.rs | 26 ++--- testing/integration-tests/src/frame/sudo.rs | 17 +++- testing/integration-tests/src/frame/system.rs | 10 +- .../integration-tests/src/frame/timestamp.rs | 6 +- .../src/metadata/validation.rs | 27 +++--- testing/integration-tests/src/storage/mod.rs | 14 +-- .../integration-tests/src/utils/context.rs | 63 +----------- .../integration-tests/src/utils/node_proc.rs | 95 ++++--------------- testing/test-runtime/build.rs | 2 +- 15 files changed, 136 insertions(+), 240 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index df8a9b85fb..cc8e99fae8 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -132,14 +132,14 @@ jobs: toolchain: stable override: true - - name: Install latest nextest release - uses: taiki-e/install-action@nextest - - name: Rust Cache uses: Swatinem/rust-cache@6fd3edff6979b79f87531400ad694fb7f2c84b1f # v2.2.1 - name: Cargo test - run: cargo nextest run --workspace + uses: actions-rs/cargo@v1.0.3 + with: + command: test + args: --all-targets --workspace clippy: name: Cargo clippy diff --git a/Cargo.lock b/Cargo.lock index 3b10629386..7d4e821a7f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1540,7 +1540,6 @@ dependencies = [ "frame-metadata", "futures", "hex", - "lazy_static", "parity-scale-codec", "regex", "scale-info", diff --git a/subxt/src/rpc/rpc_client.rs b/subxt/src/rpc/rpc_client.rs index 2d89e7c8cf..a23483258c 100644 --- a/subxt/src/rpc/rpc_client.rs +++ b/subxt/src/rpc/rpc_client.rs @@ -9,7 +9,7 @@ use serde::{de::DeserializeOwned, Serialize}; use serde_json::value::RawValue; use std::{pin::Pin, sync::Arc, task::Poll}; -/// A concrete wrapper around an [`RpcClientT`] which exposes the underlying interface via some +/// A concrete wrapper around an [`RpcClientT`] which exposes the udnerlying interface via some /// higher level methods that make it a little easier to work with. /// /// Wrapping [`RpcClientT`] in this way is simply a way to expose this additional functionality diff --git a/testing/integration-tests/Cargo.toml b/testing/integration-tests/Cargo.toml index 418f372a98..f4f14b72b6 100644 --- a/testing/integration-tests/Cargo.toml +++ b/testing/integration-tests/Cargo.toml @@ -35,4 +35,3 @@ tracing = "0.1.34" tracing-subscriber = "0.3.11" wabt = "0.10.0" which = "4.4.0" -lazy_static = "1.4.0" diff --git a/testing/integration-tests/src/blocks/mod.rs b/testing/integration-tests/src/blocks/mod.rs index 1db2bfa2ea..ae25594d76 100644 --- a/testing/integration-tests/src/blocks/mod.rs +++ b/testing/integration-tests/src/blocks/mod.rs @@ -2,7 +2,7 @@ // This file is dual-licensed as Apache-2.0 or GPL-3.0. // see LICENSE for license details. -use crate::test_context_shared; +use crate::test_context; use codec::{Compact, Decode}; use frame_metadata::RuntimeMetadataPrefixed; use futures::StreamExt; @@ -10,8 +10,8 @@ use futures::StreamExt; // Check that we can subscribe to non-finalized blocks. #[tokio::test] async fn non_finalized_headers_subscription() -> Result<(), subxt::Error> { - let ctx = test_context_shared().await; - let api = ctx.client().await; + let ctx = test_context().await; + let api = ctx.client(); let mut sub = api.blocks().subscribe_best().await?; @@ -29,8 +29,8 @@ async fn non_finalized_headers_subscription() -> Result<(), subxt::Error> { // Check that we can subscribe to finalized blocks. #[tokio::test] async fn finalized_headers_subscription() -> Result<(), subxt::Error> { - let ctx = test_context_shared().await; - let api = ctx.client().await; + let ctx = test_context().await; + let api = ctx.client(); let mut sub = api.blocks().subscribe_finalized().await?; @@ -46,8 +46,8 @@ async fn finalized_headers_subscription() -> Result<(), subxt::Error> { #[tokio::test] async fn missing_block_headers_will_be_filled_in() -> Result<(), subxt::Error> { - let ctx = test_context_shared().await; - let api = ctx.client().await; + let ctx = test_context().await; + let api = ctx.client(); // Manually subscribe to the next 6 finalized block headers, but deliberately // filter out some in the middle so we get back b _ _ b _ b. This guarantees @@ -66,7 +66,7 @@ async fn missing_block_headers_will_be_filled_in() -> Result<(), subxt::Error> { // This should spot any gaps in the middle and fill them back in. let all_finalized_blocks = subxt::blocks::subscribe_to_block_headers_filling_in_gaps( - ctx.client().await, + ctx.client(), None, some_finalized_blocks, ); @@ -93,8 +93,8 @@ async fn missing_block_headers_will_be_filled_in() -> Result<(), subxt::Error> { // Check that we can subscribe to non-finalized blocks. #[tokio::test] async fn runtime_api_call() -> Result<(), subxt::Error> { - let ctx = test_context_shared().await; - let api = ctx.client().await; + let ctx = test_context().await; + let api = ctx.client(); let mut sub = api.blocks().subscribe_best().await?; diff --git a/testing/integration-tests/src/client/mod.rs b/testing/integration-tests/src/client/mod.rs index 24aab0a049..0baf465a92 100644 --- a/testing/integration-tests/src/client/mod.rs +++ b/testing/integration-tests/src/client/mod.rs @@ -3,7 +3,7 @@ // see LICENSE for license details. use crate::{ - pair_signer, test_context, test_context_shared, test_context_with, + pair_signer, test_context, test_context_with, utils::{node_runtime, wait_for_blocks}, }; use assert_matches::assert_matches; @@ -45,14 +45,14 @@ async fn insert_key() { #[tokio::test] async fn fetch_block_hash() { - let ctx = test_context_shared().await; - ctx.client().await.rpc().block_hash(None).await.unwrap(); + let ctx = test_context().await; + ctx.client().rpc().block_hash(None).await.unwrap(); } #[tokio::test] async fn fetch_block() { - let ctx = test_context_shared().await; - let api = ctx.client().await; + let ctx = test_context().await; + let api = ctx.client(); let block_hash = api.rpc().block_hash(None).await.unwrap(); api.rpc().block(block_hash).await.unwrap(); @@ -60,8 +60,8 @@ async fn fetch_block() { #[tokio::test] async fn fetch_read_proof() { - let ctx = test_context_shared().await; - let api = ctx.client().await; + let ctx = test_context().await; + let api = ctx.client(); let block_hash = api.rpc().block_hash(None).await.unwrap(); api.rpc() @@ -78,8 +78,8 @@ async fn fetch_read_proof() { #[tokio::test] async fn chain_subscribe_all_blocks() { - let ctx = test_context_shared().await; - let api = ctx.client().await; + let ctx = test_context().await; + let api = ctx.client(); let mut blocks = api.rpc().subscribe_all_block_headers().await.unwrap(); blocks.next().await.unwrap().unwrap(); @@ -87,8 +87,8 @@ async fn chain_subscribe_all_blocks() { #[tokio::test] async fn chain_subscribe_best_blocks() { - let ctx = test_context_shared().await; - let api = ctx.client().await; + let ctx = test_context().await; + let api = ctx.client(); let mut blocks = api.rpc().subscribe_best_block_headers().await.unwrap(); blocks.next().await.unwrap().unwrap(); @@ -96,8 +96,8 @@ async fn chain_subscribe_best_blocks() { #[tokio::test] async fn chain_subscribe_finalized_blocks() { - let ctx = test_context_shared().await; - let api = ctx.client().await; + let ctx = test_context().await; + let api = ctx.client(); let mut blocks = api.rpc().subscribe_finalized_block_headers().await.unwrap(); blocks.next().await.unwrap().unwrap(); @@ -105,8 +105,8 @@ async fn chain_subscribe_finalized_blocks() { #[tokio::test] async fn fetch_keys() { - let ctx = test_context_shared().await; - let api = ctx.client().await; + let ctx = test_context().await; + let api = ctx.client(); let addr = node_runtime::storage().system().account_root(); let keys = api @@ -122,8 +122,8 @@ async fn fetch_keys() { #[tokio::test] async fn test_iter() { - let ctx = test_context_shared().await; - let api = ctx.client().await; + let ctx = test_context().await; + let api = ctx.client(); let addr = node_runtime::storage().system().account_root(); let mut iter = api @@ -143,8 +143,8 @@ async fn test_iter() { #[tokio::test] async fn fetch_system_info() { - let ctx = test_context_shared().await; - let api = ctx.client().await; + let ctx = test_context().await; + let api = ctx.client(); assert_eq!(api.rpc().system_chain().await.unwrap(), "Development"); assert_eq!(api.rpc().system_name().await.unwrap(), "Substrate Node"); @@ -153,8 +153,8 @@ async fn fetch_system_info() { #[tokio::test] async fn dry_run_passes() { - let ctx = test_context_shared().await; - let api = ctx.client().await; + let ctx = test_context().await; + let api = ctx.client(); let alice = pair_signer(AccountKeyring::Alice.pair()); let bob = pair_signer(AccountKeyring::Bob.pair()); @@ -248,8 +248,8 @@ async fn dry_run_result_is_substrate_compatible() { // We really just connect to a node to get some valid metadata to help us // decode Dispatch Errors. - let ctx = test_context_shared().await; - let api = ctx.client().await; + let ctx = test_context().await; + let api = ctx.client(); let pairs = vec![ // All ok @@ -293,8 +293,8 @@ async fn dry_run_result_is_substrate_compatible() { #[tokio::test] async fn external_signing() { - let ctx = test_context_shared().await; - let api = ctx.client().await; + let ctx = test_context().await; + let api = ctx.client(); let alice = pair_signer(AccountKeyring::Alice.pair()); // Create a partial extrinsic. We can get the signer payload at this point, to be @@ -352,8 +352,8 @@ async fn submit_large_extrinsic() { #[tokio::test] async fn unsigned_extrinsic_is_same_shape_as_polkadotjs() { - let ctx = test_context_shared().await; - let api = ctx.client().await; + let ctx = test_context().await; + let api = ctx.client(); let tx = node_runtime::tx().balances().transfer( pair_signer(AccountKeyring::Alice.pair()) @@ -384,8 +384,8 @@ async fn unsigned_extrinsic_is_same_shape_as_polkadotjs() { #[tokio::test] async fn rpc_state_call() { - let ctx = test_context_shared().await; - let api = ctx.client().await; + let ctx = test_context().await; + let api = ctx.client(); // Call into the runtime of the chain to get the Metadata. let metadata_bytes = api @@ -410,8 +410,8 @@ async fn rpc_state_call() { #[tokio::test] async fn chainhead_unstable_follow() { - let ctx = test_context_shared().await; - let api = ctx.client().await; + let ctx = test_context().await; + let api = ctx.client(); // Check subscription with runtime updates set on false. let mut blocks = api.rpc().chainhead_unstable_follow(false).await.unwrap(); @@ -431,7 +431,7 @@ async fn chainhead_unstable_follow() { let event = blocks.next().await.unwrap().unwrap(); // The initialized event should contain the finalized block hash. let finalized_block_hash = api.rpc().finalized_head().await.unwrap(); - let runtime_version = api.runtime_version(); + let runtime_version = ctx.client().runtime_version(); assert_matches!( event, @@ -446,8 +446,8 @@ async fn chainhead_unstable_follow() { #[tokio::test] async fn chainhead_unstable_body() { - let ctx = test_context_shared().await; - let api = ctx.client().await; + let ctx = test_context().await; + let api = ctx.client(); let mut blocks = api.rpc().chainhead_unstable_follow(false).await.unwrap(); let event = blocks.next().await.unwrap().unwrap(); @@ -477,8 +477,8 @@ async fn chainhead_unstable_body() { #[tokio::test] async fn chainhead_unstable_header() { - let ctx = test_context_shared().await; - let api = ctx.client().await; + let ctx = test_context().await; + let api = ctx.client(); let mut blocks = api.rpc().chainhead_unstable_follow(false).await.unwrap(); let event = blocks.next().await.unwrap().unwrap(); @@ -503,8 +503,8 @@ async fn chainhead_unstable_header() { #[tokio::test] async fn chainhead_unstable_storage() { - let ctx = test_context_shared().await; - let api = ctx.client().await; + let ctx = test_context().await; + let api = ctx.client(); let mut blocks = api.rpc().chainhead_unstable_follow(false).await.unwrap(); let event = blocks.next().await.unwrap().unwrap(); @@ -530,8 +530,8 @@ async fn chainhead_unstable_storage() { #[tokio::test] async fn chainhead_unstable_call() { - let ctx = test_context_shared().await; - let api = ctx.client().await; + let ctx = test_context().await; + let api = ctx.client(); let mut blocks = api.rpc().chainhead_unstable_follow(true).await.unwrap(); let event = blocks.next().await.unwrap().unwrap(); @@ -559,8 +559,8 @@ async fn chainhead_unstable_call() { #[tokio::test] async fn chainhead_unstable_unpin() { - let ctx = test_context_shared().await; - let api = ctx.client().await; + let ctx = test_context().await; + let api = ctx.client(); let mut blocks = api.rpc().chainhead_unstable_follow(true).await.unwrap(); let event = blocks.next().await.unwrap().unwrap(); diff --git a/testing/integration-tests/src/frame/staking.rs b/testing/integration-tests/src/frame/staking.rs index d9333753b2..fa198c4366 100644 --- a/testing/integration-tests/src/frame/staking.rs +++ b/testing/integration-tests/src/frame/staking.rs @@ -11,7 +11,7 @@ use crate::{ }, staking, }, - pair_signer, test_context, test_context_shared, + pair_signer, test_context, }; use assert_matches::assert_matches; use sp_core::{sr25519, Pair}; @@ -52,8 +52,8 @@ async fn validate_with_controller_account() { #[tokio::test] async fn validate_not_possible_for_stash_account() -> Result<(), Error> { - let ctx = test_context_shared().await; - let api = ctx.client().await; + let ctx = test_context().await; + let api = ctx.client(); let alice_stash = pair_signer(get_from_seed("Alice//stash")); @@ -77,8 +77,8 @@ async fn validate_not_possible_for_stash_account() -> Result<(), Error> { #[tokio::test] async fn nominate_with_controller_account() { - let ctx = test_context_shared().await; - let api = ctx.client().await; + let ctx = test_context().await; + let api = ctx.client(); let alice = pair_signer(AccountKeyring::Alice.pair()); let bob = pair_signer(AccountKeyring::Bob.pair()); @@ -98,8 +98,8 @@ async fn nominate_with_controller_account() { #[tokio::test] async fn nominate_not_possible_for_stash_account() -> Result<(), Error> { - let ctx = test_context_shared().await; - let api = ctx.client().await; + let ctx = test_context().await; + let api = ctx.client(); let alice_stash = pair_signer(get_from_seed("Alice//stash")); let bob = pair_signer(AccountKeyring::Bob.pair()); @@ -219,8 +219,8 @@ async fn tx_bond() -> Result<(), Error> { #[tokio::test] async fn storage_history_depth() -> Result<(), Error> { - let ctx = test_context_shared().await; - let api = ctx.client().await; + let ctx = test_context().await; + let api = ctx.client(); let history_depth_addr = node_runtime::constants().staking().history_depth(); let history_depth = api.constants().at(&history_depth_addr)?; assert_eq!(history_depth, 84); @@ -229,8 +229,8 @@ async fn storage_history_depth() -> Result<(), Error> { #[tokio::test] async fn storage_current_era() -> Result<(), Error> { - let ctx = test_context_shared().await; - let api = ctx.client().await; + let ctx = test_context().await; + let api = ctx.client(); let current_era_addr = node_runtime::storage().staking().current_era(); let _current_era = api .storage() @@ -244,8 +244,8 @@ async fn storage_current_era() -> Result<(), Error> { #[tokio::test] async fn storage_era_reward_points() -> Result<(), Error> { - let ctx = test_context_shared().await; - let api = ctx.client().await; + let ctx = test_context().await; + let api = ctx.client(); let reward_points_addr = node_runtime::storage().staking().eras_reward_points(0); let current_era_result = api .storage() diff --git a/testing/integration-tests/src/frame/sudo.rs b/testing/integration-tests/src/frame/sudo.rs index 938be1ca8c..257ec46266 100644 --- a/testing/integration-tests/src/frame/sudo.rs +++ b/testing/integration-tests/src/frame/sudo.rs @@ -21,11 +21,10 @@ async fn test_sudo() -> Result<(), subxt::Error> { let api = ctx.client(); let alice = pair_signer(AccountKeyring::Alice.pair()); - let bob: subxt::utils::MultiAddress<::subxt::utils::AccountId32, u32> = - AccountKeyring::Bob.to_account_id().into(); + let bob = AccountKeyring::Bob.to_account_id().into(); let call = Call::Balances(BalancesCall::transfer { - dest: bob.clone(), + dest: bob, value: 10_000, }); let tx = node_runtime::tx().sudo().sudo(call); @@ -39,8 +38,17 @@ async fn test_sudo() -> Result<(), subxt::Error> { .has::()?; assert!(found_event); + Ok(()) +} + +#[tokio::test] +async fn test_sudo_unchecked_weight() -> Result<(), subxt::Error> { + let ctx = test_context().await; + let api = ctx.client(); + + let alice = pair_signer(AccountKeyring::Alice.pair()); + let bob = AccountKeyring::Bob.to_account_id().into(); - // Test sudo with unchecked weight let call = Call::Balances(BalancesCall::transfer { dest: bob, value: 10_000, @@ -62,6 +70,5 @@ async fn test_sudo() -> Result<(), subxt::Error> { .has::()?; assert!(found_event); - Ok(()) } diff --git a/testing/integration-tests/src/frame/system.rs b/testing/integration-tests/src/frame/system.rs index 249ba95dc1..9c149c5557 100644 --- a/testing/integration-tests/src/frame/system.rs +++ b/testing/integration-tests/src/frame/system.rs @@ -4,15 +4,15 @@ use crate::{ node_runtime::{self, system}, - pair_signer, test_context_shared, + pair_signer, test_context, }; use assert_matches::assert_matches; use sp_keyring::AccountKeyring; #[tokio::test] async fn storage_account() -> Result<(), subxt::Error> { - let ctx = test_context_shared().await; - let api = ctx.client().await; + let ctx = test_context().await; + let api = ctx.client(); let alice = pair_signer(AccountKeyring::Alice.pair()); @@ -31,8 +31,8 @@ async fn storage_account() -> Result<(), subxt::Error> { #[tokio::test] async fn tx_remark_with_event() -> Result<(), subxt::Error> { - let ctx = test_context_shared().await; - let api = ctx.client().await; + let ctx = test_context().await; + let api = ctx.client(); let alice = pair_signer(AccountKeyring::Alice.pair()); diff --git a/testing/integration-tests/src/frame/timestamp.rs b/testing/integration-tests/src/frame/timestamp.rs index ddbdeb1a33..115d9f620f 100644 --- a/testing/integration-tests/src/frame/timestamp.rs +++ b/testing/integration-tests/src/frame/timestamp.rs @@ -2,12 +2,12 @@ // This file is dual-licensed as Apache-2.0 or GPL-3.0. // see LICENSE for license details. -use crate::{node_runtime, test_context_shared}; +use crate::{node_runtime, test_context}; #[tokio::test] async fn storage_get_current_timestamp() { - let ctx = test_context_shared().await; - let api = ctx.client().await; + let ctx = test_context().await; + let api = ctx.client(); let timestamp = api .storage() diff --git a/testing/integration-tests/src/metadata/validation.rs b/testing/integration-tests/src/metadata/validation.rs index dd00cf1e2d..1e29f5c74d 100644 --- a/testing/integration-tests/src/metadata/validation.rs +++ b/testing/integration-tests/src/metadata/validation.rs @@ -2,7 +2,7 @@ // This file is dual-licensed as Apache-2.0 or GPL-3.0. // see LICENSE for license details. -use crate::{node_runtime, test_context_shared, TestContextShared}; +use crate::{node_runtime, test_context, TestContext}; use frame_metadata::{ ExtrinsicMetadata, PalletCallMetadata, PalletMetadata, PalletStorageMetadata, RuntimeMetadataPrefixed, RuntimeMetadataV14, StorageEntryMetadata, StorageEntryModifier, @@ -16,19 +16,22 @@ use subxt::{Metadata, OfflineClient, SubstrateConfig}; async fn metadata_to_api( metadata: RuntimeMetadataV14, - ctx: &TestContextShared, + ctx: &TestContext, ) -> OfflineClient { let prefixed = RuntimeMetadataPrefixed::from(metadata); let metadata = Metadata::try_from(prefixed).unwrap(); - let api = ctx.client().await; - OfflineClient::new(api.genesis_hash(), api.runtime_version(), metadata) + OfflineClient::new( + ctx.client().genesis_hash(), + ctx.client().runtime_version(), + metadata, + ) } #[tokio::test] async fn full_metadata_check() { - let ctx = test_context_shared().await; - let api = ctx.client().await; + let ctx = test_context().await; + let api = ctx.client(); // Runtime metadata is identical to the metadata used during API generation. assert!(node_runtime::validate_codegen(&api).is_ok()); @@ -47,8 +50,8 @@ async fn full_metadata_check() { #[tokio::test] async fn constant_values_are_not_validated() { - let ctx = test_context_shared().await; - let api = ctx.client().await; + let ctx = test_context().await; + let api = ctx.client(); let deposit_addr = node_runtime::constants().balances().existential_deposit(); @@ -103,8 +106,8 @@ fn pallets_to_metadata(pallets: Vec) -> RuntimeMetadataV14 { #[tokio::test] async fn calls_check() { - let ctx = test_context_shared().await; - let api = ctx.client().await; + let ctx = test_context().await; + let api = ctx.client(); let unbond_tx = node_runtime::tx().staking().unbond(123_456_789_012_345); let withdraw_unbonded_addr = node_runtime::tx().staking().withdraw_unbonded(10); @@ -189,8 +192,8 @@ async fn calls_check() { #[tokio::test] async fn storage_check() { - let ctx = test_context_shared().await; - let api = ctx.client().await; + let ctx = test_context().await; + let api = ctx.client(); let tx_count_addr = node_runtime::storage().system().extrinsic_count(); let tx_len_addr = node_runtime::storage().system().all_extrinsics_len(); diff --git a/testing/integration-tests/src/storage/mod.rs b/testing/integration-tests/src/storage/mod.rs index 3df816863b..0c6a5939a8 100644 --- a/testing/integration-tests/src/storage/mod.rs +++ b/testing/integration-tests/src/storage/mod.rs @@ -2,14 +2,14 @@ // This file is dual-licensed as Apache-2.0 or GPL-3.0. // see LICENSE for license details. -use crate::{node_runtime, pair_signer, test_context, test_context_shared, utils::wait_for_blocks}; +use crate::{node_runtime, pair_signer, test_context, utils::wait_for_blocks}; use sp_keyring::AccountKeyring; use subxt::utils::AccountId32; #[tokio::test] async fn storage_plain_lookup() -> Result<(), subxt::Error> { - let ctx = test_context_shared().await; - let api = ctx.client().await; + let ctx = test_context().await; + let api = ctx.client(); // Look up a plain value. Wait long enough that we don't get the genesis block data, // because it may have no storage associated with it. @@ -65,8 +65,8 @@ async fn storage_n_mapish_key_is_properly_created() -> Result<(), subxt::Error> use codec::Encode; use node_runtime::runtime_types::sp_core::crypto::KeyTypeId; - let ctx = test_context_shared().await; - let api = ctx.client().await; + let ctx = test_context().await; + let api = ctx.client(); // This is what the generated code hashes a `session().key_owner(..)` key into: let actual_key = node_runtime::storage() @@ -92,8 +92,8 @@ async fn storage_n_mapish_key_is_properly_created() -> Result<(), subxt::Error> #[tokio::test] async fn storage_n_map_storage_lookup() -> Result<(), subxt::Error> { - let ctx = test_context_shared().await; - let api = ctx.client().await; + let ctx = test_context().await; + let api = ctx.client(); // Boilerplate; we create a new asset class with ID 99, and then // we "approveTransfer" of some of this asset class. This gives us an diff --git a/testing/integration-tests/src/utils/context.rs b/testing/integration-tests/src/utils/context.rs index 87446d4eb9..980295269f 100644 --- a/testing/integration-tests/src/utils/context.rs +++ b/testing/integration-tests/src/utils/context.rs @@ -2,23 +2,15 @@ // This file is dual-licensed as Apache-2.0 or GPL-3.0. // see LICENSE for license details. -use std::sync::Arc; - pub(crate) use crate::{node_runtime, TestNodeProcess}; -use futures::lock::Mutex; -use lazy_static::lazy_static; + use sp_core::sr25519::Pair; use sp_keyring::AccountKeyring; -use subxt::{client::default_rpc_client, tx::PairSigner, OnlineClient, SubstrateConfig}; - -use super::node_proc::TestNodeProcessBuilder; +use subxt::{tx::PairSigner, SubstrateConfig}; /// substrate node should be installed on the $PATH const SUBSTRATE_NODE_PATH: &str = "substrate"; -/// Test context that spawns a dedicated substrate binary. -pub type TestContext = TestNodeProcess; - pub async fn test_context_with(key: AccountKeyring) -> TestContext { let path = std::env::var("SUBSTRATE_NODE_PATH").unwrap_or_else(|_| { if which::which(SUBSTRATE_NODE_PATH).is_err() { @@ -32,62 +24,17 @@ pub async fn test_context_with(key: AccountKeyring) -> TestContext { let proc = TestContext::build(path.as_str()) .with_authority(key) - .spawn() + .spawn::() .await; proc.unwrap() } -/// Create a test context that spawns a dedicated substrate binary. +pub type TestContext = TestNodeProcess; + pub async fn test_context() -> TestContext { test_context_with(AccountKeyring::Alice).await } -/// Test context that shares a single substrate binary. -pub struct TestContextShared { - url: String, -} - -impl TestContextShared { - /// Returns the subxt client connected to the running node. - pub async fn client(&self) -> OnlineClient { - let rpc_client = Arc::new( - default_rpc_client(self.url.clone()) - .await - .expect("Cannot create RPC client for testing"), - ); - - let (genesis, runtime, metadata) = TestNodeProcessBuilder::get_cache(rpc_client.clone()) - .await - .expect("Cannot obtain caching for testing"); - - OnlineClient::from_rpc_client_with(genesis, runtime, metadata, rpc_client) - .expect("Cannot create subxt client for testing") - } -} - -/// Create a test context that shares the substrate binary. -pub async fn test_context_shared() -> TestContextShared { - lazy_static! { - static ref CACHE: Mutex> = Mutex::new(None); - } - - let mut cache = CACHE.lock().await; - match &mut *cache { - Some(test_context) => TestContextShared { - url: test_context.url(), - }, - None => { - let test_context = test_context_with(AccountKeyring::Alice).await; - let shared = TestContextShared { - url: test_context.url(), - }; - - *cache = Some(test_context); - shared - } - } -} - pub fn pair_signer(pair: Pair) -> PairSigner { PairSigner::new(pair) } diff --git a/testing/integration-tests/src/utils/node_proc.rs b/testing/integration-tests/src/utils/node_proc.rs index c252e92377..8c1fc88c3f 100644 --- a/testing/integration-tests/src/utils/node_proc.rs +++ b/testing/integration-tests/src/utils/node_proc.rs @@ -2,36 +2,33 @@ // This file is dual-licensed as Apache-2.0 or GPL-3.0. // see LICENSE for license details. -use futures::future; -use lazy_static::lazy_static; use sp_keyring::AccountKeyring; use std::{ ffi::{OsStr, OsString}, io::{BufRead, BufReader, Read}, process, - sync::Arc, }; -use subxt::{ - client::default_rpc_client, - rpc::{types::RuntimeVersion, Rpc, RpcClientT}, - Config, Metadata, OnlineClient, SubstrateConfig, -}; -use tokio::sync::Mutex; +use subxt::{Config, OnlineClient}; /// Spawn a local substrate node for testing subxt. -pub struct TestNodeProcess { +pub struct TestNodeProcess { proc: process::Child, - client: OnlineClient, - ws_url: String, + client: OnlineClient, } -impl Drop for TestNodeProcess { +impl Drop for TestNodeProcess +where + R: Config, +{ fn drop(&mut self) { let _ = self.kill(); } } -impl TestNodeProcess { +impl TestNodeProcess +where + R: Config, +{ /// Construct a builder for spawning a test node process. pub fn build(program: S) -> TestNodeProcessBuilder where @@ -53,14 +50,9 @@ impl TestNodeProcess { } /// Returns the subxt client connected to the running node. - pub fn client(&self) -> OnlineClient { + pub fn client(&self) -> OnlineClient { self.client.clone() } - - /// Returns the server URL that the client is connected to. - pub fn url(&self) -> String { - self.ws_url.clone() - } } /// Construct a test node process. @@ -86,49 +78,11 @@ impl TestNodeProcessBuilder { self } - async fn fetch_cache_data( - rpc_client: Arc, - ) -> Result<(::Hash, RuntimeVersion, Metadata), String> { - let rpc = Rpc::::new(rpc_client); - - let (genesis_hash, runtime_version, metadata) = future::join3( - rpc.genesis_hash(), - rpc.runtime_version(None), - rpc.metadata(None), - ) - .await; - Ok(( - genesis_hash.map_err(|err| format!("Cannot fetch genesis: {:?}", err))?, - runtime_version.map_err(|err| format!("Cannot fetch runtime version: {:?}", err))?, - metadata.map_err(|err| format!("Cannot fetch metadata {:?}", err))?, - )) - } - - pub async fn get_cache( - rpc_client: Arc, - ) -> Result<(::Hash, RuntimeVersion, Metadata), String> { - lazy_static! { - static ref CACHE: Mutex::Hash, RuntimeVersion, Metadata)>> = - Mutex::new(None); - } - - let mut cache = CACHE.lock().await; - - match &mut *cache { - Some((genesis, runtime, metadata)) => Ok((*genesis, runtime.clone(), metadata.clone())), - None => { - let (genesis, runtime_version, metadata) = - TestNodeProcessBuilder::fetch_cache_data(rpc_client).await?; - - *cache = Some((genesis, runtime_version.clone(), metadata.clone())); - - Ok((genesis, runtime_version, metadata)) - } - } - } - /// Spawn the substrate node at the given path, and wait for rpc to be initialized. - pub async fn spawn(&self) -> Result { + pub async fn spawn(&self) -> Result, String> + where + R: Config, + { let mut cmd = process::Command::new(&self.node_path); cmd.env("RUST_LOG", "info") .arg("--dev") @@ -158,23 +112,10 @@ impl TestNodeProcessBuilder { let ws_port = find_substrate_port_from_output(stderr); let ws_url = format!("ws://127.0.0.1:{ws_port}"); - let rpc_client = Arc::new( - default_rpc_client(ws_url.clone()) - .await - .map_err(|err| err.to_string())?, - ); - - let (genesis, runtime, metadata) = - TestNodeProcessBuilder::get_cache(rpc_client.clone()).await?; - // Connect to the node with a subxt client: - let client = OnlineClient::from_rpc_client_with(genesis, runtime, metadata, rpc_client); + let client = OnlineClient::from_url(ws_url.clone()).await; match client { - Ok(client) => Ok(TestNodeProcess { - proc, - client, - ws_url: ws_url.clone(), - }), + Ok(client) => Ok(TestNodeProcess { proc, client }), Err(err) => { let err = format!("Failed to connect to node rpc at {ws_url}: {err}"); tracing::error!("{}", err); diff --git a/testing/test-runtime/build.rs b/testing/test-runtime/build.rs index a87d6a77b0..c86bc0e86a 100644 --- a/testing/test-runtime/build.rs +++ b/testing/test-runtime/build.rs @@ -44,7 +44,7 @@ async fn run() { // Download metadata from binary; retry until successful, or a limit is hit. let metadata_bytes: subxt::rpc::types::Bytes = { - const MAX_RETRIES: usize = 10; + const MAX_RETRIES: usize = 6; let mut retries = 0; loop { From 5b2fe4a4493a1e1668883c1a5138ef1913bba47a Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Tue, 28 Mar 2023 19:22:13 +0300 Subject: [PATCH 13/13] ci: Use cargo-nextest Signed-off-by: Alexandru Vasile --- .github/workflows/rust.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index cc8e99fae8..df8a9b85fb 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -132,14 +132,14 @@ jobs: toolchain: stable override: true + - name: Install latest nextest release + uses: taiki-e/install-action@nextest + - name: Rust Cache uses: Swatinem/rust-cache@6fd3edff6979b79f87531400ad694fb7f2c84b1f # v2.2.1 - name: Cargo test - uses: actions-rs/cargo@v1.0.3 - with: - command: test - args: --all-targets --workspace + run: cargo nextest run --workspace clippy: name: Cargo clippy