tests compile using new test framework

This commit is contained in:
Robert Habermeier
2018-10-29 17:03:08 +01:00
parent 84925067f4
commit 6d4acb053d
4 changed files with 140 additions and 48 deletions
+1
View File
@@ -3047,6 +3047,7 @@ dependencies = [
"substrate-keyring 0.1.0", "substrate-keyring 0.1.0",
"substrate-network 0.1.0", "substrate-network 0.1.0",
"substrate-primitives 0.1.0", "substrate-primitives 0.1.0",
"substrate-test-client 0.1.0",
"tokio 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@@ -24,3 +24,4 @@ features = ["derive-codec"]
[dev-dependencies] [dev-dependencies]
substrate-network = { path = "../network", features = ["test-helpers"] } substrate-network = { path = "../network", features = ["test-helpers"] }
substrate-keyring = { path = "../keyring" } substrate-keyring = { path = "../keyring" }
substrate-test-client = { path = "../test-client"}
+137 -47
View File
@@ -38,6 +38,9 @@ extern crate substrate_network as network;
#[cfg(test)] #[cfg(test)]
extern crate substrate_keyring as keyring; extern crate substrate_keyring as keyring;
#[cfg(test)]
extern crate substrate_test_client as test_client;
#[macro_use] #[macro_use]
extern crate parity_codec_derive; extern crate parity_codec_derive;
@@ -620,6 +623,7 @@ impl<B, E, Block: BlockT, N> voter::Environment<Block::Hash, NumberFor<Block>> f
return Ok(()); return Ok(());
} }
// lock must be held through writing to DB to avoid race
let mut authority_set = self.authority_set.inner().write(); let mut authority_set = self.authority_set.inner().write();
let client = &self.inner; let client = &self.inner;
let status = authority_set.apply_changes(number, |canon_number| { let status = authority_set.apply_changes(number, |canon_number| {
@@ -752,32 +756,23 @@ impl<B, E, Block: BlockT> BlockImport<Block> for GrandpaBlockImport<B, E, Block>
} }
} }
/// Run a GRANDPA voter as a task. This returns two pieces of data: a task to run, /// Half of a link between a block-import worker and a the background voter.
/// and a `BlockImport` implementation. // This should remain non-clone.
pub fn run_grandpa<B, E, Block: BlockT, N>( pub struct LinkHalf<B, E, Block: BlockT> {
config: Config,
client: Arc<Client<B, E, Block>>, client: Arc<Client<B, E, Block>>,
voters: HashMap<AuthorityId, u64>, authority_set: SharedAuthoritySet<Block::Hash, NumberFor<Block>>,
network: N, }
) -> ::client::error::Result<(
impl Future<Item=(),Error=()>, /// Make block importer and link half necessary to tie the background voter
GrandpaBlockImport<B, E, Block>, /// to it.
)> where pub fn block_import<B, E, Block: BlockT>(client: Arc<Client<B, E, Block>>)
Block::Hash: Ord, -> Result<(GrandpaBlockImport<B, E, Block>, LinkHalf<B, E, Block>), ClientError>
where
B: Backend<Block, Blake2Hasher> + 'static, B: Backend<Block, Blake2Hasher> + 'static,
E: CallExecutor<Block, Blake2Hasher> + 'static, E: CallExecutor<Block, Blake2Hasher> + 'static,
N: Network + 'static,
N::In: 'static,
NumberFor<Block>: BlockNumberOps,
DigestFor<Block>: Encode,
{ {
use futures::future::{self, Loop as FutureLoop};
use runtime_primitives::traits::Zero; use runtime_primitives::traits::Zero;
let chain_info = client.info()?;
let genesis_hash = chain_info.chain.genesis_hash;
let authority_set = match client.backend().get_aux(AUTHORITY_SET_KEY)? { let authority_set = match client.backend().get_aux(AUTHORITY_SET_KEY)? {
None => { None => {
info!(target: "afg", "Loading GRANDPA authorities \ info!(target: "afg", "Loading GRANDPA authorities \
@@ -802,10 +797,33 @@ pub fn run_grandpa<B, E, Block: BlockT, N>(
.into(), .into(),
}; };
let block_import = GrandpaBlockImport { Ok((
inner: client.clone(), GrandpaBlockImport { inner: client.clone(), authority_set: authority_set.clone() },
authority_set: authority_set.clone(), LinkHalf { client, authority_set },
}; ))
}
/// Run a GRANDPA voter as a task. Provide configuration and a link to a
/// block import worker that has already been instantiated with `block_import`.
pub fn run_grandpa<B, E, Block: BlockT, N>(
config: Config,
link: LinkHalf<B, E, Block>,
network: N,
) -> ::client::error::Result<impl Future<Item=(),Error=()>> where
Block::Hash: Ord,
B: Backend<Block, Blake2Hasher> + 'static,
E: CallExecutor<Block, Blake2Hasher> + 'static,
N: Network + 'static,
N::In: 'static,
NumberFor<Block>: BlockNumberOps,
DigestFor<Block>: Encode,
{
use futures::future::{self, Loop as FutureLoop};
use runtime_primitives::traits::Zero;
let LinkHalf { client, authority_set } = link;
let chain_info = client.info()?;
let genesis_hash = chain_info.chain.genesis_hash;
let (last_round_number, last_state) = match client.backend().get_aux(LAST_COMPLETED_KEY)? { let (last_round_number, last_state) = match client.backend().get_aux(LAST_COMPLETED_KEY)? {
None => (0, RoundState::genesis((genesis_hash, <NumberFor<Block>>::zero()))), None => (0, RoundState::genesis((genesis_hash, <NumberFor<Block>>::zero()))),
@@ -815,6 +833,10 @@ pub fn run_grandpa<B, E, Block: BlockT, N>(
))? ))?
}; };
let voters = authority_set.inner().read().current().1.iter()
.cloned()
.collect();
let initial_environment = Arc::new(Environment { let initial_environment = Arc::new(Environment {
inner: client.clone(), inner: client.clone(),
config: config.clone(), config: config.clone(),
@@ -824,7 +846,7 @@ pub fn run_grandpa<B, E, Block: BlockT, N>(
authority_set: authority_set.clone(), authority_set: authority_set.clone(),
}); });
let voters = future::loop_fn((initial_environment, last_round_number, last_state), move |params| { let work = future::loop_fn((initial_environment, last_round_number, last_state), move |params| {
let (env, last_round_number, last_state) = params; let (env, last_round_number, last_state) = params;
let chain_info = match client.info() { let chain_info = match client.info() {
Ok(i) => i, Ok(i) => i,
@@ -866,29 +888,84 @@ pub fn run_grandpa<B, E, Block: BlockT, N>(
})) }))
}); });
let work = voters.map_err(|e| warn!("GRANDPA Voter failed: {:?}", e)); Ok(work.map_err(|e| warn!("GRANDPA Voter failed: {:?}", e)))
Ok((work, block_import))
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use network::test::*; use network::test::{Block, Hash, TestNetFactory, Peer, PeersClient};
use network::import_queue::{PassThroughVerifier};
use network::ProtocolConfig;
use parking_lot::Mutex; use parking_lot::Mutex;
use tokio::runtime::current_thread; use tokio::runtime::current_thread;
use keyring::Keyring; use keyring::Keyring;
use client::BlockchainEvents; use client::BlockchainEvents;
use test_client;
type PeerData = Mutex<Option<LinkHalf<test_client::Backend, test_client::Executor, Block>>>;
type GrandpaPeer = Peer<PassThroughVerifier, PeerData>;
struct GrandpaTestNet {
peers: Vec<Arc<GrandpaPeer>>,
started: bool
}
impl TestNetFactory for GrandpaTestNet {
type Verifier = PassThroughVerifier;
type PeerData = PeerData;
/// Create new test network with peers and given config.
fn from_config(_config: &ProtocolConfig) -> Self {
GrandpaTestNet {
peers: Vec::new(),
started: false
}
}
fn make_verifier(&self, _client: Arc<PeersClient>, _cfg: &ProtocolConfig)
-> Arc<Self::Verifier>
{
Arc::new(PassThroughVerifier(false)) // use non-instant finality.
}
fn make_block_import(&self, client: Arc<PeersClient>)
-> (Arc<BlockImport<Block,Error=ClientError> + Send + Sync>, PeerData)
{
let (import, link) = block_import(client).expect("Could not create block import for fresh peer.");
(Arc::new(import), Mutex::new(Some(link)))
}
fn peer(&self, i: usize) -> &GrandpaPeer {
&self.peers[i]
}
fn peers(&self) -> &Vec<Arc<GrandpaPeer>> {
&self.peers
}
fn mut_peers<F: Fn(&mut Vec<Arc<GrandpaPeer>>)>(&mut self, closure: F) {
closure(&mut self.peers);
}
fn started(&self) -> bool {
self.started
}
fn set_started(&mut self, new: bool) {
self.started = new;
}
}
#[derive(Clone)] #[derive(Clone)]
struct TestGrandpaNetwork { struct MessageRouting {
inner: Arc<Mutex<TestNet>>, inner: Arc<Mutex<GrandpaTestNet>>,
peer_id: usize, peer_id: usize,
} }
impl TestGrandpaNetwork { impl MessageRouting {
fn new(inner: Arc<Mutex<TestNet>>, peer_id: usize,) -> Self { fn new(inner: Arc<Mutex<GrandpaTestNet>>, peer_id: usize,) -> Self {
TestGrandpaNetwork { MessageRouting {
inner, inner,
peer_id, peer_id,
} }
@@ -904,7 +981,7 @@ mod tests {
hash hash
} }
impl Network for TestGrandpaNetwork { impl Network for MessageRouting {
type In = Box<Stream<Item=Vec<u8>,Error=()>>; type In = Box<Stream<Item=Vec<u8>,Error=()>>;
fn messages_for(&self, round: u64) -> Self::In { fn messages_for(&self, round: u64) -> Self::In {
@@ -936,7 +1013,7 @@ mod tests {
#[test] #[test]
fn finalize_20_unanimous_3_peers() { fn finalize_20_unanimous_3_peers() {
let mut net = TestNet::new(3); let mut net = GrandpaTestNet::new(3);
net.peer(0).push_blocks(20, false); net.peer(0).push_blocks(20, false);
net.sync(); net.sync();
@@ -955,20 +1032,27 @@ mod tests {
let mut runtime = current_thread::Runtime::new().unwrap(); let mut runtime = current_thread::Runtime::new().unwrap();
for (peer_id, key) in peers { for (peer_id, key) in peers {
let client = net.lock().peer(*peer_id).client().clone(); let (client, link) = {
let mut net = net.lock();
// temporary needed for some reason
let link = net.peers[*peer_id].data.lock().take().expect("link initialized at startup; qed");
(
net.peers[*peer_id].client().clone(),
link,
)
};
finality_notifications.push( finality_notifications.push(
client.finality_notification_stream() client.finality_notification_stream()
.take_while(|n| Ok(n.header.number() < &20)) .take_while(|n| Ok(n.header.number() < &20))
.for_each(move |_| Ok(())) .for_each(move |_| Ok(()))
); );
let (voter, _) = run_grandpa( let voter = run_grandpa(
Config { Config {
gossip_duration: TEST_GOSSIP_DURATION, gossip_duration: TEST_GOSSIP_DURATION,
local_key: Some(Arc::new(key.clone().into())), local_key: Some(Arc::new(key.clone().into())),
}, },
client, link,
voters.iter().map(|&id| (id, 1)).collect(), MessageRouting::new(net.clone(), *peer_id),
TestGrandpaNetwork::new(net.clone(), *peer_id),
).expect("all in order with client and network"); ).expect("all in order with client and network");
runtime.spawn(voter); runtime.spawn(voter);
@@ -989,7 +1073,7 @@ mod tests {
#[test] #[test]
fn observer_can_finalize() { fn observer_can_finalize() {
let mut net = TestNet::new(4); let mut net = GrandpaTestNet::new(4);
net.peer(0).push_blocks(20, false); net.peer(0).push_blocks(20, false);
net.sync(); net.sync();
@@ -1013,20 +1097,26 @@ mod tests {
.chain(::std::iter::once((3, None))); .chain(::std::iter::once((3, None)));
for (peer_id, local_key) in all_peers { for (peer_id, local_key) in all_peers {
let client = net.lock().peer(peer_id).client().clone(); let (client, link) = {
let mut net = net.lock();
let link = net.peers[peer_id].data.lock().take().expect("link initialized at startup; qed");
(
net.peers[peer_id].client().clone(),
link,
)
};
finality_notifications.push( finality_notifications.push(
client.finality_notification_stream() client.finality_notification_stream()
.take_while(|n| Ok(n.header.number() < &20)) .take_while(|n| Ok(n.header.number() < &20))
.for_each(move |_| Ok(())) .for_each(move |_| Ok(()))
); );
let (voter, _) = run_grandpa( let voter = run_grandpa(
Config { Config {
gossip_duration: TEST_GOSSIP_DURATION, gossip_duration: TEST_GOSSIP_DURATION,
local_key, local_key,
}, },
client, link,
voters.clone(), MessageRouting::new(net.clone(), peer_id),
TestGrandpaNetwork::new(net.clone(), peer_id),
).expect("all in order with client and network"); ).expect("all in order with client and network");
runtime.spawn(voter); runtime.spawn(voter);
+1 -1
View File
@@ -324,7 +324,7 @@ pub trait TestNetFactory: Sized {
/// Get reference to peer. /// Get reference to peer.
fn peer(&self, i: usize) -> &Peer<Self::Verifier, Self::PeerData>; fn peer(&self, i: usize) -> &Peer<Self::Verifier, Self::PeerData>;
fn peers(&self) -> &Vec<Arc<Peer<Self::Verifier, Self::PeerData>>>; fn peers(&self) -> &Vec<Arc<Peer<Self::Verifier, Self::PeerData>>>;
fn mut_peers<F: Fn(&mut Vec<Arc<Peer<Self::Verifier, Self::PeerData>>>)>(&mut self, closure: F ); fn mut_peers<F: Fn(&mut Vec<Arc<Peer<Self::Verifier, Self::PeerData>>>)>(&mut self, closure: F);
fn started(&self) -> bool; fn started(&self) -> bool;
fn set_started(&mut self, now: bool); fn set_started(&mut self, now: bool);