def switch_to_candidate(self): """Switch to candidate state. Increment the current term, vote for self, and broadcast a request vote. The election timeout is randomly reinitialized. """ if self._current_state == ServerState._LEADER: raise InvalidState( "Invalid state '%s' while transiting to candidate state." % self._current_state) self._current_term += 1 self._current_state = ServerState._CANDIDATE LOG.debug("switched to candidate, term='%d'" % self._current_term) self._voters.clear() self._voters.add(self._private_endpoint) self._voted_for = self._private_endpoint l_l_i, l_l_t = self._log.index_and_term_of_last_entry() rv_message = message.build_request_vote(self._current_term, l_l_i, l_l_t) # Broadcast request vote and reset election timeout. self._server.broadcast_message(rv_message) self._server.reset_election_timeout()
def test_process_internal_raft_message(self): self.server._process_append_entry_request = mock.Mock() self.server._process_append_entry_response = mock.Mock() self.server._process_request_vote = mock.Mock() self.server._process_request_vote_response = mock.Mock() mock_socket = mock.Mock(spec=zmq.sugar.socket.Socket) # Append entry request. aereq = (1, 2, 3, 4, ()) aereq_packed = message.build_append_entry_request(*aereq) mock_socket.recv_multipart.return_value = ("identifier", aereq_packed) self.server._process_internal_message(mock_socket, zmq.POLLIN) self.server._process_append_entry_request.assert_called_once_with( "identifier", *aereq) # Append entry response. aeresp = (1, True, 0, None) aeresp_packed = message.build_append_entry_response(*aeresp) mock_socket.recv_multipart.return_value = ("identifier", aeresp_packed) self.server._process_internal_message(mock_socket, zmq.POLLIN) self.server._process_append_entry_response.\ assert_called_once_with("identifier", *aeresp) # Request vote. rv = (1, 2, 3) rv_packed = message.build_request_vote(*rv) mock_socket.recv_multipart.return_value = ("identifier", rv_packed) self.server._process_internal_message(mock_socket, zmq.POLLIN) self.server._process_request_vote.assert_called_once_with( "identifier", *rv) # Request vote response. rvresp = (0, False) rvresp_packed = message.build_request_vote_response(*rvresp) mock_socket.recv_multipart.return_value = ("identifier", rvresp_packed) self.server._process_internal_message(mock_socket, zmq.POLLIN) self.server._process_request_vote_response.\ assert_called_once_with("identifier", *rvresp)
def test_switch_to_candidate(self): self.server_state._current_state = serverstate.ServerState._LEADER pytest.raises(serverstate.InvalidState, self.server_state.switch_to_candidate) self.server_state._current_state = serverstate.ServerState._FOLLOWER self.log.index_and_term_of_last_entry.return_value = (0, 0) current_term = self.server_state._current_term self.server_state.switch_to_candidate() assert self.server_state._current_term == current_term + 1 assert (self.server_state._voters == {self.server_state._private_endpoint}) assert self.server_state._current_state == \ serverstate.ServerState._CANDIDATE assert (self.server_state._voted_for == self.server_state._private_endpoint) rv = message.build_request_vote(self.server_state._current_term, 0, 0) self.server.broadcast_message.assert_called_once_with(rv) self.server.reset_election_timeout.assert_called_once_with()
def test_build_request_vote(): test_params = (0, 1, 2) rv_message = message.build_request_vote(*test_params) decoded_message = message.decode_message(rv_message) assert (message.REQUEST_VOTE, test_params) == decoded_message