def test_process_append_entry_request_induction_failed(self): ae_req = (0, -1, -1, 4, ()) self.server._server_state.is_leader.return_value = False self.server._process_append_entry_request("peer_id", *ae_req) ae_response = message.build_append_entry_response( self.server._server_state.term(), False, None, 0) self.server._remote_peers["peer_id"].send_message.\ assert_called_once_with(ae_response) self.server._remote_peers["peer_id"].send_message.reset_mock()
def test_process_append_entry_request_induction_failed(self): ae_req = (0, -1, -1, 4, ()) self.server._server_state.is_leader.return_value = False self.server._process_append_entry_request("peer_id", *ae_req) ae_response = message.build_append_entry_response( self.server._server_state.term(), False, None, 0) self.server._remote_peers["peer_id"].send_message.\ assert_called_once_with(ae_response) self.server._remote_peers["peer_id"].send_message.reset_mock()
def test_process_append_entry_request_stale_term(self): ae_req = (-1, 2, 3, 4, ()) self.server._process_append_entry_request("peer_id", *ae_req) ae_response = message.build_append_entry_response( self.server._server_state.term(), False, None, None) self.server._remote_peers["peer_id"].send_message.\ assert_called_once_with(ae_response) self.server._remote_peers["peer_id"].send_message.reset_mock()
def test_process_append_entry_request_stale_term(self): ae_req = (-1, 2, 3, 4, ()) self.server._process_append_entry_request("peer_id", *ae_req) ae_response = message.build_append_entry_response( self.server._server_state.term(), False, None, None) self.server._remote_peers["peer_id"].send_message.\ assert_called_once_with(ae_response) self.server._remote_peers["peer_id"].send_message.reset_mock()
def test_process_append_entry_request_as_follower(self): ae_req = (0, 0, 0, 4, ()) self.server._server_state.is_leader.return_value = False self.server._server_state.commit_index.return_value = 4 self.server._process_append_entry_request("peer_id", *ae_req) self.server._server_state.update_leader.assert_called_once_with( "peer_id") self.server._server_state.update_leader.reset_mock() ae_response = message.build_append_entry_response( self.server._server_state.term(), True, 0, None) self.server._remote_peers["peer_id"].\ send_message.assert_called_once_with(ae_response) self.server._remote_peers["peer_id"].\ send_message.reset_mock()
def test_process_append_entry_request_as_follower(self): ae_req = (0, 0, 0, 4, ()) self.server._server_state.is_leader.return_value = False self.server._server_state.commit_index.return_value = 4 self.server._process_append_entry_request("peer_id", *ae_req) self.server._server_state.update_leader.assert_called_once_with( "peer_id") self.server._server_state.update_leader.reset_mock() ae_response = message.build_append_entry_response( self.server._server_state.term(), True, 0, None) self.server._remote_peers["peer_id"].\ send_message.assert_called_once_with(ae_response) self.server._remote_peers["peer_id"].\ send_message.reset_mock()
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_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_build_append_entry_response(): test_params = (0, True, 0, None) aer_message = message.build_append_entry_response(*test_params) decoded_message = message.decode_message(aer_message) assert (message.APPEND_ENTRY_RESPONSE, test_params) == decoded_message
def _process_append_entry_request(self, m_leader_id, remote_term, leader_prev_log_index, leader_prev_log_term, leader_commit_index, leader_entries): """Processes the append entry request. :param m_leader_id: The identifier of the remote peer in the form of "address ip:port". :type: str :param remote_term: The term of the leader. :type remote_term: int :param leader_prev_log_index: The previous log entry of the leader. :type leader_prev_log_index: int :param leader_prev_log_term: The previous log term of the leader. :type leader_prev_log_term: int :param leader_commit_index: The commit index of the leader. :type leader_commit_index: int :param leader_entries: The leader entries to add next to the previous log entry of the leader. :type leader_entries: tuple """ # Received a stale request then respond negatively. if self._server_state.term() > remote_term: LOG.debug("stale append entry from '%s'" % m_leader_id) ae_response_ko = message.build_append_entry_response( self._server_state.term(), False, None, None) self._remote_peers[m_leader_id].send_message(ae_response_ko) # The current server is outdated then switch to follower. elif self._server_state.term() < remote_term: self._server_state.switch_to_follower(remote_term, m_leader_id) ae_response_ko = message.build_append_entry_response( self._server_state.term(), False, None, None) self._remote_peers[m_leader_id].send_message(ae_response_ko) else: if self._server_state.is_leader(): LOG.error("'%s' elected at same term '%d'" % (m_leader_id, remote_term)) self._server_state.switch_to_follower(remote_term, None) return LOG.debug("leader='%s', term='%d'" % (m_leader_id, self._server_state.term())) # If the peer is in candidate state and received an append entry # request in the same term, it means the remote peer has been # elected, then switch to follower state. if self._server_state.is_candidate(): self._server_state.switch_to_follower(remote_term, m_leader_id) # The leader is alive. self._server_state.update_leader(m_leader_id) local_prev_log_index = self._log.entry_at_index( leader_prev_log_index, decode=True) local_prev_entry_term = local_prev_log_index[1] # If induction checking is verified then add the leader entries to # the log and send positive response otherwise respond negatively. if local_prev_entry_term == leader_prev_log_term: LOG.info("received append entry request, induction checking " "succeed, previous_entry_index='%s', " "previous_entry_term='%s'" % (leader_prev_log_index, leader_prev_log_term)) self._log.add_entries_at_start_index(leader_prev_log_index + 1, leader_entries) last_log_index = self._log.last_index() ae_response_ok = message.build_append_entry_response( self._server_state.term(), True, last_log_index, None) self._remote_peers[m_leader_id].send_message(ae_response_ok) # Update local commit_index. if leader_commit_index > self._server_state.commit_index(): new_commit_index = min(leader_commit_index, self._log.last_index()) self._server_state.update_commit_index(new_commit_index) # Check if leader entries are committed and apply them to # the state machine if they are not applied yet. self._apply_committed_log_entries_to_state_machine() else: LOG.warn("received append entry request, induction checking " "failed, local entry term='%s', leader previous " "entry term='%s'" % (local_prev_entry_term, leader_prev_log_term)) first_conflicting_index = self._log.first_index_of_term( local_prev_entry_term) ae_response_ko = message.build_append_entry_response( self._server_state.term(), False, None, first_conflicting_index) self._remote_peers[m_leader_id].send_message(ae_response_ko)