agreement_tests.rs 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. extern crate labrpc;
  2. extern crate ruaft;
  3. #[macro_use]
  4. extern crate anyhow;
  5. mod config;
  6. #[test]
  7. fn basic_agreement() -> config::Result<()> {
  8. const SERVERS: usize = 5;
  9. let cfg = config::make_config(SERVERS, false);
  10. let _guard = cfg.deferred_cleanup();
  11. cfg.begin("Test (2B): basic agreement");
  12. for index in 1..4 {
  13. let committed = cfg.committed_count(index)?;
  14. assert_eq!(0, committed.0, "some have committed before start()");
  15. let commit_index = cfg.one(index as i32 * 100, SERVERS, false)?;
  16. assert_eq!(
  17. index, commit_index,
  18. "got index {} but expected {}",
  19. commit_index, index
  20. );
  21. }
  22. Ok(())
  23. }
  24. #[test]
  25. fn fail_agree() -> config::Result<()> {
  26. const SERVERS: usize = 3;
  27. let cfg = config::make_config(SERVERS, false);
  28. let _guard = cfg.deferred_cleanup();
  29. cfg.begin("Test (2B): agreement despite follower disconnection");
  30. cfg.one(101, SERVERS, false)?;
  31. // follower network disconnection
  32. let leader = cfg.check_one_leader()?;
  33. cfg.disconnect((leader + 1) % SERVERS);
  34. // agree despite one disconnected server?
  35. cfg.one(102, SERVERS - 1, false)?;
  36. cfg.one(103, SERVERS - 1, false)?;
  37. config::sleep_election_timeouts(1);
  38. cfg.one(104, SERVERS - 1, false)?;
  39. cfg.one(105, SERVERS - 1, false)?;
  40. // re-connect
  41. cfg.connect((leader + 1) % SERVERS);
  42. // agree with full set of servers?
  43. cfg.one(106, SERVERS, true)?;
  44. config::sleep_election_timeouts(1);
  45. cfg.one(107, SERVERS, true)?;
  46. cfg.end();
  47. Ok(())
  48. }
  49. #[test]
  50. fn fail_no_agree() -> config::Result<()> {
  51. const SERVERS: usize = 5;
  52. let cfg = config::make_config(SERVERS, false);
  53. let _guard = cfg.deferred_cleanup();
  54. cfg.begin("Test (2B): no agreement if too many followers disconnect");
  55. cfg.one(10, SERVERS, false)?;
  56. // 3 of 5 followers disconnect
  57. let leader = cfg.check_one_leader()?;
  58. cfg.disconnect((leader + 1) % SERVERS);
  59. cfg.disconnect((leader + 2) % SERVERS);
  60. cfg.disconnect((leader + 3) % SERVERS);
  61. let result = cfg.leader_start(leader, 20);
  62. assert!(result.is_some(), "leader rejected start()");
  63. let index = result.unwrap().1;
  64. assert_eq!(2, index, "expected index 2, got {}", index);
  65. config::sleep_election_timeouts(2);
  66. let (commit_count, _) = cfg.committed_count(index)?;
  67. assert_eq!(
  68. 0, commit_count,
  69. "{} committed but no majority",
  70. commit_count
  71. );
  72. // repair
  73. cfg.connect((leader + 1) % SERVERS);
  74. cfg.connect((leader + 2) % SERVERS);
  75. cfg.connect((leader + 3) % SERVERS);
  76. // the disconnected majority may have chosen a leader from
  77. // among their own ranks, forgetting index 2.
  78. let leader2 = cfg.check_one_leader()?;
  79. let result = cfg.leader_start(leader2, 30);
  80. assert!(result.is_some(), "leader2 rejected start()");
  81. let index = result.unwrap().1;
  82. assert!(index == 2 || index == 3, "unexpected index {}", index);
  83. cfg.one(1000, SERVERS, true)?;
  84. cfg.end();
  85. Ok(())
  86. }
  87. #[test]
  88. fn rejoin() -> config::Result<()> {
  89. const SERVERS: usize = 3;
  90. let cfg = config::make_config(SERVERS, false);
  91. let _guard = cfg.deferred_cleanup();
  92. cfg.begin("Test (2B): rejoin of partitioned leader");
  93. cfg.one(101, SERVERS, true)?;
  94. // leader network failure
  95. let leader1 = cfg.check_one_leader()?;
  96. cfg.disconnect(leader1);
  97. // make old leader try to agree on some entries
  98. cfg.leader_start(leader1, 102);
  99. cfg.leader_start(leader1, 103);
  100. cfg.leader_start(leader1, 104);
  101. // new leader commits, also for index=2
  102. cfg.one(103, 2, true)?;
  103. // new leader network failure
  104. let leader2 = cfg.check_one_leader()?;
  105. cfg.disconnect(leader2);
  106. // old leader connected again
  107. cfg.connect(leader1);
  108. cfg.one(104, 2, true)?;
  109. // all together now
  110. cfg.connect(leader2);
  111. cfg.one(105, SERVERS, true)?;
  112. cfg.end();
  113. drop(_guard);
  114. Ok(())
  115. }