feat(raft-sim-conformance): Leader Completeness invariant checker (task 3.3)
This commit is contained in:
parent
d9b5fd51e0
commit
63a9740c85
4 changed files with 143 additions and 1 deletions
|
|
@ -3750,6 +3750,80 @@ static void test_sim_check_election_safety_pass_on_single_leader(void)
|
|||
TEST_ASSERT_EQUAL_INT(1, raft_sim_check_election_safety(&c));
|
||||
}
|
||||
|
||||
/*
|
||||
* test_sim_check_leader_completeness_fail_on_missing_committed (task 3.3)
|
||||
*
|
||||
* Leader Completeness: an entry committed in term t must be present (same index,
|
||||
* same term) in the log of every leader of a higher term. Hand-build a cluster
|
||||
* where node B has committed (index=2, term=3) but the current higher-term leader
|
||||
* (node A, LEADER at term 5) is MISSING that index ⇒ the checker must FAIL (0).
|
||||
* (Hand-set role/term/log/commit_index directly — this is a checker unit test over
|
||||
* a hand-built cluster, not a protocol run.)
|
||||
*/
|
||||
static void test_sim_check_leader_completeness_fail_on_missing_committed(void)
|
||||
{
|
||||
raft_sim_cluster_t c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(0, raft_sim_init(&c, 3, 2000));
|
||||
|
||||
/* Node B (idx 1): committed prefix 1..2, with entry 2 carrying term 3. */
|
||||
c.nodes[1].log[0].term = 1;
|
||||
c.nodes[1].log[1].term = 3;
|
||||
c.nodes[1].log_count = 2;
|
||||
c.nodes[1].commit_index = 2; /* (index=2, term=3) is committed */
|
||||
|
||||
/* Node A (idx 0): current LEADER at the HIGHER term 5, but its log is SHORT
|
||||
* (only index 1) ⇒ it is MISSING the committed index 2 ⇒ violation. */
|
||||
c.nodes[0].state.role = RAFT_LEADER;
|
||||
c.nodes[0].state.term = 5;
|
||||
c.nodes[0].log[0].term = 1;
|
||||
c.nodes[0].log_count = 1;
|
||||
|
||||
c.nodes[2].state.role = RAFT_FOLLOWER;
|
||||
c.nodes[2].state.term = 5;
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(0, raft_sim_check_leader_completeness(&c));
|
||||
}
|
||||
|
||||
/*
|
||||
* test_sim_check_leader_completeness_pass_when_present (task 3.3)
|
||||
*
|
||||
* Leader Completeness holds when every higher-term leader's log contains every
|
||||
* lower-term committed entry at the same (index, term). Two scenarios pass:
|
||||
* (a) the committed (index=2, term=3) entry IS present in higher-term leader A;
|
||||
* (b) a clean cluster with no current leaders trivially holds.
|
||||
*/
|
||||
static void test_sim_check_leader_completeness_pass_when_present(void)
|
||||
{
|
||||
raft_sim_cluster_t c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(0, raft_sim_init(&c, 3, 2000));
|
||||
|
||||
/* Node B (idx 1): committed prefix 1..2, entry 2 carries term 3. */
|
||||
c.nodes[1].log[0].term = 1;
|
||||
c.nodes[1].log[1].term = 3;
|
||||
c.nodes[1].log_count = 2;
|
||||
c.nodes[1].commit_index = 2;
|
||||
|
||||
/* (a) Node A (idx 0): LEADER at higher term 5 and DOES contain index 2 at
|
||||
* term 3 (and index 1) ⇒ Leader Completeness holds. */
|
||||
c.nodes[0].state.role = RAFT_LEADER;
|
||||
c.nodes[0].state.term = 5;
|
||||
c.nodes[0].log[0].term = 1;
|
||||
c.nodes[0].log[1].term = 3;
|
||||
c.nodes[0].log_count = 2;
|
||||
|
||||
c.nodes[2].state.role = RAFT_FOLLOWER;
|
||||
c.nodes[2].state.term = 5;
|
||||
TEST_ASSERT_EQUAL_INT(1, raft_sim_check_leader_completeness(&c));
|
||||
|
||||
/* (b) no current leaders at all ⇒ trivially holds (nothing to bind). */
|
||||
c.nodes[0].state.role = RAFT_FOLLOWER;
|
||||
TEST_ASSERT_EQUAL_INT(1, raft_sim_check_leader_completeness(&c));
|
||||
}
|
||||
|
||||
/* ---------- Group: Simulator invariant tests (tasks 9.1-9.4) ----------
|
||||
*
|
||||
* These are observation-based invariant tests. They drive the COMPLETE
|
||||
|
|
@ -7485,6 +7559,8 @@ void test_raft(void)
|
|||
RUN_TEST(test_sim_3_2_log_matching_shared_idx_term_requires_identical_prefix);
|
||||
RUN_TEST(test_sim_check_election_safety_fail_on_two_leaders);
|
||||
RUN_TEST(test_sim_check_election_safety_pass_on_single_leader);
|
||||
RUN_TEST(test_sim_check_leader_completeness_fail_on_missing_committed);
|
||||
RUN_TEST(test_sim_check_leader_completeness_pass_when_present);
|
||||
RUN_TEST(test_sim_9_1_replication_and_partition_catch_up);
|
||||
RUN_TEST(test_sim_9_2_divergent_suffix_truncation);
|
||||
RUN_TEST(test_sim_9_3_drop_dup_reorder_convergence);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue