# Tests that PreVote+CheckQuorum prevents a node from obtaining prevotes if
# voters have heard from a leader recently. Also tests that a node is able to
# obtain prevotes if the voter hasn't heard from the leader in the past election
# timeout interval, or if a quorum of voters are precandidates.

log-level none
----
ok

add-nodes 3 voters=(1,2,3) index=10 prevote=true checkquorum=true
----
ok

campaign 1
----
ok

stabilize
----
ok

log-level debug
----
ok

withdraw-support 2 1
----
  1 2 3
1 1 1 1
2 x 1 1
3 1 1 1

# 2 should fail to campaign, leaving 1's leadership alone.
campaign 2
----
INFO 2 is starting a new election at term 1
INFO 2 became pre-candidate at term 1
INFO 2 [logterm: 1, index: 11] sent MsgPreVote request to 1 at term 1
INFO 2 [logterm: 1, index: 11] sent MsgPreVote request to 3 at term 1

stabilize
----
> 2 handling Ready
  Ready MustSync=true:
  State:StatePreCandidate
  HardState Term:1 Vote:1 Commit:11 Lead:0 LeadEpoch:0
  Messages:
  2->1 MsgPreVote Term:2 Log:1/11
  2->3 MsgPreVote Term:2 Log:1/11
  INFO 2 received MsgPreVoteResp from 2 at term 1
  INFO 2 has received 1 MsgPreVoteResp votes and 0 vote rejections
> 1 receiving messages
  2->1 MsgPreVote Term:2 Log:1/11
  INFO 1 [logterm: 1, index: 11, vote: 1] ignored MsgPreVote from 2 [logterm: 1, index: 11] at term 1: supporting fortified leader 1 at epoch 1
> 3 receiving messages
  2->3 MsgPreVote Term:2 Log:1/11
  INFO 3 [logterm: 1, index: 11, vote: 1] ignored MsgPreVote from 2 [logterm: 1, index: 11] at term 1: supporting fortified leader 1 at epoch 1

# If 2 hasn't heard from the leader in the past election timeout, it should
# grant prevotes, allowing 3 to hold an election.
set-randomized-election-timeout 2 timeout=5
----
ok

tick-election 2
----
ok

withdraw-support 3 1
----
  1 2 3
1 1 1 1
2 x 1 1
3 x 1 1

campaign 3
----
INFO 3 is starting a new election at term 1
INFO 3 became pre-candidate at term 1
INFO 3 [logterm: 1, index: 11] sent MsgPreVote request to 1 at term 1
INFO 3 [logterm: 1, index: 11] sent MsgPreVote request to 2 at term 1

process-ready 3
----
Ready MustSync=true:
State:StatePreCandidate
HardState Term:1 Vote:1 Commit:11 Lead:0 LeadEpoch:0
Messages:
3->1 MsgPreVote Term:2 Log:1/11
3->2 MsgPreVote Term:2 Log:1/11
INFO 3 received MsgPreVoteResp from 3 at term 1
INFO 3 has received 1 MsgPreVoteResp votes and 0 vote rejections

deliver-msgs 2
----
3->2 MsgPreVote Term:2 Log:1/11
INFO 2 [logterm: 1, index: 11, vote: 1] cast MsgPreVote for 3 [logterm: 1, index: 11] at term 1

process-ready 2
----
Ready MustSync=false:
Messages:
2->3 MsgPreVoteResp Term:2 Log:0/0

stabilize
----
> 1 receiving messages
  3->1 MsgPreVote Term:2 Log:1/11
  INFO 1 [logterm: 1, index: 11, vote: 1] ignored MsgPreVote from 3 [logterm: 1, index: 11] at term 1: supporting fortified leader 1 at epoch 1
> 3 receiving messages
  2->3 MsgPreVoteResp Term:2 Log:0/0
  INFO 3 received MsgPreVoteResp from 2 at term 1
  INFO 3 has received 2 MsgPreVoteResp votes and 0 vote rejections
  INFO 3 became candidate at term 2
  INFO 3 [logterm: 1, index: 11] sent MsgVote request to 1 at term 2
  INFO 3 [logterm: 1, index: 11] sent MsgVote request to 2 at term 2
