Skip to content

Commit b107391

Browse files
committed
Test: leader state reversion upon restart
1 parent b262f05 commit b107391

File tree

2 files changed

+88
-0
lines changed

2 files changed

+88
-0
lines changed

tests/tests/life_cycle/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ mod fixtures;
1010
mod t10_initialization;
1111
mod t11_shutdown;
1212
mod t50_follower_restart_does_not_interrupt;
13+
mod t50_leader_restart_clears_state;
1314
mod t50_single_follower_restart;
1415
mod t50_single_leader_restart_re_apply_logs;
1516
mod t90_issue_607_single_restart;
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
use std::sync::Arc;
2+
use std::time::Duration;
3+
4+
use maplit::btreemap;
5+
use openraft::Config;
6+
use openraft::ServerState;
7+
8+
use crate::fixtures::ut_harness;
9+
use crate::fixtures::MemLogStore;
10+
use crate::fixtures::MemRaft;
11+
use crate::fixtures::MemStateMachine;
12+
use crate::fixtures::RaftRouter;
13+
14+
/// Test leader restart with complete state loss and recovery.
15+
///
16+
/// A 3-nodes cluster leader loses all state on restart,
17+
/// then re-initialize it, it should not become the leader.
18+
#[tracing::instrument]
19+
#[test_harness::test(harness = ut_harness)]
20+
async fn leader_restart_clears_state() -> anyhow::Result<()> {
21+
let config = Arc::new(
22+
Config {
23+
enable_heartbeat: false,
24+
enable_elect: false,
25+
..Default::default()
26+
}
27+
.validate()?,
28+
);
29+
30+
let mut router = RaftRouter::new(config.clone());
31+
router.enable_saving_committed = false;
32+
33+
let mut log_index = 0;
34+
35+
// It must initialize a 3-nodes cluster so that it won't become leader in term-1, without election,
36+
// but instead, it becomes leader in term-2 after a round of election.
37+
// Otherwise after restart, the restarted leader has greater vote.
38+
tracing::info!("--- bring up cluster of 3 node");
39+
{
40+
router.new_raft_node(0).await;
41+
router.new_raft_node(1).await;
42+
router.new_raft_node(2).await;
43+
44+
tracing::info!("--- initialize node-0 wiht [0,1,2]");
45+
let n0 = router.get_raft_handle(&0)?;
46+
n0.initialize(btreemap! {0 => (), 1=>(), 2=>()}).await?;
47+
// log_index == 0;
48+
49+
tracing::info!("--- trigger election for node-0");
50+
n0.trigger().elect().await?;
51+
log_index += 1;
52+
53+
n0.wait(timeout()).state(ServerState::Leader, "node-0 should become leader").await?;
54+
n0.wait(timeout()).applied_index(Some(log_index), "node-0 applied log").await?;
55+
}
56+
57+
tracing::info!(log_index, "--- write to 1 log");
58+
{
59+
log_index += router.client_request_many(0, "foo", 1).await?;
60+
}
61+
62+
tracing::info!(log_index, "--- stop and restart node-0");
63+
{
64+
let (node, _log, _sm): (MemRaft, MemLogStore, MemStateMachine) = router.remove_node(0).unwrap();
65+
node.shutdown().await?;
66+
67+
tracing::info!(log_index, "--- restart node-0 with empty log and sm");
68+
69+
router.new_raft_node(0).await;
70+
let n0 = router.get_raft_handle(&0)?;
71+
72+
tracing::info!(log_index, "--- initialize node-0 after restart");
73+
n0.initialize(btreemap! {0 => (), 1=>(), 2=>()}).await?;
74+
75+
tracing::info!(log_index, "--- trigger election for node-0 after restart");
76+
n0.trigger().elect().await?;
77+
78+
let res = n0.wait(timeout()).state(ServerState::Leader, "should not become leader upon restart").await;
79+
assert!(res.is_err());
80+
}
81+
82+
Ok(())
83+
}
84+
85+
fn timeout() -> Option<Duration> {
86+
Some(Duration::from_millis(1_000))
87+
}

0 commit comments

Comments
 (0)