/* If commitidx > lastApplied: increment lastApplied, apply log[lastApplied] * to state machine (§5.3) */ void TestRaft_server_increment_lastApplied_when_lastApplied_lt_commitidx( CuTest* tc) { raft_entry_t ety; void *r = raft_new(); /* must be follower */ raft_set_state(r, RAFT_STATE_FOLLOWER); raft_set_current_term(r, 1); raft_set_commit_idx(r, 1); raft_set_last_applied_idx(r, 0); /* need at least one entry */ ety.term = 1; ety.id = 1; ety.data.buf = "aaa"; ety.data.len = 3; raft_append_entry(r, &ety); /* let time lapse */ raft_periodic(r, 1); CuAssertTrue(tc, 0 != raft_get_last_applied_idx(r)); CuAssertTrue(tc, 1 == raft_get_last_applied_idx(r)); }
/* TODO: check if test case is needed */ void TestRaft_follower_recv_appendentries_updates_currentterm_if_term_gt_currentterm( CuTest * tc) { msg_appendentries_t ae; msg_appendentries_response_t aer; void *r = raft_new(); raft_add_node(r, (void*)1, 1); raft_add_node(r, (void*)2, 0); /* older currentterm */ raft_set_current_term(r, 1); CuAssertTrue(tc, -1 == raft_get_current_leader(r)); /* newer term for appendentry */ memset(&ae, 0, sizeof(msg_appendentries_t)); /* no prev log idx */ ae.prev_log_idx = 0; ae.term = 2; /* appendentry has newer term, so we change our currentterm */ raft_recv_appendentries(r, 1, &ae, &aer); CuAssertTrue(tc, 1 == aer.success); /* term has been updated */ CuAssertTrue(tc, 2 == raft_get_current_term(r)); /* and leader has been updated */ CuAssertTrue(tc, 1 == raft_get_current_leader(r)); }
void TestRaft_scenario_leader_appears(CuTest * tc) { unsigned long i, j; raft_server_t *r[3]; void* sender[3]; senders_new(); for (j = 0; j < 3; j++) sender[j] = sender_new((void*)j); for (j = 0; j < 3; j++) { r[j] = raft_new(); sender_set_raft(sender[j], r[j]); raft_set_election_timeout(r[j], 500); raft_add_node(r[j], sender[0], 1, j==0); raft_add_node(r[j], sender[1], 2, j==1); raft_add_node(r[j], sender[2], 3, j==2); raft_set_callbacks(r[j], &((raft_cbs_t) { .send_requestvote = sender_requestvote, .send_appendentries = sender_appendentries, .persist_term = __raft_persist_term, .persist_vote = __raft_persist_vote, .log = NULL }), sender[j]); }
void TestRaft_follower_recv_appendentries_add_new_entries_not_already_in_log( CuTest * tc) { void *r = raft_new(); raft_add_node(r, (void*)1, 1); raft_add_node(r, (void*)2, 0); raft_set_current_term(r, 1); msg_appendentries_t ae; msg_appendentries_response_t aer; memset(&ae, 0, sizeof(msg_appendentries_t)); ae.term = 1; ae.prev_log_idx = 0; ae.prev_log_term = 1; /* include entries */ msg_entry_t e[2]; memset(&e, 0, sizeof(msg_entry_t) * 2); e[0].id = 1; e[1].id = 2; ae.entries = e; ae.n_entries = 2; raft_recv_appendentries(r, 1, &ae, &aer); CuAssertTrue(tc, 1 == aer.success); CuAssertTrue(tc, 2 == raft_get_log_count(r)); }
void TestRaft_election_start_increments_term(CuTest * tc) { void *r = raft_new(); raft_set_current_term(r, 1); raft_election_start(r); CuAssertTrue(tc, 2 == raft_get_current_term(r)); }
/* Candidate 5.2 */ void TestRaft_follower_becoming_candidate_increments_current_term(CuTest * tc) { void *r = raft_new(); CuAssertTrue(tc, 0 == raft_get_current_term(r)); raft_become_candidate(r); CuAssertTrue(tc, 1 == raft_get_current_term(r)); }
void TestRaft_server_entry_is_retrieveable_using_idx(CuTest* tc) { raft_entry_t e1; raft_entry_t e2; raft_entry_t *ety_appended; char *str = "aaa"; char *str2 = "bbb"; void *r = raft_new(); e1.term = 1; e1.id = 1; e1.data.buf = str; e1.data.len = 3; raft_append_entry(r, &e1); /* different ID so we can be successful */ e2.term = 1; e2.id = 2; e2.data.buf = str2; e2.data.len = 3; raft_append_entry(r, &e2); CuAssertTrue(tc, NULL != (ety_appended = raft_get_entry_from_idx(r, 2))); CuAssertTrue(tc, !strncmp(ety_appended->data.buf, str2, 3)); }
/* 5.1 */ void TestRaft_follower_recv_appendentries_reply_false_if_term_less_than_currentterm( CuTest * tc) { msg_appendentries_t ae; msg_appendentries_response_t aer, *aerr; void *r = raft_new(); raft_add_node(r, (void*)1, 1); raft_add_node(r, (void*)2, 0); void *sender = sender_new(NULL); /* no leader known at this point */ CuAssertTrue(tc, -1 == raft_get_current_leader(r)); /* term is low */ memset(&ae, 0, sizeof(msg_appendentries_t)); ae.term = 1; /* higher current term */ raft_set_current_term(r, 5); raft_recv_appendentries(r, 1, &ae, &aer); aerr = sender_poll_msg_data(sender); CuAssertTrue(tc, NULL != aerr); CuAssertTrue(tc, 0 == aerr->success); /* rejected appendentries doesn't change the current leader. */ CuAssertTrue(tc, -1 == raft_get_current_leader(r)); }
/* Candidate 5.2 */ void TestRaft_follower_dont_grant_vote_if_candidate_has_a_less_complete_log( CuTest * tc) { msg_requestvote_t rv; msg_requestvote_response_t rvr; void *r = raft_new(); raft_add_node(r, (void*)1, 1); raft_add_node(r, (void*)2, 0); /* request vote */ /* vote indicates candidate's log is not complete compared to follower */ memset(&rv, 0, sizeof(msg_requestvote_t)); rv.term = 1; rv.candidate_id = 1; rv.last_log_idx = 1; rv.last_log_term = 1; /* server's term and idx are more up-to-date */ raft_set_current_term(r, 1); raft_entry_t ety; ety.term = 1; ety.id = 100; ety.data.len = 4; ety.data.buf = (unsigned char*)"aaa"; raft_append_entry(r, &ety); ety.id = 101; raft_append_entry(r, &ety); /* vote not granted */ raft_recv_requestvote(r, 1, &rv, &rvr); CuAssertTrue(tc, 0 == rvr.vote_granted); }
void TestRaft_follower_recv_appendentries_does_not_log_if_no_entries_are_specified( CuTest * tc) { msg_appendentries_t ae; msg_appendentries_response_t aer; void *r = raft_new(); raft_add_node(r, (void*)1, 1); raft_add_node(r, (void*)2, 0); raft_set_state(r, RAFT_STATE_FOLLOWER); /* log size s */ CuAssertTrue(tc, 0 == raft_get_log_count(r)); /* receive an appendentry with commit */ memset(&ae, 0, sizeof(msg_appendentries_t)); ae.term = 1; ae.prev_log_term = 1; ae.prev_log_idx = 4; ae.leader_commit = 5; ae.n_entries = 0; raft_recv_appendentries(r, 1, &ae, &aer); CuAssertTrue(tc, 0 == raft_get_log_count(r)); }
void TestRaft_server_voting_results_in_voting(CuTest * tc) { void *r = raft_new(); raft_vote(r, 1); CuAssertTrue(tc, 1 == raft_get_voted_for(r)); raft_vote(r, 9); CuAssertTrue(tc, 9 == raft_get_voted_for(r)); }
void TestRaft_follower_becomes_follower_clears_voted_for(CuTest * tc) { void *r = raft_new(); raft_vote(r, 1); CuAssertTrue(tc, 1 == raft_get_voted_for(r)); raft_become_follower(r); CuAssertTrue(tc, -1 == raft_get_voted_for(r)); }
/* Candidate 5.2 */ void TestRaft_follower_becoming_candidate_votes_for_self(CuTest * tc) { void *r = raft_new(); CuAssertTrue(tc, -1 == raft_get_voted_for(r)); raft_become_candidate(r); CuAssertTrue(tc, raft_get_nodeid(r) == raft_get_voted_for(r)); CuAssertTrue(tc, 1 == raft_get_nvotes_for_me(r)); }
void TestRaft_server_cfg_sets_num_nodes(CuTest * tc) { void *r = raft_new(); raft_add_node(r, (void*)1, 1); raft_add_node(r, (void*)2, 0); CuAssertTrue(tc, 2 == raft_get_num_nodes(r)); }
/* 5.3 */ void TestRaft_follower_recv_appendentries_delete_entries_if_conflict_with_new_entries( CuTest * tc) { msg_appendentries_t ae; msg_appendentries_response_t aer; raft_entry_t *ety_appended; void *r = raft_new(); raft_add_node(r, (void*)1, 1); raft_add_node(r, (void*)2, 0); raft_set_current_term(r, 1); raft_entry_t ety; /* increase log size */ char *str1 = "111"; ety.data.buf = str1; ety.data.len = 3; ety.id = 1; ety.term = 1; raft_append_entry(r, &ety); CuAssertTrue(tc, 1 == raft_get_log_count(r)); /* this log will be overwritten by the appendentries below */ char *str2 = "222"; ety.data.buf = str2; ety.data.len = 3; ety.id = 2; ety.term = 1; raft_append_entry(r, &ety); CuAssertTrue(tc, 2 == raft_get_log_count(r)); CuAssertTrue(tc, NULL != (ety_appended = raft_get_entry_from_idx(r, 2))); CuAssertTrue(tc, !strncmp(ety_appended->data.buf, str2, 3)); /* pass a appendentry that is newer */ msg_entry_t mety; memset(&ae, 0, sizeof(msg_appendentries_t)); ae.term = 2; ae.prev_log_idx = 1; ae.prev_log_term = 1; /* include one entry */ memset(&mety, 0, sizeof(msg_entry_t)); char *str3 = "333"; mety.data.buf = str3; mety.data.len = 3; mety.id = 3; ae.entries = &mety; ae.n_entries = 1; raft_recv_appendentries(r, 1, &ae, &aer); CuAssertTrue(tc, 1 == aer.success); CuAssertTrue(tc, 2 == raft_get_log_count(r)); CuAssertTrue(tc, NULL != (ety_appended = raft_get_entry_from_idx(r, 1))); CuAssertTrue(tc, !strncmp(ety_appended->data.buf, str1, 3)); }
void TestRaft_server_cant_get_node_we_dont_have(CuTest * tc) { void *r = raft_new(); raft_add_node(r, (void*)1, 1); raft_add_node(r, (void*)2, 0); CuAssertTrue(tc, NULL != raft_get_node(r, 0)); CuAssertTrue(tc, NULL != raft_get_node(r, 1)); CuAssertTrue(tc, NULL == raft_get_node(r, 2)); }
void TestRaft_server_election_timeout_sets_to_zero_when_elapsed_time_greater_than_timeout( CuTest * tc) { void *r = raft_new(); raft_set_election_timeout(r, 1000); /* greater than 1000 */ raft_periodic(r, 2000); /* less than 1000 as the timeout would be randomised */ CuAssertTrue(tc, raft_get_timeout_elapsed(r) < 1000); }
void TestRaft_server_periodic_elapses_election_timeout(CuTest * tc) { void *r = raft_new(); /* we don't want to set the timeout to zero */ raft_set_election_timeout(r, 1000); CuAssertTrue(tc, 0 == raft_get_timeout_elapsed(r)); raft_periodic(r, 0); CuAssertTrue(tc, 0 == raft_get_timeout_elapsed(r)); raft_periodic(r, 100); CuAssertTrue(tc, 100 == raft_get_timeout_elapsed(r)); }
void TestRaft_server_idx_starts_at_1(CuTest * tc) { void *r = raft_new(); CuAssertTrue(tc, 0 == raft_get_current_idx(r)); raft_entry_t ety; ety.data.buf = "aaa"; ety.data.len = 3; ety.id = 1; ety.term = 1; raft_append_entry(r, &ety); CuAssertTrue(tc, 1 == raft_get_current_idx(r)); }
/* Candidate 5.2 */ void TestRaft_follower_becoming_candidate_resets_election_timeout(CuTest * tc) { void *r = raft_new(); raft_set_election_timeout(r, 1000); CuAssertTrue(tc, 0 == raft_get_timeout_elapsed(r)); raft_periodic(r, 900); CuAssertTrue(tc, 900 == raft_get_timeout_elapsed(r)); raft_become_candidate(r); /* time is selected randomly */ CuAssertTrue(tc, raft_get_timeout_elapsed(r) < 900); }
void TestRaft_server_append_entry_means_entry_gets_current_term(CuTest* tc) { raft_entry_t ety; char *str = "aaa"; ety.data.buf = str; ety.data.len = 3; ety.id = 1; ety.term = 1; void *r = raft_new(); CuAssertTrue(tc, 0 == raft_get_current_idx(r)); raft_append_entry(r, &ety); CuAssertTrue(tc, 1 == raft_get_current_idx(r)); }
void TestRaft_server_entry_append_cant_append_if_id_is_zero(CuTest* tc) { raft_entry_t ety; char *str = "aaa"; ety.data.buf = str; ety.data.len = 3; ety.id = 0; ety.term = 1; void *r = raft_new(); CuAssertTrue(tc, 0 == raft_get_current_idx(r)); raft_append_entry(r, &ety); CuAssertTrue(tc, 0 == raft_get_current_idx(r)); }
bool RaftConsensus::initialize(const Options& options) { if (_raft) { return true; } _raft = raft_new(); if (!_raft) { return false; } // // Seed the random number generator // rc_seed_random(); // // Initialize callbacks // rc_init_func(); raft_set_callbacks(_raft, &rc_funcs, this); // // add self // _opt = options; if (!addNode(_opt.node_id)) { return false; } // // Start as master // if (_opt.is_master) { becomeMaster(); } // // Set the election timeout // raft_set_election_timeout(_raft, _opt.election_timeout_ms); return true; }
void TestRaft_follower_recv_appendentries_resets_election_timeout( CuTest * tc) { void *r = raft_new(); raft_set_election_timeout(r, 1000); raft_periodic(r, 900); msg_appendentries_t ae; msg_appendentries_response_t aer; memset(&ae, 0, sizeof(msg_appendentries_t)); ae.term = 1; raft_recv_appendentries(r, 1, &ae, &aer); CuAssertTrue(tc, 0 == raft_get_timeout_elapsed(r)); }
void TestRaft_server_increase_votes_for_me_when_receive_request_vote_response( CuTest * tc ) { void *r = raft_new(); raft_add_node(r, (void*)1, 1); raft_add_node(r, (void*)2, 0); raft_set_current_term(r, 1); CuAssertTrue(tc, 0 == raft_get_nvotes_for_me(r)); msg_requestvote_response_t rvr; memset(&rvr, 0, sizeof(msg_requestvote_response_t)); rvr.term = 1; rvr.vote_granted = 1; raft_recv_requestvote_response(r, 1, &rvr); CuAssertTrue(tc, 1 == raft_get_nvotes_for_me(r)); }
void TestRaft_follower_becomes_candidate_when_election_timeout_occurs( CuTest * tc) { void *r = raft_new(); /* 1 second election timeout */ raft_set_election_timeout(r, 1000); raft_add_node(r, (void*)1, 1); raft_add_node(r, (void*)2, 0); /* 1.001 seconds have passed */ raft_periodic(r, 1001); /* is a candidate now */ CuAssertTrue(tc, 1 == raft_is_candidate(r)); }
void TestRaft_server_apply_entry_increments_last_applied_idx(CuTest* tc) { raft_entry_t ety; char *str = "aaa"; ety.term = 1; void *r = raft_new(); raft_set_commit_idx(r, 1); raft_set_last_applied_idx(r, 0); ety.id = 1; ety.data.buf = str; ety.data.len = 3; raft_append_entry(r, &ety); raft_apply_entry(r); CuAssertTrue(tc, 1 == raft_get_last_applied_idx(r)); }
/* Reply false if term < currentTerm (§5.1) */ void TestRaft_server_recv_requestvote_reply_false_if_term_less_than_current_term( CuTest * tc ) { msg_requestvote_response_t rvr; void *r = raft_new(); raft_add_node(r, (void*)1, 1); raft_add_node(r, (void*)2, 0); raft_set_current_term(r, 2); /* term is less than current term */ msg_requestvote_t rv; memset(&rv, 0, sizeof(msg_requestvote_t)); rv.term = 1; raft_recv_requestvote(r, 1, &rv, &rvr); CuAssertTrue(tc, 0 == rvr.vote_granted); }
void TestRaft_server_recv_requestvote_candidate_step_down_if_term_is_higher_than_current_term( CuTest * tc ) { void *r = raft_new(); raft_add_node(r, (void*)1, 1); raft_add_node(r, (void*)2, 0); raft_become_candidate(r); raft_set_current_term(r, 1); /* current term is less than term */ msg_requestvote_t rv; memset(&rv, 0, sizeof(msg_requestvote_t)); rv.term = 2; rv.last_log_idx = 1; msg_requestvote_response_t rvr; raft_recv_requestvote(r, 1, &rv, &rvr); CuAssertTrue(tc, 1 == raft_is_follower(r)); }
void TestRaft_follower_recv_appendentries_set_commitidx_to_LeaderCommit( CuTest * tc) { void *r = raft_new(); raft_add_node(r, (void*)1, 1); raft_add_node(r, (void*)2, 0); msg_appendentries_t ae; msg_appendentries_response_t aer; memset(&ae, 0, sizeof(msg_appendentries_t)); ae.term = 1; ae.prev_log_idx = 0; ae.prev_log_term = 1; /* include entries */ msg_entry_t e[4]; memset(&e, 0, sizeof(msg_entry_t) * 4); e[0].term = 1; e[0].id = 1; e[1].term = 1; e[1].id = 2; e[2].term = 1; e[2].id = 3; e[3].term = 1; e[3].id = 4; ae.entries = e; ae.n_entries = 4; raft_recv_appendentries(r, 1, &ae, &aer); /* receive an appendentry with commit */ memset(&ae, 0, sizeof(msg_appendentries_t)); ae.term = 1; ae.prev_log_term = 1; ae.prev_log_idx = 3; ae.leader_commit = 3; /* receipt of appendentries changes commit idx */ raft_recv_appendentries(r, 1, &ae, &aer); CuAssertTrue(tc, 1 == aer.success); /* set to 3 because leaderCommit is lower */ CuAssertTrue(tc, 3 == raft_get_commit_idx(r)); }