> 3 handling Ready
  Ready MustSync=true:
  State:StateCandidate
  HardState Term:2 Vote:3 Commit:11 Lead:0 LeadEpoch:0
  Messages:
  3->1 MsgVote Term:2 Log:1/11
  3->2 MsgVote Term:2 Log:1/11
  INFO 3 received MsgVoteResp from 3 at term 2
  INFO 3 has received 1 MsgVoteResp votes and 0 vote rejections
> 1 receiving messages
  3->1 MsgVote Term:2 Log:1/11
  INFO 1 [logterm: 1, index: 11, vote: 1] ignored MsgVote from 3 [logterm: 1, index: 11] at term 1: supporting fortified leader 1 at epoch 1
> 2 receiving messages
  3->2 MsgVote Term:2 Log:1/11
  INFO 2 [term: 1] received a MsgVote message with higher term from 3 [term: 2], advancing term
  INFO 2 became follower at term 2
  DEBUG 2 reset election elapsed to 0
  INFO 2 [logterm: 1, index: 11, vote: 0] cast MsgVote for 3 [logterm: 1, index: 11] at term 2
> 2 handling Ready
  Ready MustSync=true:
  State:StateFollower
  HardState Term:2 Vote:3 Commit:11 Lead:0 LeadEpoch:0
  Messages:
  2->3 MsgVoteResp Term:2 Log:0/0
> 3 receiving messages
  2->3 MsgVoteResp Term:2 Log:0/0
  INFO 3 received MsgVoteResp from 2 at term 2
  INFO 3 has received 2 MsgVoteResp votes and 0 vote rejections
  INFO 3 became leader at term 2
> 3 handling Ready
  Ready MustSync=true:
  State:StateLeader
  HardState Term:2 Vote:3 Commit:11 Lead:3 LeadEpoch:1
  Entries:
  2/12 EntryNormal ""
  Messages:
  3->1 MsgFortifyLeader Term:2 Log:0/0
  3->2 MsgFortifyLeader Term:2 Log:0/0
  3->1 MsgApp Term:2 Log:1/11 Commit:11 Entries:[2/12 EntryNormal ""]
  3->2 MsgApp Term:2 Log:1/11 Commit:11 Entries:[2/12 EntryNormal ""]
> 1 receiving messages
  3->1 MsgFortifyLeader Term:2 Log:0/0
  INFO 1 [term: 1] received a MsgFortifyLeader message with higher term from 3 [term: 2], new leader indicated, advancing term
  DEBUG 1 setting election elapsed to start from 3 ticks after store liveness support expired
  INFO 1 became follower at term 2
  DEBUG 1 reset election elapsed to 0
  3->1 MsgApp Term:2 Log:1/11 Commit:11 Entries:[2/12 EntryNormal ""]
> 2 receiving messages
  3->2 MsgFortifyLeader Term:2 Log:0/0
  3->2 MsgApp Term:2 Log:1/11 Commit:11 Entries:[2/12 EntryNormal ""]
> 1 handling Ready
  Ready MustSync=true:
  State:StateFollower
  HardState Term:2 Commit:11 Lead:3 LeadEpoch:1
  Entries:
  2/12 EntryNormal ""
  Messages:
  1->3 MsgFortifyLeaderResp Term:2 Log:0/0 LeadEpoch:1
  1->3 MsgAppResp Term:2 Log:0/12 Commit:11
> 2 handling Ready
  Ready MustSync=true:
  HardState Term:2 Vote:3 Commit:11 Lead:3 LeadEpoch:1
  Entries:
  2/12 EntryNormal ""
  Messages:
  2->3 MsgFortifyLeaderResp Term:2 Log:0/0 LeadEpoch:1
  2->3 MsgAppResp Term:2 Log:0/12 Commit:11
> 3 receiving messages
  1->3 MsgFortifyLeaderResp Term:2 Log:0/0 LeadEpoch:1
  1->3 MsgAppResp Term:2 Log:0/12 Commit:11
  2->3 MsgFortifyLeaderResp Term:2 Log:0/0 LeadEpoch:1
  2->3 MsgAppResp Term:2 Log:0/12 Commit:11
