def test_handle_RequestVoteMessage_vote_for_candidate(): controller = mock.MagicMock() id_ = 1 m = Machine(id_, controller) m._controller.enqueue.reset_mock() m.current_term = 2 m.log = [log.LogEntry(2, '')] m.voted_for = None msg = messages.RequestVoteMessage( src=4, dst=id_, term=2, candidate_id=4, last_log_index=0, last_log_term=2, ) m.handle_RequestVoteMessage(msg) enqueue_calls = m._controller.enqueue.mock_calls call = enqueue_calls[0] name, args, kwargs = call first_arg = args[0] assert isinstance(first_arg, messages.RequestVoteResponseMessage) assert first_arg.src == id_ assert first_arg.dst == 4 assert first_arg.term == m.current_term assert first_arg.vote_granted
def test_get_last_log_data(): controller = mock.MagicMock() id_ = 1 m = Machine(id_, controller) m._controller.enqueue.reset_mock() m.log = [log.LogEntry(m.current_term, '')] last_log_term, last_log_index = m.get_last_log_data() assert last_log_term == 0 assert last_log_index == 0
def test_handle_request_vote_reply_is_candidate_win_election(now): now.return_value = 123456789 controller = mock.MagicMock() id_ = 1 m = Machine(id_, controller) m._controller.enqueue.reset_mock() m.current_term = 5 m.voted_for = id_ m._state = constants.State.CANDIDATE m._votes = 2 m.log = [log.LogEntry(m.current_term, '')] msg = messages.RequestVoteResponseMessage( src=0, dst=1, term=m.current_term, ) m.handle_RequestVoteResponseMessage(msg) assert m._state == constants.State.LEADER # Assert messages sent to all other servers enqueue_calls = m._controller.enqueue.mock_calls[:-1] assert len(enqueue_calls) == len(m._servers) - 1 dsts = set() for mock_call in enqueue_calls: name, args, kwargs = mock_call msg = args[0] assert isinstance(msg, messages.AppendEntriesMessage) assert msg.src == id_ dsts.add(msg.dst) assert msg.term == m.current_term assert msg.leader_id == id_ assert msg.prev_log_term == 5 assert msg.prev_log_index == 0 assert msg.entries == () assert msg.leader_commit == 0 assert set(range(len(m._servers))) - {id_} == dsts call = m._controller.enqueue.mock_calls[-1] name, args, kwargs = call first_arg = args[0] assert isinstance(first_arg, messages.LeaderTimeoutMessage) assert first_arg.src == id_ assert first_arg.dst == id_ assert first_arg.term == m.current_term assert first_arg.time == 123456789 + m._leader_timeout
def test_send_heartbeat(): controller = mock.MagicMock() id_ = 1 m = Machine(id_, controller) m._controller.enqueue.reset_mock() m.log = [log.LogEntry(m.current_term, '')] m.send_heartbeat(3) enqueue_calls = m._controller.enqueue.mock_calls call = enqueue_calls[0] name, args, kwargs = call first_arg = args[0] assert isinstance(first_arg, messages.AppendEntriesMessage) assert first_arg.src == id_ assert first_arg.dst == 3 assert first_arg.term == m.current_term
def test_handle_append_entries_candidate_with_log_truncation(): controller = mock.MagicMock() servers = [(), ()] # Need two items in list for id = 1 to be valid id_ = 1 m = Machine(id_, controller, servers) m.current_term = 2 m.log = [ log.LogEntry(2, 'a'), log.LogEntry(2, 'b'), log.LogEntry(2, 'c'), ] m._state = constants.State.FOLLOWER m.voted_for = id_ msg = messages.AppendEntriesMessage( src=2, dst=id_, term=2, leader_id=2, prev_log_index=1, prev_log_term=2, entries=[ log.LogEntry(2, 'd'), log.LogEntry(2, 'e'), ], leader_commit=4, ) m.handle_AppendEntriesMessage(msg) assert m.log == [ log.LogEntry(2, 'a'), log.LogEntry(2, 'b'), log.LogEntry(2, 'd'), log.LogEntry(2, 'e'), ]