Skip to content

Commit

Permalink
test runner (paritytech#7665)
Browse files Browse the repository at this point in the history
  • Loading branch information
Seun Lanlege authored and hirschenberger committed Apr 14, 2021
1 parent fd295c2 commit 01fb1c6
Show file tree
Hide file tree
Showing 11 changed files with 1,502 additions and 157 deletions.
425 changes: 271 additions & 154 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ members = [
"bin/node/bench",
"bin/node/browser-testing",
"bin/node/cli",
"bin/node/test-runner-example",
"bin/node/executor",
"bin/node/primitives",
"bin/node/rpc",
Expand Down Expand Up @@ -184,6 +185,7 @@ members = [
"test-utils/runtime",
"test-utils/runtime/client",
"test-utils/runtime/transaction-pool",
"test-utils/test-runner",
"test-utils/test-crate",
"utils/browser",
"utils/build-script-utils",
Expand Down
40 changes: 40 additions & 0 deletions bin/node/test-runner-example/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
[package]
name = "test-runner-example"
version = "0.1.0"
authors = ["Parity Technologies <[email protected]>"]
edition = "2018"
publish = false

[dependencies]
test-runner = { path = "../../../test-utils/test-runner", version = "0.9.0" }

frame-system = { version = "3.0.0", path = "../../../frame/system" }
frame-support = { path = "../../../frame/support", version = "3.0.0" }
frame-benchmarking = { path = "../../../frame/benchmarking", version = "3.0.0" }
pallet-balances = { path = "../../../frame/balances", version = "3.0.0" }
pallet-sudo = { path = "../../../frame/sudo", version = "3.0.0" }
pallet-transaction-payment = { version = "3.0.0", path = "../../../frame/transaction-payment" }

node-runtime = { path = "../runtime", version = "2.0.1" }
node-primitives = { version = "2.0.0", path = "../primitives" }
node-cli = { path = "../cli", version = "2.0.0" }

grandpa = { version = "0.9.0", package = "sc-finality-grandpa", path = "../../../client/finality-grandpa" }
sp-consensus-babe = { version = "0.9.0", path = "../../../primitives/consensus/babe" }
sc-consensus-babe = { version = "0.9.0", path = "../../../client/consensus/babe" }
sc-consensus-manual-seal = { version = "0.9.0", path = "../../../client/consensus/manual-seal" }
sc-service = { version = "0.9.0", default-features = false, path = "../../../client/service" }
sc-executor = { version = "0.9.0", path = "../../../client/executor" }
sc-client-api = { version = "3.0.0", path = "../../../client/api" }
sc-network = { version = "0.9.0", path = "../../../client/network" }
sc-informant = { version = "0.9.0", path = "../../../client/informant" }
sc-consensus = { version = "0.9.0", path = "../../../client/consensus/common" }

sp-runtime = { path = "../../../primitives/runtime", version = "3.0.0" }
sp-keyring = { version = "3.0.0", path = "../../../primitives/keyring" }
sp-api = { version = "3.0.0", path = "../../../primitives/api" }
sp-inherents = { version = "3.0.0", path = "../../../primitives/inherents" }
sp-keystore = { version = "0.9.0", path = "../../../primitives/keystore" }

rand = "0.8.3"
log = "0.4.14"
202 changes: 202 additions & 0 deletions bin/node/test-runner-example/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
// This file is part of Substrate.

// Copyright (C) 2021 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/>.

//! Basic example of end to end runtime tests.
use test_runner::{Node, ChainInfo, SignatureVerificationOverride};
use grandpa::GrandpaBlockImport;
use sc_service::{TFullBackend, TFullClient, Configuration, TaskManager, new_full_parts};
use std::sync::Arc;
use sp_inherents::InherentDataProviders;
use sc_consensus_babe::BabeBlockImport;
use sp_keystore::SyncCryptoStorePtr;
use sp_keyring::sr25519::Keyring::Alice;
use sp_consensus_babe::AuthorityId;
use sc_consensus_manual_seal::{ConsensusDataProvider, consensus::babe::BabeConsensusDataProvider};
use sp_runtime::{traits::IdentifyAccount, MultiSigner, generic::Era};

type BlockImport<B, BE, C, SC> = BabeBlockImport<B, C, GrandpaBlockImport<BE, B, C, SC>>;

sc_executor::native_executor_instance!(
pub Executor,
node_runtime::api::dispatch,
node_runtime::native_version,
(
frame_benchmarking::benchmarking::HostFunctions,
SignatureVerificationOverride,
)
);

/// ChainInfo implementation.
struct NodeTemplateChainInfo;

impl ChainInfo for NodeTemplateChainInfo {
type Block = node_primitives::Block;
type Executor = Executor;
type Runtime = node_runtime::Runtime;
type RuntimeApi = node_runtime::RuntimeApi;
type SelectChain = sc_consensus::LongestChain<TFullBackend<Self::Block>, Self::Block>;
type BlockImport = BlockImport<
Self::Block,
TFullBackend<Self::Block>,
TFullClient<Self::Block, Self::RuntimeApi, Self::Executor>,
Self::SelectChain,
>;
type SignedExtras = node_runtime::SignedExtra;

fn signed_extras(from: <Self::Runtime as frame_system::Config>::AccountId) -> Self::SignedExtras {
(
frame_system::CheckSpecVersion::<Self::Runtime>::new(),
frame_system::CheckTxVersion::<Self::Runtime>::new(),
frame_system::CheckGenesis::<Self::Runtime>::new(),
frame_system::CheckMortality::<Self::Runtime>::from(Era::Immortal),
frame_system::CheckNonce::<Self::Runtime>::from(frame_system::Pallet::<Self::Runtime>::account_nonce(from)),
frame_system::CheckWeight::<Self::Runtime>::new(),
pallet_transaction_payment::ChargeTransactionPayment::<Self::Runtime>::from(0),
)
}

fn create_client_parts(
config: &Configuration,
) -> Result<
(
Arc<TFullClient<Self::Block, Self::RuntimeApi, Self::Executor>>,
Arc<TFullBackend<Self::Block>>,
SyncCryptoStorePtr,
TaskManager,
InherentDataProviders,
Option<
Box<
dyn ConsensusDataProvider<
Self::Block,
Transaction = sp_api::TransactionFor<
TFullClient<Self::Block, Self::RuntimeApi, Self::Executor>,
Self::Block,
>,
>,
>,
>,
Self::SelectChain,
Self::BlockImport,
),
sc_service::Error,
> {
let (client, backend, keystore, task_manager) =
new_full_parts::<Self::Block, Self::RuntimeApi, Self::Executor>(config, None)?;
let client = Arc::new(client);

let inherent_providers = InherentDataProviders::new();
let select_chain = sc_consensus::LongestChain::new(backend.clone());

let (grandpa_block_import, ..) =
grandpa::block_import(
client.clone(),
&(client.clone() as Arc<_>),
select_chain.clone(),
None
)?;

let (block_import, babe_link) = sc_consensus_babe::block_import(
sc_consensus_babe::Config::get_or_compute(&*client)?,
grandpa_block_import,
client.clone(),
)?;

let consensus_data_provider = BabeConsensusDataProvider::new(
client.clone(),
keystore.sync_keystore(),
&inherent_providers,
babe_link.epoch_changes().clone(),
vec![(AuthorityId::from(Alice.public()), 1000)],
)
.expect("failed to create ConsensusDataProvider");

Ok((
client,
backend,
keystore.sync_keystore(),
task_manager,
inherent_providers,
Some(Box::new(consensus_data_provider)),
select_chain,
block_import,
))
}

fn dispatch_with_root(call: <Self::Runtime as frame_system::Config>::Call, node: &mut Node<Self>) {
let alice = MultiSigner::from(Alice.public()).into_account();
let call = pallet_sudo::Call::sudo(Box::new(call));
node.submit_extrinsic(call, alice);
node.seal_blocks(1);
}
}

#[cfg(test)]
mod tests {
use super::*;
use test_runner::NodeConfig;
use log::LevelFilter;
use sc_client_api::execution_extensions::ExecutionStrategies;
use node_cli::chain_spec::development_config;

#[test]
fn test_runner() {
let config = NodeConfig {
execution_strategies: ExecutionStrategies {
syncing: sc_client_api::ExecutionStrategy::AlwaysWasm,
importing: sc_client_api::ExecutionStrategy::AlwaysWasm,
block_construction: sc_client_api::ExecutionStrategy::AlwaysWasm,
offchain_worker: sc_client_api::ExecutionStrategy::AlwaysWasm,
other: sc_client_api::ExecutionStrategy::AlwaysWasm,
},
chain_spec: Box::new(development_config()),
log_targets: vec![
("yamux", LevelFilter::Off),
("multistream_select", LevelFilter::Off),
("libp2p", LevelFilter::Off),
("jsonrpc_client_transports", LevelFilter::Off),
("sc_network", LevelFilter::Off),
("tokio_reactor", LevelFilter::Off),
("parity-db", LevelFilter::Off),
("sub-libp2p", LevelFilter::Off),
("sync", LevelFilter::Off),
("peerset", LevelFilter::Off),
("ws", LevelFilter::Off),
("sc_network", LevelFilter::Off),
("sc_service", LevelFilter::Off),
("sc_basic_authorship", LevelFilter::Off),
("telemetry-logger", LevelFilter::Off),
("sc_peerset", LevelFilter::Off),
("rpc", LevelFilter::Off),
("runtime", LevelFilter::Trace),
("babe", LevelFilter::Debug)
],
};
let mut node = Node::<NodeTemplateChainInfo>::new(config).unwrap();
// seals blocks
node.seal_blocks(1);
// submit extrinsics
let alice = MultiSigner::from(Alice.public()).into_account();
node.submit_extrinsic(frame_system::Call::remark((b"hello world").to_vec()), alice);

// look ma, I can read state.
let _events = node.with_state(|| frame_system::Pallet::<node_runtime::Runtime>::events());
// get access to the underlying client.
let _client = node.client();
}
}
14 changes: 12 additions & 2 deletions client/executor/src/native_executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -274,10 +274,20 @@ impl<D: NativeExecutionDispatch> NativeExecutor<D> {
default_heap_pages: Option<u64>,
max_runtime_instances: usize,
) -> Self {
let mut host_functions = D::ExtendHostFunctions::host_functions();
let extended = D::ExtendHostFunctions::host_functions();
let mut host_functions = sp_io::SubstrateHostFunctions::host_functions()
.into_iter()
// filter out any host function overrides provided.
.filter(|host_fn| {
extended.iter()
.find(|ext_host_fn| host_fn.name() == ext_host_fn.name())
.is_none()
})
.collect::<Vec<_>>();


// Add the custom host functions provided by the user.
host_functions.extend(sp_io::SubstrateHostFunctions::host_functions());
host_functions.extend(extended);
let wasm_executor = WasmExecutor::new(
fallback_method,
default_heap_pages,
Expand Down
1 change: 0 additions & 1 deletion frame/babe/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,6 @@ fn can_fetch_current_and_next_epoch_data() {
Babe::current_epoch().authorities,
Babe::next_epoch().authorities,
);

// 1 era = 3 epochs
// 1 epoch = 3 slots
// Eras start from 0.
Expand Down
61 changes: 61 additions & 0 deletions test-utils/test-runner/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
[package]
name = "test-runner"
version = "0.9.0"
authors = ["Parity Technologies <[email protected]>"]
edition = "2018"
publish = false

[dependencies]
# client deps
sc-executor = { version = "0.9.0", path = "../../client/executor" }
sc-service = { version = "0.9.0", path = "../../client/service" }
sc-informant = { version = "0.9.0", path = "../../client/informant" }
sc-network = { version = "0.9.0", path = "../../client/network" }
sc-cli = { version = "0.9.0", path = "../../client/cli" }
sc-basic-authorship = { version = "0.9.0", path = "../../client/basic-authorship" }
sc-rpc = { version = "3.0.0", path = "../../client/rpc" }
sc-transaction-pool = { version = "3.0.0", path = "../../client/transaction-pool" }
sc-transaction-graph = { version = "3.0.0", path = "../../client/transaction-pool/graph" }
sc-client-api = { version = "3.0.0", path = "../../client/api" }
sc-rpc-server = { version = "3.0.0", path = "../../client/rpc-servers" }
manual-seal = { package = "sc-consensus-manual-seal", version = "0.9.0", path = "../../client/consensus/manual-seal" }

# primitive deps
sp-core = { version = "3.0.0", path = "../../primitives/core" }
sp-blockchain = { version = "3.0.0", path = "../../primitives/blockchain" }
sp-block-builder = { version = "3.0.0", path = "../../primitives/block-builder" }
sp-api = { version = "3.0.0", path = "../../primitives/api" }
sp-io = { version = "3.0.0", path = "../../primitives/io" }
sp-transaction-pool = { version = "3.0.0", path = "../../primitives/transaction-pool" }
sp-consensus = { version = "0.9.0", path = "../../primitives/consensus/common" }
sp-keystore = { version = "0.9.0", path = "../../primitives/keystore" }
sp-runtime = { version = "3.0.0", path = "../../primitives/runtime" }
sp-session = { version = "3.0.0", path = "../../primitives/session" }
sp-offchain = { version = "3.0.0", path = "../../primitives/offchain" }
sp-inherents = { version = "3.0.0", path = "../../primitives/inherents" }
sp-keyring = { version = "3.0.0", path = "../../primitives/keyring" }

sp-externalities = { version = "0.9.0", path = "../../primitives/externalities" }
sp-state-machine = { version = "0.9.0", path = "../../primitives/state-machine" }
sp-wasm-interface = { version = "3.0.0", path = "../../primitives/wasm-interface" }
sp-runtime-interface = { version = "3.0.0", path = "../../primitives/runtime-interface" }

# pallets
frame-system = { version = "3.0.0", path = "../../frame/system" }

parity-scale-codec = "1.3.1"
env_logger = "0.7.1"
log = "0.4.8"
futures01 = { package = "futures", version = "0.1.29" }
futures = { package = "futures", version = "0.3", features = ["compat"] }
rand = "0.7"
tokio = { version = "0.2", features = ["full"] }
libp2p = "0.35.1"

# Calling RPC
jsonrpc-core = "15.1"
[dev-dependencies]
sc-finality-grandpa = { version = "0.9.0", path = "../../client/finality-grandpa" }
sc-consensus-babe = { version = "0.9.0", path = "../../client/consensus/babe" }
sp-consensus-babe = { version = "0.9.0", path = "../../primitives/consensus/babe" }
node-cli = { version = "2.0.0", path = "../../bin/node/cli" }
Loading

0 comments on commit 01fb1c6

Please sign in to comment.