> 3 handling Ready
  Ready MustSync=true:
  HardState Term:2 Vote:3 Commit:12 Lead:3 LeadEpoch:1
  CommittedEntries:
  2/12 EntryNormal ""
  Messages:
  3->1 MsgApp Term:2 Log:1/11 Commit:11 Entries:[2/12 EntryNormal ""]
  3->1 MsgApp Term:2 Log:2/12 Commit:12
  3->2 MsgApp Term:2 Log:1/11 Commit:12 Entries:[2/12 EntryNormal ""]
  3->2 MsgApp Term:2 Log:2/12 Commit:12
> 1 receiving messages
  3->1 MsgApp Term:2 Log:1/11 Commit:11 Entries:[2/12 EntryNormal ""]
  3->1 MsgApp Term:2 Log:2/12 Commit:12
> 2 receiving messages
  3->2 MsgApp Term:2 Log:1/11 Commit:12 Entries:[2/12 EntryNormal ""]
  3->2 MsgApp Term:2 Log:2/12 Commit:12
> 1 handling Ready
  Ready MustSync=true:
  HardState Term:2 Commit:12 Lead:3 LeadEpoch:1
  CommittedEntries:
  2/12 EntryNormal ""
  Messages:
  1->3 MsgAppResp Term:2 Log:0/12 Commit:11
  1->3 MsgAppResp Term:2 Log:0/12 Commit:12
> 2 handling Ready
  Ready MustSync=true:
  HardState Term:2 Vote:3 Commit:12 Lead:3 LeadEpoch:1
  CommittedEntries:
  2/12 EntryNormal ""
  Messages:
  2->3 MsgAppResp Term:2 Log:0/12 Commit:12
  2->3 MsgAppResp Term:2 Log:0/12 Commit:12
> 3 receiving messages
  1->3 MsgAppResp Term:2 Log:0/12 Commit:11
  1->3 MsgAppResp Term:2 Log:0/12 Commit:12
  2->3 MsgAppResp Term:2 Log:0/12 Commit:12
  2->3 MsgAppResp Term:2 Log:0/12 Commit:12

withdraw-support 1 3
----
  1 2 3
1 1 1 x
2 x 1 1
3 x 1 1

# At this point we can't campaign because we are not supported by a quorum.
campaign 1
----
DEBUG 1 cannot campaign since it's not supported by a quorum in store liveness

grant-support 3 1
----
  1 2 3
1 2 1 x
2 x 1 1
3 2 1 1

# Node 3 is now the leader. Even though the leader is active, nodes 1 and 2 can
# still win a prevote and election if they both explicitly campaign, since the
# PreVote+CheckQuorum recent leader condition only applies to follower voters.
# This is beneficial, because it allows a quorum of nodes to replace a leader
# when they have strong reason to believe that it's dead, despite having heard
# from it recently.
#
# We first let 1 lose an election, as we'd otherwise get a tie.
campaign 1
----
INFO 1 is starting a new election at term 2
INFO 1 became pre-candidate at term 2
INFO 1 [logterm: 2, index: 12] sent MsgPreVote request to 2 at term 2
INFO 1 [logterm: 2, index: 12] sent MsgPreVote request to 3 at term 2

stabilize
----
> 1 handling Ready
  Ready MustSync=true:
  State:StatePreCandidate
  HardState Term:2 Commit:12 Lead:0 LeadEpoch:0
  Messages:
  1->2 MsgPreVote Term:3 Log:2/12
  1->3 MsgPreVote Term:3 Log:2/12
  INFO 1 received MsgPreVoteResp from 1 at term 2
  INFO 1 has received 1 MsgPreVoteResp votes and 0 vote rejections
> 2 receiving messages
  1->2 MsgPreVote Term:3 Log:2/12
  INFO 2 [logterm: 2, index: 12, vote: 3] ignored MsgPreVote from 1 [logterm: 2, index: 12] at term 2: supporting fortified leader 3 at epoch 1
> 3 receiving messages
  1->3 MsgPreVote Term:3 Log:2/12
  INFO 3 [logterm: 2, index: 12, vote: 3] ignored MsgPreVote from 1 [logterm: 2, index: 12] at term 2: supporting fortified leader 3 at epoch 1

