# Regression test that verifies that learners can vote. This holds only in the
# sense that if a learner is asked to vote, a candidate believes that they are a
# voter based on its current config, which may be more recent than that of the
# learner. If learners which are actually voters but don't know it yet don't
# vote in that situation, the raft group may end up unavailable despite a quorum
# of voters (as of the latest config) being available.
#
# See:
# https://github.com/etcd-io/etcd/pull/10998

# Turn output off during boilerplate.
log-level none
----
ok

# Bootstrap three nodes.
add-nodes 3 voters=(1,2) learners=(3) index=2
----
ok

# n1 gets to be leader.
campaign 1
----
ok

stabilize
----
ok (quiet)

# Propose a conf change on n1 that promotes n3 to voter.
propose-conf-change 1
v3
----
ok

# Commit and fully apply said conf change. n1 and n2 now consider n3 a voter.
stabilize 1 2
----
ok (quiet)

# Drop all inflight messages to 3. We don't want it to be caught up when it is
# asked to vote.
deliver-msgs drop=(3)
----
ok (quiet)

# We now pretend that n1 is dead, and n2 is trying to become leader.

log-level debug
----
ok

campaign 2
----
INFO 2 is starting a new election at term 1
INFO 2 became candidate at term 2
INFO 2 received MsgVoteResp from 2 at term 2
INFO 2 [logterm: 1, index: 4] sent MsgVote request to 1 at term 2
INFO 2 [logterm: 1, index: 4] sent MsgVote request to 3 at term 2

# Send out the MsgVote requests.
process-ready 2
----
Ready MustSync=true:
Lead:0 State:StateCandidate
HardState Term:2 Vote:2 Commit:4
Messages:
2->1 MsgVote Term:2 Log:1/4
2->3 MsgVote Term:2 Log:1/4

# n2 is now campaigning while n1 is down (does not respond). The latest config
# has n3 as a voter, but n3 doesn't even have the corresponding conf change in
# its log. Still, it casts a vote for n2 which can in turn become leader and
# catches up n3.
stabilize 3
----
> 3 receiving messages
  2->3 MsgVote Term:2 Log:1/4
  INFO 3 [term: 1] received a MsgVote message with higher term from 2 [term: 2]
  INFO 3 became follower at term 2
  INFO 3 [logterm: 1, index: 3, vote: 0] cast MsgVote for 2 [logterm: 1, index: 4] at term 2
> 3 handling Ready
  Ready MustSync=true:
  Lead:0 State:StateFollower
  HardState Term:2 Vote:2 Commit:3
  Messages:
  3->2 MsgVoteResp Term:2 Log:0/0

stabilize 2 3
----
> 2 receiving messages
  3->2 MsgVoteResp Term:2 Log:0/0
  INFO 2 received MsgVoteResp from 3 at term 2
  INFO 2 has received 2 MsgVoteResp votes and 0 vote rejections
  INFO 2 became leader at term 2
> 2 handling Ready
  Ready MustSync=true:
  Lead:2 State:StateLeader
  Entries:
  2/5 EntryNormal ""
  Messages:
  2->1 MsgApp Term:2 Log:1/4 Commit:4 Entries:[2/5 EntryNormal ""]
  2->3 MsgApp Term:2 Log:1/4 Commit:4 Entries:[2/5 EntryNormal ""]
> 3 receiving messages
  2->3 MsgApp Term:2 Log:1/4 Commit:4 Entries:[2/5 EntryNormal ""]
  DEBUG 3 [logterm: 0, index: 4] rejected MsgApp [logterm: 1, index: 4] from 2
> 3 handling Ready
  Ready MustSync=false:
  Lead:2 State:StateFollower
  Messages:
  3->2 MsgAppResp Term:2 Log:1/4 Rejected (Hint: 3)
> 2 receiving messages
  3->2 MsgAppResp Term:2 Log:1/4 Rejected (Hint: 3)
  DEBUG 2 received MsgAppResp(rejected, hint: (index 3, term 1)) from 3 for index 4
  DEBUG 2 decreased progress of 3 to [StateProbe match=0 next=4]
> 2 handling Ready
  Ready MustSync=false:
  Messages:
  2->3 MsgApp Term:2 Log:1/3 Commit:4 Entries:[1/4 EntryConfChangeV2 v3, 2/5 EntryNormal ""]
> 3 receiving messages
  2->3 MsgApp Term:2 Log:1/3 Commit:4 Entries:[1/4 EntryConfChangeV2 v3, 2/5 EntryNormal ""]
> 3 handling Ready
  Ready MustSync=true:
  HardState Term:2 Vote:2 Commit:4
  Entries:
  1/4 EntryConfChangeV2 v3
  2/5 EntryNormal ""
  CommittedEntries:
  1/4 EntryConfChangeV2 v3
  Messages:
  3->2 MsgAppResp Term:2 Log:0/5
  INFO 3 switched to configuration voters=(1 2 3)
> 2 receiving messages
  3->2 MsgAppResp Term:2 Log:0/5
> 2 handling Ready
  Ready MustSync=false:
  HardState Term:2 Vote:2 Commit:5
  CommittedEntries:
  2/5 EntryNormal ""
  Messages:
  2->3 MsgApp Term:2 Log:2/5 Commit:5
> 3 receiving messages
  2->3 MsgApp Term:2 Log:2/5 Commit:5
> 3 handling Ready
  Ready MustSync=false:
  HardState Term:2 Vote:2 Commit:5
  CommittedEntries:
  2/5 EntryNormal ""
  Messages:
  3->2 MsgAppResp Term:2 Log:0/5
> 2 receiving messages
  3->2 MsgAppResp Term:2 Log:0/5
