def test_peer_rejects_append_entries_on_term_mismatch_setup(): event_queues = common.create_event_queues() peers = None startup_state = "follower" initial_term = 3 election_timeout = range(1000, 3000) commit_index = 0 log = MemoryLog() log.append(LogEntry(log_index=1, term=2, command=None, data=None)) log.append(LogEntry(log_index=2, term=2, command=None, data=None)) log.append(LogEntry(log_index=3, term=2, command=None, data=None)) log.append(LogEntry(log_index=4, term=2, command=None, data=None)) key_store = None initialize_next_index = False event_queues.state_machine.put_nowait( AppendEntries( event_id=str(uuid.uuid4()), source_server="leader_server", destination_server="peer_server", term=4, leader_id="leader_server", prev_log_index=4, prev_log_term=4, entries=[LogEntry(log_index=5, term=4, command=None, data=None)], leader_commit=1, )) proc = mp.Process( target=common.start_state_machine, args=( event_queues, startup_state, peers, initial_term, election_timeout, commit_index, log, key_store, initialize_next_index, "peer_server", ), ) proc.start() time.sleep(0.1) yield event_queues proc.kill()
def test_peer_grants_vote_setup(): event_queues = common.create_event_queues() peers = None startup_state = "follower" initial_term = 3 election_timeout = range(1000, 3000) commit_index = 0 log = MemoryLog() log.append(LogEntry(log_index=1, term=3, command=None, data=None)) log.append(LogEntry(log_index=2, term=3, command=None, data=None)) key_store = None initialize_next_index = False event_queues.state_machine.put_nowait( RequestVote( event_id=str(uuid.uuid4()), source_server="candidate_server", destination_server="peer_server", term=4, candidate_id="candidate_server", last_log_index=6, last_log_term=3, )) event_queues.state_machine.put_nowait( LocalStateSnapshotRequestForTesting()) proc = mp.Process( target=common.start_state_machine, args=( event_queues, startup_state, peers, initial_term, election_timeout, commit_index, log, key_store, initialize_next_index, "peer_server", ), ) proc.start() time.sleep(0.1) yield event_queues proc.kill()
def test_peer_deletes_conflicting_log_entries_and_appends_new( conflicting_entries): event_queues = conflicting_entries event = event_queues.dispatcher.get_nowait() state = event_queues.testing.get_nowait() assert event.success == True assert event.term == 4 assert event.last_log_index == 5 assert state.state["log"] == [ LogEntry(log_index=1, term=2, command="_set", data={ "key": "a", "value": "foo" }), LogEntry(log_index=2, term=2, command="_set", data={ "key": "a", "value": "foo" }), LogEntry(log_index=3, term=2, command="_set", data={ "key": "a", "value": "foo" }), LogEntry(log_index=4, term=2, command="_set", data={ "key": "a", "value": "foo" }), LogEntry(log_index=5, term=4, command="_set", data={ "key": "a", "value": 1 }), ]
def _handle_client_request(self, event): log_entry = LogEntry(log_index=self._log.next_index(), term=self._term, command=event.command, data=event.data) self._log.append(log_entry) self._event_queues.log_writer.put_nowait(log_entry) self._pending_client_requests.append( PendingClientRequest( request_id=event.event_id, request_commit_index=log_entry.log_index, request_receive_time=time.monotonic(), ))
def test_peer_commits_entries_and_advances_commit_index_setup(): event_queues = common.create_event_queues() peers = None startup_state = "follower" initial_term = 2 election_timeout = range(1000, 3000) commit_index = 0 log = MemoryLog() log.append( LogEntry(log_index=1, term=2, command="_set", data={ "key": "a", "value": 1 })) log.append( LogEntry(log_index=2, term=2, command="_set", data={ "key": "a", "value": 1 })) log.append( LogEntry(log_index=3, term=2, command="_set", data={ "key": "a", "value": 1 })) log.append( LogEntry(log_index=4, term=2, command="_set", data={ "key": "a", "value": 1 })) log.append( LogEntry(log_index=5, term=2, command="_set", data={ "key": "a", "value": 1 })) log.append( LogEntry(log_index=6, term=2, command="_set", data={ "key": "a", "value": 1 })) log.append( LogEntry(log_index=7, term=2, command="_set", data={ "key": "a", "value": 1 })) key_store = None initialize_next_index = False event_queues.state_machine.put_nowait( AppendEntries( event_id=str(uuid.uuid4()), source_server="leader_server", destination_server="peer_server", term=3, leader_id="leader_server", prev_log_index=7, prev_log_term=2, entries=[ LogEntry(log_index=8, term=2, command="_set", data={ "key": "b", "value": 2 }) ], leader_commit=8, )) event_queues.state_machine.put_nowait( LocalStateSnapshotRequestForTesting()) proc = mp.Process( target=common.start_state_machine, args=( event_queues, startup_state, peers, initial_term, election_timeout, commit_index, log, key_store, initialize_next_index, "peer_server", ), ) proc.start() time.sleep(0.1) yield event_queues proc.kill()
def test_peer_appends_new_entries(new_entries): event_queues = new_entries event = event_queues.dispatcher.get_nowait() state = event_queues.testing.get_nowait() assert event.success == True assert event.term == 3 assert event.last_log_index == 8 assert state.state["log"] == [ LogEntry(log_index=1, term=2, command="_set", data={ "key": "a", "value": 11 }), LogEntry(log_index=2, term=2, command="_set", data={ "key": "a", "value": 11 }), LogEntry(log_index=3, term=2, command="_set", data={ "key": "a", "value": 11 }), LogEntry(log_index=4, term=2, command="_set", data={ "key": "a", "value": 11 }), LogEntry(log_index=5, term=2, command="_set", data={ "key": "a", "value": 11 }), LogEntry(log_index=6, term=2, command="_set", data={ "key": "a", "value": 11 }), LogEntry(log_index=7, term=2, command="_set", data={ "key": "a", "value": 11 }), LogEntry(log_index=8, term=2, command="_set", data={ "key": "a", "value": 11 }), ]
from raft.structures.log_entry import LogEntry _DEFAULT_LOG_INDEX = 0 _DEFAULT_LOG_TERM = 0 _DEFAULT_LOG_ENTRY = LogEntry( log_index=_DEFAULT_LOG_INDEX, term=_DEFAULT_LOG_TERM, command=None, data=None, ) class MemoryLog: def __init__(self): self._log = [] def append(self, entry): self._log.append(entry) def at(self, index): try: return self._log[index] if index < 0 else self._log[index - 1] except IndexError: return None def last_index(self): if self._log: return self._log[-1].log_index else: return _DEFAULT_LOG_INDEX