From 8ac3808fcb90dda8f839ce4f0a8e01bd00b449f3 Mon Sep 17 00:00:00 2001 From: Hoverbear Date: Fri, 21 Sep 2018 14:30:21 -0700 Subject: [PATCH 1/9] Extract Network and Interface from utils --- Cargo.toml | 10 +- src/harness/interface.rs | 120 ++++++++++++ src/harness/mod.rs | 39 ++++ src/harness/network.rs | 184 ++++++++++++++++++ src/lib.rs | 9 +- tests/integration_cases/test_raft.rs | 1 + tests/integration_cases/test_raft_paper.rs | 1 + tests/integration_cases/test_raw_node.rs | 1 + tests/test_util/mod.rs | 210 +-------------------- 9 files changed, 364 insertions(+), 211 deletions(-) create mode 100644 src/harness/interface.rs create mode 100644 src/harness/mod.rs create mode 100644 src/harness/network.rs diff --git a/Cargo.toml b/Cargo.toml index a22f58afd..822fbfe3b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,8 +12,12 @@ description = "The rust language implementation of Raft algorithm." categories = ["algorithms", "database-implementations"] [features] -default = [] +default = ["harness"] +# Enable failpoints failpoint = ["fail"] +# Enable the testing harness. +# This is required to run `cargo test` or `cargo bench`. +harness = ["env_logger"] [dependencies] log = ">0.2" @@ -21,10 +25,12 @@ protobuf = "2.0.4" quick-error = "1.2.2" rand = "0.5.4" fxhash = "0.2.1" +# Rust does not offer a common feature flag for tests and benches. +# So we have these optional behind features. fail = { version = "0.2", optional = true } +env_logger = { version = "0.5", optional = true } [dev-dependencies] -env_logger = "0.5" criterion = ">0.2.4" lazy_static = "1.0" diff --git a/src/harness/interface.rs b/src/harness/interface.rs new file mode 100644 index 000000000..e55960a65 --- /dev/null +++ b/src/harness/interface.rs @@ -0,0 +1,120 @@ +// Copyright 2018 PingCAP, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// See the License for the specific language governing permissions and +// limitations under the License. + +// Copyright 2015 CoreOS, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use std::ops::{Deref, DerefMut}; +use {eraftpb::Message, storage::MemStorage, Progress, ProgressSet, Raft, Result}; + +/// A simulated Raft façade for testing. +/// +/// If the contained value is a `Some` operations happen. If they are a `None` operations are +/// a no-op. +/// +// Compare to upstream, we use struct instead of trait here. +// Because to be able to cast Interface later, we have to make +// Raft derive Any, which will require a lot of dependencies to derive Any. +// That's not worthy for just testing purpose. +pub struct Interface { + /// The raft peer. + pub raft: Option>, +} + +impl Interface { + /// Create a new interface to a new raft. + pub fn new(r: Raft) -> Interface { + Interface { raft: Some(r) } + } + + /// Step the raft, if it exists. + pub fn step(&mut self, m: Message) -> Result<()> { + match self.raft { + Some(_) => Raft::step(self, m), + None => Ok(()), + } + } + + /// Read messages out of the raft. + pub fn read_messages(&mut self) -> Vec { + match self.raft { + Some(_) => self.msgs.drain(..).collect(), + None => vec![], + } + } + + /// Initialize a raft with the given ID and peer set. + pub fn initial(&mut self, id: u64, ids: &[u64]) { + if self.raft.is_some() { + self.id = id; + let prs = self.take_prs(); + self.set_prs(ProgressSet::new(ids.len(), prs.learners().len())); + for id in ids { + if prs.learners().contains_key(id) { + let progress = Progress { + is_learner: true, + ..Default::default() + }; + if let Err(e) = self.mut_prs().insert_learner(*id, progress) { + panic!("{}", e); + } + } else { + let progress = Progress { + ..Default::default() + }; + if let Err(e) = self.mut_prs().insert_voter(*id, progress) { + panic!("{}", e); + } + } + } + let term = self.term; + self.reset(term); + } + } +} + +impl From>> for Interface { + fn from(raft: Option>) -> Self { + Self { raft } + } +} + +impl From> for Interface { + fn from(raft: Raft) -> Self { + Self { raft: Some(raft) } + } +} + +impl Deref for Interface { + type Target = Raft; + fn deref(&self) -> &Raft { + self.raft.as_ref().unwrap() + } +} + +impl DerefMut for Interface { + fn deref_mut(&mut self) -> &mut Raft { + self.raft.as_mut().unwrap() + } +} diff --git a/src/harness/mod.rs b/src/harness/mod.rs new file mode 100644 index 000000000..6ae13fbf4 --- /dev/null +++ b/src/harness/mod.rs @@ -0,0 +1,39 @@ +// Copyright 2018 PingCAP, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// See the License for the specific language governing permissions and +// limitations under the License. + +// Copyright 2015 The etcd Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/*! + +This module contains various testing harness utilities for Raft. + +> If you want to build Raft without this, disable the `harness` feature. + +*/ + +mod interface; +mod network; + +pub use self::{interface::Interface, network::Network}; diff --git a/src/harness/network.rs b/src/harness/network.rs new file mode 100644 index 000000000..36bdd93ea --- /dev/null +++ b/src/harness/network.rs @@ -0,0 +1,184 @@ +// Copyright 2018 PingCAP, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// See the License for the specific language governing permissions and +// limitations under the License. + +// Copyright 2015 CoreOS, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use super::interface::Interface; +use rand; +use std::collections::HashMap; +use { + eraftpb::{Message, MessageType}, + storage::MemStorage, + Config, Raft, NO_LIMIT, +}; + +#[derive(Default, Debug, PartialEq, Eq, Hash)] +struct Connem { + from: u64, + to: u64, +} + +/// A simulated network for testing. +/// +/// You can use this to create a test network of Raft nodes. +/// +/// *Please note:* no actual network calls are made. +#[derive(Default)] +pub struct Network { + /// The set of raft peers. + pub peers: HashMap, + /// The storage of the raft peers. + pub storage: HashMap, + dropm: HashMap, + ignorem: HashMap, +} + +impl Network { + /// Initializes a network from peers. + /// + /// Nodes will recieve their ID based on their index in the vector, starting with 1. + /// + /// A `None` node will be replaced with a new Raft node. + pub fn new(peers: Vec>) -> Network { + Network::new_with_config(peers, false) + } + + /// Explicitly set the pre_vote option on newly created rafts. + /// + /// **TODO:** Make this accept any config. + pub fn new_with_config(mut peers: Vec>, pre_vote: bool) -> Network { + let size = peers.len(); + let peer_addrs: Vec = (1..size as u64 + 1).collect(); + let mut nstorage = HashMap::new(); + let mut npeers = HashMap::new(); + for (p, id) in peers.drain(..).zip(peer_addrs.clone()) { + match p { + None => { + nstorage.insert(id, MemStorage::default()); + let r = Interface::new(Raft::new( + &Config { + id, + peers: peer_addrs.clone(), + election_tick: 10, + heartbeat_tick: 1, + max_size_per_msg: NO_LIMIT, + max_inflight_msgs: 256, + pre_vote, + ..Default::default() + }, + nstorage[&id].clone(), + )); + npeers.insert(id, r); + } + Some(mut p) => { + p.initial(id, &peer_addrs); + npeers.insert(id, p); + } + } + } + Network { + peers: npeers, + storage: nstorage, + ..Default::default() + } + } + + /// Ignore a given `MessageType`. + pub fn ignore(&mut self, t: MessageType) { + self.ignorem.insert(t, true); + } + + /// Filter out messages that should be dropped according to rules set by `ignore` or `drop`. + pub fn filter(&self, mut msgs: Vec) -> Vec { + msgs.drain(..) + .filter(|m| { + if self + .ignorem + .get(&m.get_msg_type()) + .cloned() + .unwrap_or(false) + { + return false; + } + // hups never go over the network, so don't drop them but panic + assert_ne!(m.get_msg_type(), MessageType::MsgHup, "unexpected msgHup"); + let perc = self + .dropm + .get(&Connem { + from: m.get_from(), + to: m.get_to(), + }).cloned() + .unwrap_or(0f64); + rand::random::() >= perc + }).collect() + } + + /// Instruct the cluster to `step` through the given messages. + pub fn send(&mut self, msgs: Vec) { + let mut msgs = msgs; + while !msgs.is_empty() { + let mut new_msgs = vec![]; + for m in msgs.drain(..) { + let resp = { + let p = self.peers.get_mut(&m.get_to()).unwrap(); + let _ = p.step(m); + p.read_messages() + }; + new_msgs.append(&mut self.filter(resp)); + } + msgs.append(&mut new_msgs); + } + } + + /// Ignore messages from `from` to `to` at `perc` percent chance. + /// + /// `perc` set to `1f64` is a 100% chance, `0f64` is a 0% chance. + pub fn drop(&mut self, from: u64, to: u64, perc: f64) { + self.dropm.insert(Connem { from, to }, perc); + } + + /// Cut the communication between the two given nodes. + pub fn cut(&mut self, one: u64, other: u64) { + self.drop(one, other, 1f64); + self.drop(other, one, 1f64); + } + + /// Isolate the given raft to and from all other raft in the cluster. + pub fn isolate(&mut self, id: u64) { + for i in 0..self.peers.len() as u64 { + let nid = i + 1; + if nid != id { + self.drop(id, nid, 1.0); + self.drop(nid, id, 1.0); + } + } + } + + /// Recover the cluster conditions applied with `drop` and `ignore`. + pub fn recover(&mut self) { + self.dropm = HashMap::new(); + self.ignorem = HashMap::new(); + } +} diff --git a/src/lib.rs b/src/lib.rs index 21d4446c7..39e8ea5cd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -272,7 +272,7 @@ extern crate log; extern crate protobuf; #[macro_use] extern crate quick_error; -#[cfg(test)] +#[cfg(feature = "harness")] extern crate env_logger; extern crate rand; @@ -281,6 +281,8 @@ mod config; /// documented by field. pub mod eraftpb; mod errors; +#[cfg(feature = "harness")] +pub mod harness; mod log_unstable; mod progress; #[cfg(test)] @@ -340,7 +342,8 @@ pub mod prelude { } /// Do any common test initialization. Eg set up logging, setup fail-rs. -#[cfg(test)] -fn setup_for_test() { +#[cfg(feature = "harness")] +#[doc(hidden)] +pub fn setup_for_test() { let _ = env_logger::try_init(); } diff --git a/tests/integration_cases/test_raft.rs b/tests/integration_cases/test_raft.rs index 591e09130..d067fb146 100644 --- a/tests/integration_cases/test_raft.rs +++ b/tests/integration_cases/test_raft.rs @@ -33,6 +33,7 @@ use protobuf::{self, RepeatedField}; use raft::eraftpb::{ ConfChange, ConfChangeType, ConfState, Entry, EntryType, HardState, Message, MessageType, }; +use raft::harness::*; use raft::storage::MemStorage; use raft::*; use test_util::*; diff --git a/tests/integration_cases/test_raft_paper.rs b/tests/integration_cases/test_raft_paper.rs index d5bd026bb..540c88294 100644 --- a/tests/integration_cases/test_raft_paper.rs +++ b/tests/integration_cases/test_raft_paper.rs @@ -27,6 +27,7 @@ use protobuf::RepeatedField; use raft::eraftpb::*; +use raft::harness::*; use raft::storage::MemStorage; use raft::*; use test_util::*; diff --git a/tests/integration_cases/test_raw_node.rs b/tests/integration_cases/test_raw_node.rs index cd60c8301..61525acbc 100644 --- a/tests/integration_cases/test_raw_node.rs +++ b/tests/integration_cases/test_raw_node.rs @@ -27,6 +27,7 @@ use protobuf::{self, ProtobufEnum}; use raft::eraftpb::*; +use raft::harness::*; use raft::storage::MemStorage; use raft::*; use test_util::*; diff --git a/tests/test_util/mod.rs b/tests/test_util/mod.rs index 7fc04a3ad..4eb33530e 100644 --- a/tests/test_util/mod.rs +++ b/tests/test_util/mod.rs @@ -25,19 +25,15 @@ // See the License for the specific language governing permissions and // limitations under the License. -use env_logger; use protobuf::RepeatedField; use raft::eraftpb::*; +use raft::harness::*; +pub use raft::setup_for_test; use raft::storage::MemStorage; use raft::*; -use rand; -use std::collections::HashMap; -use std::ops::*; -/// Do any common test initialization. Eg set up logging, setup fail-rs. -pub fn setup_for_test() { - let _ = env_logger::try_init(); -} +#[allow(declare_interior_mutable_const)] +pub const NOP_STEPPER: Option = Some(Interface { raft: None }); pub fn ltoa(raft_log: &RaftLog) -> String { let mut s = format!("committed: {}\n", raft_log.committed); @@ -69,75 +65,6 @@ pub fn new_test_config( } } -/// Compare to upstream, we use struct instead of trait here. -/// Because to be able to cast Interface later, we have to make -/// Raft derive Any, which will require a lot of dependencies to derive Any. -/// That's not worthy for just testing purpose. -pub struct Interface { - pub raft: Option>, -} - -impl Interface { - pub fn new(r: Raft) -> Interface { - Interface { raft: Some(r) } - } - - pub fn step(&mut self, m: Message) -> Result<()> { - match self.raft { - Some(_) => Raft::step(self, m), - None => Ok(()), - } - } - - pub fn read_messages(&mut self) -> Vec { - match self.raft { - Some(_) => self.msgs.drain(..).collect(), - None => vec![], - } - } - - fn initial(&mut self, id: u64, ids: &[u64]) { - if self.raft.is_some() { - self.id = id; - let prs = self.take_prs(); - self.set_prs(ProgressSet::new(ids.len(), prs.learners().len())); - for id in ids { - if prs.learners().contains_key(id) { - let progress = Progress { - is_learner: true, - ..Default::default() - }; - if let Err(e) = self.mut_prs().insert_learner(*id, progress) { - panic!("{}", e); - } - } else { - let progress = Progress { - ..Default::default() - }; - if let Err(e) = self.mut_prs().insert_voter(*id, progress) { - panic!("{}", e); - } - } - } - let term = self.term; - self.reset(term); - } - } -} - -impl Deref for Interface { - type Target = Raft; - fn deref(&self) -> &Raft { - self.raft.as_ref().unwrap() - } -} - -impl DerefMut for Interface { - fn deref_mut(&mut self) -> &mut Raft { - self.raft.as_mut().unwrap() - } -} - pub fn new_test_raft( id: u64, peers: Vec, @@ -222,132 +149,3 @@ pub fn new_snapshot(index: u64, term: u64, nodes: Vec) -> Snapshot { s.mut_metadata().mut_conf_state().set_nodes(nodes); s } - -#[derive(Default, Debug, PartialEq, Eq, Hash)] -struct Connem { - from: u64, - to: u64, -} - -#[allow(declare_interior_mutable_const)] -pub const NOP_STEPPER: Option = Some(Interface { raft: None }); - -#[derive(Default)] -pub struct Network { - pub peers: HashMap, - pub storage: HashMap, - dropm: HashMap, - ignorem: HashMap, -} - -impl Network { - // initializes a network from peers. - // A nil node will be replaced with a new *stateMachine. - // A *stateMachine will get its k, id. - // When using stateMachine, the address list is always [1, n]. - pub fn new(peers: Vec>) -> Network { - Network::new_with_config(peers, false) - } - - // new_with_config is like new but sets the configuration pre_vote explicitly - // for any state machines it creates. - pub fn new_with_config(mut peers: Vec>, pre_vote: bool) -> Network { - let size = peers.len(); - let peer_addrs: Vec = (1..size as u64 + 1).collect(); - let mut nstorage = HashMap::new(); - let mut npeers = HashMap::new(); - for (p, id) in peers.drain(..).zip(peer_addrs.clone()) { - match p { - None => { - nstorage.insert(id, new_storage()); - let r = new_test_raft_with_prevote( - id, - peer_addrs.clone(), - 10, - 1, - nstorage[&id].clone(), - pre_vote, - ); - npeers.insert(id, r); - } - Some(mut p) => { - p.initial(id, &peer_addrs); - npeers.insert(id, p); - } - } - } - Network { - peers: npeers, - storage: nstorage, - ..Default::default() - } - } - - pub fn ignore(&mut self, t: MessageType) { - self.ignorem.insert(t, true); - } - - pub fn filter(&self, mut msgs: Vec) -> Vec { - msgs.drain(..) - .filter(|m| { - if self - .ignorem - .get(&m.get_msg_type()) - .cloned() - .unwrap_or(false) - { - return false; - } - // hups never go over the network, so don't drop them but panic - assert_ne!(m.get_msg_type(), MessageType::MsgHup, "unexpected msgHup"); - let perc = self - .dropm - .get(&Connem { - from: m.get_from(), - to: m.get_to(), - }).cloned() - .unwrap_or(0f64); - rand::random::() >= perc - }).collect() - } - - pub fn send(&mut self, msgs: Vec) { - let mut msgs = msgs; - while !msgs.is_empty() { - let mut new_msgs = vec![]; - for m in msgs.drain(..) { - let resp = { - let p = self.peers.get_mut(&m.get_to()).unwrap(); - let _ = p.step(m); - p.read_messages() - }; - new_msgs.append(&mut self.filter(resp)); - } - msgs.append(&mut new_msgs); - } - } - - pub fn drop(&mut self, from: u64, to: u64, perc: f64) { - self.dropm.insert(Connem { from, to }, perc); - } - - pub fn cut(&mut self, one: u64, other: u64) { - self.drop(one, other, 1f64); - self.drop(other, one, 1f64); - } - - pub fn isolate(&mut self, id: u64) { - for i in 0..self.peers.len() as u64 { - let nid = i + 1; - if nid != id { - self.drop(id, nid, 1.0); - self.drop(nid, id, 1.0); - } - } - } - - pub fn recover(&mut self) { - self.dropm = HashMap::new(); - self.ignorem = HashMap::new(); - } -} From 918c35a78fe1e2520168c1467415edfea7d375de Mon Sep 17 00:00:00 2001 From: Hoverbear Date: Wed, 10 Oct 2018 15:26:45 -0700 Subject: [PATCH 2/9] Use a component --- .gitignore | 2 ++ Cargo.toml | 16 +++++++++------- harness/Cargo.toml | 18 ++++++++++++++++++ {src/harness => harness/src}/interface.rs | 2 +- src/harness/mod.rs => harness/src/lib.rs | 3 +++ {src/harness => harness/src}/network.rs | 2 +- src/lib.rs | 6 +----- tests/integration_cases/test_raft.rs | 2 +- tests/integration_cases/test_raft_paper.rs | 2 +- tests/integration_cases/test_raw_node.rs | 2 +- tests/test_util/mod.rs | 2 +- tests/tests.rs | 2 ++ 12 files changed, 41 insertions(+), 18 deletions(-) create mode 100644 harness/Cargo.toml rename {src/harness => harness/src}/interface.rs (97%) rename src/harness/mod.rs => harness/src/lib.rs (97%) rename {src/harness => harness/src}/network.rs (99%) diff --git a/.gitignore b/.gitignore index a484e4d95..c4f2457f7 100644 --- a/.gitignore +++ b/.gitignore @@ -25,6 +25,8 @@ target tmp /bin +harness/target + Cargo.lock *.rs.bk *.rs.fmt diff --git a/Cargo.toml b/Cargo.toml index 822fbfe3b..0c0ebd87e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,27 +12,29 @@ description = "The rust language implementation of Raft algorithm." categories = ["algorithms", "database-implementations"] [features] -default = ["harness"] +default = [] # Enable failpoints failpoint = ["fail"] -# Enable the testing harness. -# This is required to run `cargo test` or `cargo bench`. -harness = ["env_logger"] +# Make sure to synchronize updates with Harness. [dependencies] log = ">0.2" protobuf = "2.0.4" quick-error = "1.2.2" rand = "0.5.4" fxhash = "0.2.1" -# Rust does not offer a common feature flag for tests and benches. -# So we have these optional behind features. fail = { version = "0.2", optional = true } -env_logger = { version = "0.5", optional = true } +env_logger = "0.5" [dev-dependencies] criterion = ">0.2.4" lazy_static = "1.0" +harness = { path = "harness" } + +[workspace] +members = [ + "harness", +] [[bench]] name = "benches" diff --git a/harness/Cargo.toml b/harness/Cargo.toml new file mode 100644 index 000000000..a1ca2e9cb --- /dev/null +++ b/harness/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "harness" +version = "0.1.0" +authors = ["The TiKV Project Developers"] +license = "Apache-2.0" +keywords = [] +repository = "https://github.com/pingcap/raft-rs/harness" +readme = "README.md" +homepage = "https://github.com/pingcap/raft-rs/harness" +description = "A testing harness for Raft." +categories = [] + +# Make sure to synchronize updates with Raft. +[dependencies] +raft = { path = ".." } +rand = "0.5.4" + +[dev-dependencies] diff --git a/src/harness/interface.rs b/harness/src/interface.rs similarity index 97% rename from src/harness/interface.rs rename to harness/src/interface.rs index e55960a65..49c9c40a3 100644 --- a/src/harness/interface.rs +++ b/harness/src/interface.rs @@ -26,7 +26,7 @@ // limitations under the License. use std::ops::{Deref, DerefMut}; -use {eraftpb::Message, storage::MemStorage, Progress, ProgressSet, Raft, Result}; +use raft::{eraftpb::Message, storage::MemStorage, Progress, ProgressSet, Raft, Result}; /// A simulated Raft façade for testing. /// diff --git a/src/harness/mod.rs b/harness/src/lib.rs similarity index 97% rename from src/harness/mod.rs rename to harness/src/lib.rs index 6ae13fbf4..6f150d629 100644 --- a/src/harness/mod.rs +++ b/harness/src/lib.rs @@ -33,6 +33,9 @@ This module contains various testing harness utilities for Raft. */ +extern crate raft; +extern crate rand; + mod interface; mod network; diff --git a/src/harness/network.rs b/harness/src/network.rs similarity index 99% rename from src/harness/network.rs rename to harness/src/network.rs index 36bdd93ea..256be2206 100644 --- a/src/harness/network.rs +++ b/harness/src/network.rs @@ -28,7 +28,7 @@ use super::interface::Interface; use rand; use std::collections::HashMap; -use { +use raft::{ eraftpb::{Message, MessageType}, storage::MemStorage, Config, Raft, NO_LIMIT, diff --git a/src/lib.rs b/src/lib.rs index 39e8ea5cd..3e34c1586 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -272,7 +272,6 @@ extern crate log; extern crate protobuf; #[macro_use] extern crate quick_error; -#[cfg(feature = "harness")] extern crate env_logger; extern crate rand; @@ -281,8 +280,6 @@ mod config; /// documented by field. pub mod eraftpb; mod errors; -#[cfg(feature = "harness")] -pub mod harness; mod log_unstable; mod progress; #[cfg(test)] @@ -341,8 +338,7 @@ pub mod prelude { pub use read_only::{ReadOnlyOption, ReadState}; } -/// Do any common test initialization. Eg set up logging, setup fail-rs. -#[cfg(feature = "harness")] +/// Do any common test initialization. Eg set up logging. #[doc(hidden)] pub fn setup_for_test() { let _ = env_logger::try_init(); diff --git a/tests/integration_cases/test_raft.rs b/tests/integration_cases/test_raft.rs index d067fb146..ae6a9d426 100644 --- a/tests/integration_cases/test_raft.rs +++ b/tests/integration_cases/test_raft.rs @@ -33,7 +33,7 @@ use protobuf::{self, RepeatedField}; use raft::eraftpb::{ ConfChange, ConfChangeType, ConfState, Entry, EntryType, HardState, Message, MessageType, }; -use raft::harness::*; +use harness::*; use raft::storage::MemStorage; use raft::*; use test_util::*; diff --git a/tests/integration_cases/test_raft_paper.rs b/tests/integration_cases/test_raft_paper.rs index 540c88294..8153a1ad5 100644 --- a/tests/integration_cases/test_raft_paper.rs +++ b/tests/integration_cases/test_raft_paper.rs @@ -27,7 +27,7 @@ use protobuf::RepeatedField; use raft::eraftpb::*; -use raft::harness::*; +use harness::*; use raft::storage::MemStorage; use raft::*; use test_util::*; diff --git a/tests/integration_cases/test_raw_node.rs b/tests/integration_cases/test_raw_node.rs index 61525acbc..595ab4e4f 100644 --- a/tests/integration_cases/test_raw_node.rs +++ b/tests/integration_cases/test_raw_node.rs @@ -27,7 +27,7 @@ use protobuf::{self, ProtobufEnum}; use raft::eraftpb::*; -use raft::harness::*; +use harness::*; use raft::storage::MemStorage; use raft::*; use test_util::*; diff --git a/tests/test_util/mod.rs b/tests/test_util/mod.rs index 4eb33530e..d662cd32f 100644 --- a/tests/test_util/mod.rs +++ b/tests/test_util/mod.rs @@ -27,7 +27,7 @@ use protobuf::RepeatedField; use raft::eraftpb::*; -use raft::harness::*; +use harness::*; pub use raft::setup_for_test; use raft::storage::MemStorage; use raft::*; diff --git a/tests/tests.rs b/tests/tests.rs index d19c5d013..5e548bf4f 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -25,6 +25,7 @@ extern crate rand; extern crate lazy_static; #[cfg(feature = "failpoint")] extern crate fail; +extern crate harness; /// Get the count of macro's arguments. /// @@ -93,3 +94,4 @@ mod failpoint_cases; #[cfg(not(feature = "failpoint"))] mod integration_cases; mod test_util; + From bbfbf8a96a829c6ad34c2c45376c7ce3b5b8c2b0 Mon Sep 17 00:00:00 2001 From: Hoverbear Date: Wed, 10 Oct 2018 15:40:01 -0700 Subject: [PATCH 3/9] fmt --- Cargo.toml | 5 ---- harness/src/interface.rs | 2 +- harness/src/network.rs | 32 ++++++++++++---------- tests/integration_cases/test_raft.rs | 2 +- tests/integration_cases/test_raft_paper.rs | 2 +- tests/integration_cases/test_raw_node.rs | 2 +- tests/test_util/mod.rs | 2 +- tests/tests.rs | 3 +- 8 files changed, 23 insertions(+), 27 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0c0ebd87e..cca4336b7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,11 +31,6 @@ criterion = ">0.2.4" lazy_static = "1.0" harness = { path = "harness" } -[workspace] -members = [ - "harness", -] - [[bench]] name = "benches" harness = false diff --git a/harness/src/interface.rs b/harness/src/interface.rs index 09f45a02a..b69d091ac 100644 --- a/harness/src/interface.rs +++ b/harness/src/interface.rs @@ -25,8 +25,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::ops::{Deref, DerefMut}; use raft::{eraftpb::Message, storage::MemStorage, Progress, ProgressSet, Raft, Result}; +use std::ops::{Deref, DerefMut}; /// A simulated Raft façade for testing. /// diff --git a/harness/src/network.rs b/harness/src/network.rs index 8dbbaf954..04f436582 100644 --- a/harness/src/network.rs +++ b/harness/src/network.rs @@ -26,13 +26,13 @@ // limitations under the License. use super::interface::Interface; -use rand; -use std::collections::HashMap; use raft::{ eraftpb::{Message, MessageType}, storage::MemStorage, Config, Raft, NO_LIMIT, }; +use rand; +use std::collections::HashMap; #[derive(Default, Debug, PartialEq, Eq, Hash)] struct Connem { @@ -77,19 +77,21 @@ impl Network { match p { None => { nstorage.insert(id, MemStorage::default()); - let r = Interface::new(Raft::new( - &Config { - id, - peers: peer_addrs.clone(), - election_tick: 10, - heartbeat_tick: 1, - max_size_per_msg: NO_LIMIT, - max_inflight_msgs: 256, - pre_vote, - ..Default::default() - }, - nstorage[&id].clone(), - ).unwrap()); + let r = Interface::new( + Raft::new( + &Config { + id, + peers: peer_addrs.clone(), + election_tick: 10, + heartbeat_tick: 1, + max_size_per_msg: NO_LIMIT, + max_inflight_msgs: 256, + pre_vote, + ..Default::default() + }, + nstorage[&id].clone(), + ).unwrap(), + ); npeers.insert(id, r); } Some(mut p) => { diff --git a/tests/integration_cases/test_raft.rs b/tests/integration_cases/test_raft.rs index 0a41c2564..93da9e20c 100644 --- a/tests/integration_cases/test_raft.rs +++ b/tests/integration_cases/test_raft.rs @@ -30,11 +30,11 @@ use std::collections::HashMap; use std::panic::{self, AssertUnwindSafe}; use fxhash::FxHashSet; +use harness::*; use protobuf::{self, RepeatedField}; use raft::eraftpb::{ ConfChange, ConfChangeType, ConfState, Entry, EntryType, HardState, Message, MessageType, }; -use harness::*; use raft::storage::MemStorage; use raft::*; use test_util::*; diff --git a/tests/integration_cases/test_raft_paper.rs b/tests/integration_cases/test_raft_paper.rs index 8153a1ad5..a30c607d6 100644 --- a/tests/integration_cases/test_raft_paper.rs +++ b/tests/integration_cases/test_raft_paper.rs @@ -25,9 +25,9 @@ // See the License for the specific language governing permissions and // limitations under the License. +use harness::*; use protobuf::RepeatedField; use raft::eraftpb::*; -use harness::*; use raft::storage::MemStorage; use raft::*; use test_util::*; diff --git a/tests/integration_cases/test_raw_node.rs b/tests/integration_cases/test_raw_node.rs index 595ab4e4f..e833532c1 100644 --- a/tests/integration_cases/test_raw_node.rs +++ b/tests/integration_cases/test_raw_node.rs @@ -25,9 +25,9 @@ // See the License for the specific language governing permissions and // limitations under the License. +use harness::*; use protobuf::{self, ProtobufEnum}; use raft::eraftpb::*; -use harness::*; use raft::storage::MemStorage; use raft::*; use test_util::*; diff --git a/tests/test_util/mod.rs b/tests/test_util/mod.rs index f19e9d191..db5e32724 100644 --- a/tests/test_util/mod.rs +++ b/tests/test_util/mod.rs @@ -25,9 +25,9 @@ // See the License for the specific language governing permissions and // limitations under the License. +use harness::*; use protobuf::RepeatedField; use raft::eraftpb::*; -use harness::*; pub use raft::setup_for_test; use raft::storage::MemStorage; use raft::*; diff --git a/tests/tests.rs b/tests/tests.rs index 521f1f1c7..2cdc0d75a 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -25,8 +25,8 @@ extern crate rand; extern crate lazy_static; #[cfg(feature = "failpoint")] extern crate fail; -extern crate harness; extern crate fxhash; +extern crate harness; /// Get the count of macro's arguments. /// @@ -95,4 +95,3 @@ mod failpoint_cases; #[cfg(not(feature = "failpoint"))] mod integration_cases; mod test_util; - From 64c4b5da42873593c0abe2d8b6937d8333027519 Mon Sep 17 00:00:00 2001 From: Hoverbear Date: Wed, 10 Oct 2018 15:41:23 -0700 Subject: [PATCH 4/9] Remove unnecessary dev-dep --- harness/Cargo.toml | 2 -- 1 file changed, 2 deletions(-) diff --git a/harness/Cargo.toml b/harness/Cargo.toml index a1ca2e9cb..a4e090831 100644 --- a/harness/Cargo.toml +++ b/harness/Cargo.toml @@ -14,5 +14,3 @@ categories = [] [dependencies] raft = { path = ".." } rand = "0.5.4" - -[dev-dependencies] From 68bee1c7e29266f8cae04648d7fda0923d9e1893 Mon Sep 17 00:00:00 2001 From: Ana Hobden Date: Mon, 14 Jan 2019 16:19:55 -0800 Subject: [PATCH 5/9] fmt --- harness/src/interface.rs | 2 +- harness/src/network.rs | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/harness/src/interface.rs b/harness/src/interface.rs index 9761e8637..2d03b9ea0 100644 --- a/harness/src/interface.rs +++ b/harness/src/interface.rs @@ -112,4 +112,4 @@ impl DerefMut for Interface { fn deref_mut(&mut self) -> &mut Raft { self.raft.as_mut().unwrap() } -} \ No newline at end of file +} diff --git a/harness/src/network.rs b/harness/src/network.rs index 58b74e79f..f0d75b700 100644 --- a/harness/src/network.rs +++ b/harness/src/network.rs @@ -90,7 +90,8 @@ impl Network { ..Default::default() }, nstorage[&id].clone(), - ).unwrap(), + ) + .unwrap(), ); npeers.insert(id, r); } @@ -131,10 +132,12 @@ impl Network { .get(&Connem { from: m.get_from(), to: m.get_to(), - }).cloned() + }) + .cloned() .unwrap_or(0f64); rand::random::() >= perc - }).collect() + }) + .collect() } /// Instruct the cluster to `step` through the given messages. From 1266fb3b407373a47509da56846831fc46019baf Mon Sep 17 00:00:00 2001 From: Ana Hobden Date: Wed, 13 Feb 2019 14:26:04 -0800 Subject: [PATCH 6/9] extract setup_for_test Signed-off-by: Ana Hobden --- harness/Cargo.toml | 1 + harness/src/lib.rs | 7 +++++++ src/errors.rs | 2 +- src/lib.rs | 10 +++------- src/log_unstable.rs | 2 +- src/progress.rs | 2 +- src/raft_log.rs | 2 +- src/raw_node.rs | 2 +- src/storage.rs | 3 ++- tests/integration_cases/test_raft_flow_control.rs | 1 + tests/integration_cases/test_raft_snap.rs | 1 + tests/test_util/mod.rs | 1 - 12 files changed, 20 insertions(+), 14 deletions(-) diff --git a/harness/Cargo.toml b/harness/Cargo.toml index a4e090831..b6a3a9a26 100644 --- a/harness/Cargo.toml +++ b/harness/Cargo.toml @@ -14,3 +14,4 @@ categories = [] [dependencies] raft = { path = ".." } rand = "0.5.4" +env_logger = "0.5" diff --git a/harness/src/lib.rs b/harness/src/lib.rs index 6f150d629..df0dc7ebd 100644 --- a/harness/src/lib.rs +++ b/harness/src/lib.rs @@ -35,8 +35,15 @@ This module contains various testing harness utilities for Raft. extern crate raft; extern crate rand; +extern crate env_logger; mod interface; mod network; pub use self::{interface::Interface, network::Network}; + +/// Do any common test initialization. Eg set up logging. +#[doc(hidden)] +pub fn setup_for_test() { + let _ = env_logger::try_init(); +} diff --git a/src/errors.rs b/src/errors.rs index 869367549..782affc24 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -133,7 +133,7 @@ pub type Result = result::Result; #[cfg(test)] mod tests { use super::*; - use setup_for_test; + use harness::setup_for_test; use std::io; #[test] diff --git a/src/lib.rs b/src/lib.rs index ba79bc920..bde16df96 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -266,6 +266,8 @@ For more information, check out an [example](examples/single_mem_node/main.rs#L1 #[cfg(feature = "failpoint")] #[macro_use] extern crate fail; +#[cfg(test)] +extern crate harness; extern crate fxhash; #[macro_use] extern crate log; @@ -334,10 +336,4 @@ pub mod prelude { pub use status::Status; pub use read_only::{ReadOnlyOption, ReadState}; -} - -/// Do any common test initialization. Eg set up logging. -#[doc(hidden)] -pub fn setup_for_test() { - let _ = env_logger::try_init(); -} +} \ No newline at end of file diff --git a/src/log_unstable.rs b/src/log_unstable.rs index 87d1a1c44..19155b271 100644 --- a/src/log_unstable.rs +++ b/src/log_unstable.rs @@ -185,7 +185,7 @@ impl Unstable { mod test { use eraftpb::{Entry, Snapshot, SnapshotMetadata}; use log_unstable::Unstable; - use setup_for_test; + use harness::setup_for_test; fn new_entry(index: u64, term: u64) -> Entry { let mut e = Entry::new(); diff --git a/src/progress.rs b/src/progress.rs index 6f67cd981..5b350c02c 100644 --- a/src/progress.rs +++ b/src/progress.rs @@ -607,7 +607,7 @@ impl Inflights { #[cfg(test)] mod test { use progress::Inflights; - use setup_for_test; + use harness::setup_for_test; #[test] fn test_inflight_add() { diff --git a/src/raft_log.rs b/src/raft_log.rs index a9529fd88..780011764 100644 --- a/src/raft_log.rs +++ b/src/raft_log.rs @@ -491,7 +491,7 @@ mod test { use errors::{Error, StorageError}; use protobuf; use raft_log::{self, RaftLog}; - use setup_for_test; + use harness::setup_for_test; use storage::MemStorage; fn new_raft_log(s: MemStorage) -> RaftLog { diff --git a/src/raw_node.rs b/src/raw_node.rs index 21382f034..1c7028317 100644 --- a/src/raw_node.rs +++ b/src/raw_node.rs @@ -518,7 +518,7 @@ impl RawNode { mod test { use super::is_local_msg; use eraftpb::MessageType; - use setup_for_test; + use harness::setup_for_test; #[test] fn test_is_local_msg() { diff --git a/src/storage.rs b/src/storage.rs index 4e8a10761..7f1c92c15 100644 --- a/src/storage.rs +++ b/src/storage.rs @@ -320,11 +320,12 @@ impl Storage for MemStorage { #[cfg(test)] mod test { + extern crate harness; use eraftpb::{ConfState, Entry, Snapshot}; use protobuf; + use harness::setup_for_test; use errors::{Error as RaftError, StorageError}; - use setup_for_test; use storage::{MemStorage, Storage}; // TODO extract these duplicated utility functions for tests diff --git a/tests/integration_cases/test_raft_flow_control.rs b/tests/integration_cases/test_raft_flow_control.rs index c85a79d99..171c09d14 100644 --- a/tests/integration_cases/test_raft_flow_control.rs +++ b/tests/integration_cases/test_raft_flow_control.rs @@ -27,6 +27,7 @@ use raft::eraftpb::*; use test_util::*; +use harness::setup_for_test; // test_msg_app_flow_control_full ensures: // 1. msgApp can fill the sending window until full diff --git a/tests/integration_cases/test_raft_snap.rs b/tests/integration_cases/test_raft_snap.rs index 6b7a0aeb1..71940b92e 100644 --- a/tests/integration_cases/test_raft_snap.rs +++ b/tests/integration_cases/test_raft_snap.rs @@ -27,6 +27,7 @@ use raft::eraftpb::*; use test_util::*; +use harness::setup_for_test; fn testing_snap() -> Snapshot { new_snapshot(11, 11, vec![1, 2]) diff --git a/tests/test_util/mod.rs b/tests/test_util/mod.rs index cecffb1fe..1697207a4 100644 --- a/tests/test_util/mod.rs +++ b/tests/test_util/mod.rs @@ -28,7 +28,6 @@ use harness::*; use protobuf::RepeatedField; use raft::eraftpb::*; -pub use raft::setup_for_test; use raft::storage::MemStorage; use raft::*; From 7b7471693ecedf473dabf43dff5d4907b8df031c Mon Sep 17 00:00:00 2001 From: Ana Hobden Date: Wed, 20 Feb 2019 10:29:13 -0800 Subject: [PATCH 7/9] Fmt Signed-off-by: Ana Hobden --- harness/src/lib.rs | 2 +- harness/src/network.rs | 3 +-- tests/integration_cases/test_membership_changes.rs | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/harness/src/lib.rs b/harness/src/lib.rs index df0dc7ebd..9d005e0c8 100644 --- a/harness/src/lib.rs +++ b/harness/src/lib.rs @@ -33,9 +33,9 @@ This module contains various testing harness utilities for Raft. */ +extern crate env_logger; extern crate raft; extern crate rand; -extern crate env_logger; mod interface; mod network; diff --git a/harness/src/network.rs b/harness/src/network.rs index 863134157..095a194ad 100644 --- a/harness/src/network.rs +++ b/harness/src/network.rs @@ -29,8 +29,7 @@ use super::interface::Interface; use raft::{ eraftpb::{Message, MessageType}, storage::MemStorage, - Config, Raft, NO_LIMIT, - Result, + Config, Raft, Result, NO_LIMIT, }; use rand; use std::collections::HashMap; diff --git a/tests/integration_cases/test_membership_changes.rs b/tests/integration_cases/test_membership_changes.rs index 194bb7cb4..c96e633f1 100644 --- a/tests/integration_cases/test_membership_changes.rs +++ b/tests/integration_cases/test_membership_changes.rs @@ -12,6 +12,7 @@ // limitations under the License. // // +use harness::{setup_for_test, Network}; use hashbrown::{HashMap, HashSet}; use protobuf::{self, RepeatedField}; use raft::{ @@ -21,7 +22,6 @@ use raft::{ storage::MemStorage, Config, Configuration, Raft, Result, INVALID_ID, NO_LIMIT, }; -use harness::{setup_for_test, Network}; use std::ops::{Deref, DerefMut}; use test_util::new_message; From 09ef107c4c2830a1925135ae7a154bdfb6db58a2 Mon Sep 17 00:00:00 2001 From: Ana Hobden Date: Wed, 20 Feb 2019 12:08:28 -0800 Subject: [PATCH 8/9] Fixup failpoint test Signed-off-by: Ana Hobden --- tests/failpoint_cases/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/failpoint_cases/mod.rs b/tests/failpoint_cases/mod.rs index e97a8de02..d84ce5a99 100644 --- a/tests/failpoint_cases/mod.rs +++ b/tests/failpoint_cases/mod.rs @@ -15,6 +15,7 @@ use fail; use raft::eraftpb::MessageType; use std::sync::*; use test_util::*; +use harness::setup_for_test; lazy_static! { /// Failpoints are global structs, hence rules set in different cases From 9ba2a8d90c04b3dc8244a5a34342bc24461871ed Mon Sep 17 00:00:00 2001 From: Ana Hobden Date: Wed, 20 Feb 2019 15:31:06 -0800 Subject: [PATCH 9/9] Fmt Signed-off-by: Ana Hobden --- tests/failpoint_cases/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/failpoint_cases/mod.rs b/tests/failpoint_cases/mod.rs index d84ce5a99..4b5f4f505 100644 --- a/tests/failpoint_cases/mod.rs +++ b/tests/failpoint_cases/mod.rs @@ -12,10 +12,10 @@ // limitations under the License. use fail; +use harness::setup_for_test; use raft::eraftpb::MessageType; use std::sync::*; use test_util::*; -use harness::setup_for_test; lazy_static! { /// Failpoints are global structs, hence rules set in different cases