Skip to content

Commit ee134c0

Browse files
committed
Test: add test to reproduce issue #584
Error After change_membership: `assertion failed: value > prev`, when changing membership by converting a learner to a voter. Because the replication streams are re-spawned, thus progress reverts to zero. Then a reverted progress causes the panic.
1 parent f6f14f1 commit ee134c0

File tree

3 files changed

+54
-1
lines changed

3 files changed

+54
-1
lines changed

openraft/tests/membership/main.rs

+1
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,5 @@ mod t30_step_down;
2121
mod t40_removed_follower;
2222
mod t45_remove_unreachable_follower;
2323
mod t99_issue_471_adding_learner_uses_uninit_leader_id;
24+
mod t99_issue_584_replication_state_reverted;
2425
mod t99_new_leader_auto_commit_uniform_config;

openraft/tests/membership/t10_add_learner.rs

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use std::option::Option::None;
21
use std::sync::Arc;
32
use std::time::Duration;
43

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
use std::sync::Arc;
2+
use std::time::Duration;
3+
4+
use anyhow::Result;
5+
use maplit::btreeset;
6+
use openraft::Config;
7+
8+
use crate::fixtures::init_default_ut_tracing;
9+
use crate::fixtures::RaftRouter;
10+
11+
#[async_entry::test(worker_threads = 8, init = "init_default_ut_tracing()", tracing_span = "debug")]
12+
async fn t99_issue_584_replication_state_reverted() -> Result<()> {
13+
// - Add a learner and replicate all logs to it.
14+
// - Add the learner as a voter. When membership changes, openraft internally restarts all replication.
15+
//
16+
// This case asserts it does not break the internal monotonic-replication-progress guarantee.
17+
18+
let config = Arc::new(
19+
Config {
20+
max_in_snapshot_log_to_keep: 2000, // prevent snapshot
21+
enable_tick: false,
22+
..Default::default()
23+
}
24+
.validate()?,
25+
);
26+
let mut router = RaftRouter::new(config.clone());
27+
28+
let mut log_index = router.new_nodes_from_single(btreeset! {0}, btreeset! {1}).await?;
29+
30+
let n = 500u64;
31+
tracing::info!("--- write up to {} logs", n);
32+
{
33+
router.client_request_many(0, "foo", (n - log_index) as usize).await?;
34+
log_index = n;
35+
36+
router.wait(&1, timeout()).log(Some(log_index), "replicate all logs to learner").await?;
37+
}
38+
39+
tracing::info!("--- change-membership: make learner node-1 a voter. This should not panic");
40+
{
41+
let leader = router.get_raft_handle(&0)?;
42+
leader.change_membership(btreeset![0, 1], true, false).await?;
43+
log_index += 2; // 2 change_membership log
44+
45+
let _ = log_index;
46+
}
47+
48+
Ok(())
49+
}
50+
51+
fn timeout() -> Option<Duration> {
52+
Some(Duration::from_millis(1_000))
53+
}

0 commit comments

Comments
 (0)