withdraw-support 2 3
----
  1 2 3
1 2 1 x
2 x 1 x
3 2 1 1

campaign 2
----
INFO 2 is starting a new election at term 2
INFO 2 became pre-candidate at term 2
INFO 2 [logterm: 2, index: 12] sent MsgPreVote request to 1 at term 2
INFO 2 [logterm: 2, index: 12] sent MsgPreVote request to 3 at term 2

stabilize
----
> 2 handling Ready
  Ready MustSync=true:
  State:StatePreCandidate
  HardState Term:2 Vote:3 Commit:12 Lead:0 LeadEpoch:0
  Messages:
  2->1 MsgPreVote Term:3 Log:2/12
  2->3 MsgPreVote Term:3 Log:2/12
  INFO 2 received MsgPreVoteResp from 2 at term 2
  INFO 2 has received 1 MsgPreVoteResp votes and 0 vote rejections
> 1 receiving messages
  2->1 MsgPreVote Term:3 Log:2/12
  INFO 1 [logterm: 2, index: 12, vote: 0] cast MsgPreVote for 2 [logterm: 2, index: 12] at term 2
> 3 receiving messages
  2->3 MsgPreVote Term:3 Log:2/12
  INFO 3 [logterm: 2, index: 12, vote: 3] ignored MsgPreVote from 2 [logterm: 2, index: 12] at term 2: supporting fortified leader 3 at epoch 1
> 1 handling Ready
  Ready MustSync=false:
  Messages:
  1->2 MsgPreVoteResp Term:3 Log:0/0
> 2 receiving messages
  1->2 MsgPreVoteResp Term:3 Log:0/0
  INFO 2 received MsgPreVoteResp from 1 at term 2
  INFO 2 has received 2 MsgPreVoteResp votes and 0 vote rejections
  INFO 2 became candidate at term 3
  INFO 2 [logterm: 2, index: 12] sent MsgVote request to 1 at term 3
  INFO 2 [logterm: 2, index: 12] sent MsgVote request to 3 at term 3
> 2 handling Ready
  Ready MustSync=true:
  State:StateCandidate
  HardState Term:3 Vote:2 Commit:12 Lead:0 LeadEpoch:0
  Messages:
  2->1 MsgVote Term:3 Log:2/12
  2->3 MsgVote Term:3 Log:2/12
  INFO 2 received MsgVoteResp from 2 at term 3
  INFO 2 has received 1 MsgVoteResp votes and 0 vote rejections
> 1 receiving messages
  2->1 MsgVote Term:3 Log:2/12
  INFO 1 [term: 2] received a MsgVote message with higher term from 2 [term: 3], advancing term
  INFO 1 became follower at term 3
  DEBUG 1 reset election elapsed to 0
  INFO 1 [logterm: 2, index: 12, vote: 0] cast MsgVote for 2 [logterm: 2, index: 12] at term 3
> 3 receiving messages
  2->3 MsgVote Term:3 Log:2/12
  INFO 3 [logterm: 2, index: 12, vote: 3] ignored MsgVote from 2 [logterm: 2, index: 12] at term 2: supporting fortified leader 3 at epoch 1
> 1 handling Ready
  Ready MustSync=true:
  State:StateFollower
  HardState Term:3 Vote:2 Commit:12 Lead:0 LeadEpoch:0
  Messages:
  1->2 MsgVoteResp Term:3 Log:0/0
> 2 receiving messages
  1->2 MsgVoteResp Term:3 Log:0/0
  INFO 2 received MsgVoteResp from 1 at term 3
  INFO 2 has received 2 MsgVoteResp votes and 0 vote rejections
  INFO 2 became leader at term 3
> 2 handling Ready
  Ready MustSync=true:
  State:StateLeader
  HardState Term:3 Vote:2 Commit:12 Lead:2 LeadEpoch:1
  Entries:
  3/13 EntryNormal ""
  Messages:
  2->1 MsgFortifyLeader Term:3 Log:0/0
  2->3 MsgFortifyLeader Term:3 Log:0/0
  2->1 MsgApp Term:3 Log:2/12 Commit:12 Entries:[3/13 EntryNormal ""]
  2->3 MsgApp Term:3 Log:2/12 Commit:12 Entries:[3/13 EntryNormal ""]
