Beispiel #1
0
 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()
Beispiel #2
0
 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()
Beispiel #3
0
    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()
Beispiel #4
0
    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()
Beispiel #5
0
 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()
Beispiel #6
0
 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()
Beispiel #7
0
    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)
Beispiel #8
0
    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)
Beispiel #9
0
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
Beispiel #10
0
    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)