Skip to content

Commit

Permalink
test: add test for #438
Browse files Browse the repository at this point in the history
Signed-off-by: bsbds <69835502+bsbds@users.noreply.github.com>
  • Loading branch information
bsbds committed Sep 22, 2023
1 parent e156bd6 commit 8d94c55
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 10 deletions.
73 changes: 63 additions & 10 deletions simulation/src/curp_group.rs
Original file line number Diff line number Diff line change
Expand Up @@ -312,26 +312,79 @@ impl CurpGroup {
.unwrap()
}

// Disconnect the node from the network.
/// Disconnect the node from the network.
pub fn disable_node(&self, id: ServerId) {
let handle = madsim::runtime::Handle::current();
let net = madsim::net::NetSim::current();
let Some(node) = handle.get_node(id.to_string()) else {
panic!("no node with name {id} in the simulator")
};
let node = Self::get_node_handle(id);
net.clog_node(node.id());
}

// Reconnect the node to the network.
/// Reconnect the node to the network.
pub fn enable_node(&self, id: ServerId) {
let handle = madsim::runtime::Handle::current();
let net = madsim::net::NetSim::current();
let Some(node) = handle.get_node(id.to_string()) else {
panic!("no node with name {id} the simulator")
};
let node = Self::get_node_handle(id);
net.unclog_node(node.id());
}

/// Disconnect the network link between two nodes
pub fn clog_link_nodes(&self, fst: ServerId, snd: ServerId) {
let node_fst = Self::get_node_handle(fst);
let node_snd = Self::get_node_handle(snd);
Self::clog_bidirectional(&node_fst, &node_snd);
}

/// Reconnect the network link between two nodes
pub fn unclog_link_nodes(&self, fst: ServerId, snd: ServerId) {
let node_fst = Self::get_node_handle(fst);
let node_snd = Self::get_node_handle(snd);
Self::unclog_bidirectional(&node_fst, &node_snd);
}

/// Disconnect the network link between the client and a list of nodes
/// Note: This will affect SimClient
pub fn clog_link_client_nodes<'a>(&'a self, server_ids: impl Iterator<Item = &'a ServerId>) {
let client_node = &self.client_node;
for server_id in server_ids {
let server_node = Self::get_node_handle(*server_id);
Self::clog_bidirectional(client_node, &server_node);
}
}

/// Reconnect the network link between the client and a list of nodes
pub fn unclog_link_client_nodes<'a>(&'a self, server_ids: impl Iterator<Item = &'a ServerId>) {
let client_node = &self.client_node;
for server_id in server_ids {
let server_node = Self::get_node_handle(*server_id);
Self::unclog_bidirectional(client_node, &server_node);
}
}

/// Clog the network bidirectionally
fn clog_bidirectional(node_fst: &NodeHandle, node_snd: &NodeHandle) {
let net = madsim::net::NetSim::current();
let id_fst = node_fst.id();
let id_snd = node_snd.id();
net.clog_link(id_fst, id_snd);
net.clog_link(id_snd, id_fst);
}

/// Unclog the network bidirectionally
fn unclog_bidirectional(node_fst: &NodeHandle, node_snd: &NodeHandle) {
let net = madsim::net::NetSim::current();
let id_fst = node_fst.id();
let id_snd = node_snd.id();
net.unclog_link(id_fst, id_snd);
net.unclog_link(id_snd, id_fst);
}

/// Get the server node handle from ServerId
fn get_node_handle(id: ServerId) -> NodeHandle {
let handle = madsim::runtime::Handle::current();
handle
.get_node(id.to_string())
.expect("no node with name {id} the simulator")
}

pub async fn get_connect(&self, id: &ServerId) -> SimProtocolClient {
let addr = self
.all_members
Expand Down
40 changes: 40 additions & 0 deletions simulation/tests/it/curp/server_election.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,3 +154,43 @@ async fn propose_after_reelect() {

group.stop().await;
}

// Verifies that #438 has been fixed
// This will likely to fail without a fix
#[madsim::test]
async fn conflict_should_detected_in_new_leader() {
init_logger();

let group = CurpGroup::new(3).await;
let client = group.new_client(ClientConfig::default()).await;
let leader1 = group.get_leader().await.0;

// client only propose to leader
group.clog_link_client_nodes(group.nodes.keys().filter(|id| **id != leader1));
assert_eq!(
client
.propose(TestCommand::new_put(vec![0], 0), true)
.await
.unwrap()
.0
.values,
vec![]
);

// re-elect a new leader
group.disable_node(leader1);
group.unclog_link_client_nodes(group.nodes.keys().filter(|id| **id != leader1));
let (_leader, _term) = wait_for_election(&group).await;

assert_eq!(
client
.propose(TestCommand::new_get(vec![0]), true)
.await
.unwrap()
.0
.values,
vec![0]
);

group.stop().await;
}

0 comments on commit 8d94c55

Please sign in to comment.