> 1 receiving messages
  2->1 MsgFortifyLeader Term:3 Log:0/0
  2->1 MsgApp Term:3 Log:2/12 Commit:12 Entries:[3/13 EntryNormal ""]
> 3 receiving messages
  2->3 MsgFortifyLeader Term:3 Log:0/0
  INFO 3 [term: 2] received a MsgFortifyLeader message with higher term from 2 [term: 3], new leader indicated, advancing term
  DEBUG 3 setting election elapsed to start from 3 ticks after store liveness support expired
  INFO 3 became follower at term 3
  DEBUG 3 reset election elapsed to 0
  2->3 MsgApp Term:3 Log:2/12 Commit:12 Entries:[3/13 EntryNormal ""]
> 1 handling Ready
  Ready MustSync=true:
  HardState Term:3 Vote:2 Commit:12 Lead:2 LeadEpoch:1
  Entries:
  3/13 EntryNormal ""
  Messages:
  1->2 MsgFortifyLeaderResp Term:3 Log:0/0 LeadEpoch:1
  1->2 MsgAppResp Term:3 Log:0/13 Commit:12
> 3 handling Ready
  Ready MustSync=true:
  State:StateFollower
  HardState Term:3 Commit:12 Lead:2 LeadEpoch:1
  Entries:
  3/13 EntryNormal ""
  Messages:
  3->2 MsgFortifyLeaderResp Term:3 Log:0/0 LeadEpoch:1
  3->2 MsgAppResp Term:3 Log:0/13 Commit:12
> 2 receiving messages
  1->2 MsgFortifyLeaderResp Term:3 Log:0/0 LeadEpoch:1
  1->2 MsgAppResp Term:3 Log:0/13 Commit:12
  3->2 MsgFortifyLeaderResp Term:3 Log:0/0 LeadEpoch:1
  3->2 MsgAppResp Term:3 Log:0/13 Commit:12
> 2 handling Ready
  Ready MustSync=true:
  HardState Term:3 Vote:2 Commit:13 Lead:2 LeadEpoch:1
  CommittedEntries:
  3/13 EntryNormal ""
  Messages:
  2->1 MsgApp Term:3 Log:2/12 Commit:12 Entries:[3/13 EntryNormal ""]
  2->1 MsgApp Term:3 Log:3/13 Commit:13
  2->3 MsgApp Term:3 Log:2/12 Commit:13 Entries:[3/13 EntryNormal ""]
  2->3 MsgApp Term:3 Log:3/13 Commit:13
> 1 receiving messages
  2->1 MsgApp Term:3 Log:2/12 Commit:12 Entries:[3/13 EntryNormal ""]
  2->1 MsgApp Term:3 Log:3/13 Commit:13
> 3 receiving messages
  2->3 MsgApp Term:3 Log:2/12 Commit:13 Entries:[3/13 EntryNormal ""]
  2->3 MsgApp Term:3 Log:3/13 Commit:13
> 1 handling Ready
  Ready MustSync=true:
  HardState Term:3 Vote:2 Commit:13 Lead:2 LeadEpoch:1
  CommittedEntries:
  3/13 EntryNormal ""
  Messages:
  1->2 MsgAppResp Term:3 Log:0/13 Commit:12
  1->2 MsgAppResp Term:3 Log:0/13 Commit:13
> 3 handling Ready
  Ready MustSync=true:
  HardState Term:3 Commit:13 Lead:2 LeadEpoch:1
  CommittedEntries:
  3/13 EntryNormal ""
  Messages:
  3->2 MsgAppResp Term:3 Log:0/13 Commit:13
  3->2 MsgAppResp Term:3 Log:0/13 Commit:13
> 2 receiving messages
  1->2 MsgAppResp Term:3 Log:0/13 Commit:12
  1->2 MsgAppResp Term:3 Log:0/13 Commit:13
  3->2 MsgAppResp Term:3 Log:0/13 Commit:13
  3->2 MsgAppResp Term:3 Log:0/13 Commit:13
