feat(raft-sim-conformance): bag push/deliver routes vote+AE RPCs through library handlers (task 2.1)
This commit is contained in:
parent
631854303c
commit
ae4495104a
4 changed files with 249 additions and 2 deletions
|
|
@ -4542,6 +4542,108 @@ static void test_sim_conformance_init_append_readback(void)
|
|||
TEST_ASSERT_EQUAL_UINT64(g1.prng, g2.prng);
|
||||
}
|
||||
|
||||
/*
|
||||
* test_sim_conformance_bag_deliver_routes_rpcs (raft-sim-conformance task 2.1; Req 2.2, 2.4)
|
||||
*
|
||||
* Observable completion for raft_sim_bag_push / raft_sim_bag_deliver(i):
|
||||
* - A pushed VOTE_REQ delivered by index invokes raft_on_vote_request on dst and
|
||||
* pushes a VOTE_RSP back onto the bag (src/dst swapped, granted=result). The
|
||||
* request is consumed (swap-with-last removal); the reply is the surviving member.
|
||||
* - A pushed AE_REQ delivered by index invokes raft_on_append_entries_request on
|
||||
* dst (replicating the single entry) and pushes an AE_RSP back (src/dst swapped,
|
||||
* success=result). The dst's in-memory log grows (handler ran).
|
||||
* - A request to a PARTITIONED dst is NOT delivered: no reply is pushed, the dst
|
||||
* state is unchanged, and the request stays in the bag (mirrors a dropped edge).
|
||||
*/
|
||||
static void test_sim_conformance_bag_deliver_routes_rpcs(void)
|
||||
{
|
||||
raft_sim_cluster_t c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
|
||||
/* 3-node conformance cluster; force node 0 to LEADER so it owns a real log
|
||||
* tail and per-peer progress for a genuine AppendEntries. */
|
||||
TEST_ASSERT_EQUAL_INT(0, raft_sim_conformance_init(&c, 3, 2000, 0xBA61ULL));
|
||||
|
||||
raft_start_election(&c.nodes[0].state); /* sends vote reqs to the bag */
|
||||
/* Drain the election vote traffic via direct delivery so node 0 wins, leaving
|
||||
* the bag empty for the targeted assertions below. */
|
||||
for (int g = 0; g < 64 && c.bag_count > 0; g++)
|
||||
raft_sim_bag_deliver(&c, 0); /* always deliver head */
|
||||
TEST_ASSERT_EQUAL_INT(RAFT_LEADER, c.nodes[0].state.role);
|
||||
|
||||
/* ---- VOTE_REQ routing ---- */
|
||||
c.bag_count = 0;
|
||||
raft_sim_msg_t vreq;
|
||||
memset(&vreq, 0, sizeof(vreq));
|
||||
vreq.kind = RAFT_SIM_MSG_VOTE_REQ;
|
||||
vreq.src = 1; /* candidate */
|
||||
vreq.dst = 2; /* voter */
|
||||
vreq.term = c.nodes[1].state.term + 5; /* fresh higher term -> grant */
|
||||
vreq.last_log_term = 0; /* empty-log candidate vs empty voter */
|
||||
vreq.last_log_index = 0;
|
||||
TEST_ASSERT_EQUAL_INT(0, raft_sim_bag_push(&c, &vreq));
|
||||
TEST_ASSERT_EQUAL_INT(1, c.bag_count);
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(0, raft_sim_bag_deliver(&c, 0));
|
||||
/* Request consumed, exactly one VOTE_RSP now in the bag, src/dst swapped. */
|
||||
TEST_ASSERT_EQUAL_INT(1, c.bag_count);
|
||||
TEST_ASSERT_EQUAL_INT(RAFT_SIM_MSG_VOTE_RSP, c.bag[0].kind);
|
||||
TEST_ASSERT_EQUAL_INT(2, c.bag[0].src); /* voter replies */
|
||||
TEST_ASSERT_EQUAL_INT(1, c.bag[0].dst); /* back to candidate */
|
||||
TEST_ASSERT_EQUAL_INT(1, c.bag[0].granted);
|
||||
/* Handler ran on dst: node 2 adopted the higher term and recorded the vote. */
|
||||
TEST_ASSERT_EQUAL_UINT64(vreq.term, c.nodes[2].state.term);
|
||||
TEST_ASSERT_EQUAL_INT(1, c.nodes[2].state.voted_for);
|
||||
|
||||
/* ---- AE_REQ routing ---- */
|
||||
c.bag_count = 0;
|
||||
/* Leader appends one client value, then sends AppendEntries to peer 1 — the
|
||||
* conformance send callback pushes a real AE_REQ onto the bag. */
|
||||
uint64_t value = 0xABCDEF12u;
|
||||
uint64_t out_index = 0;
|
||||
TEST_ASSERT_EQUAL_INT(RAFT_OK,
|
||||
raft_log_append(&c.nodes[0].state, &value, sizeof(value), &out_index));
|
||||
TEST_ASSERT_EQUAL_UINT64(1, out_index);
|
||||
TEST_ASSERT_EQUAL_INT(RAFT_OK,
|
||||
raft_send_append_entries(&c.nodes[0].state, 1, /*leader_commit=*/0));
|
||||
TEST_ASSERT_EQUAL_INT(1, c.bag_count);
|
||||
TEST_ASSERT_EQUAL_INT(RAFT_SIM_MSG_AE_REQ, c.bag[0].kind);
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(0, raft_sim_bag_deliver(&c, 0));
|
||||
/* AE request consumed, one AE_RSP remains, src/dst swapped, success. */
|
||||
TEST_ASSERT_EQUAL_INT(1, c.bag_count);
|
||||
TEST_ASSERT_EQUAL_INT(RAFT_SIM_MSG_AE_RSP, c.bag[0].kind);
|
||||
TEST_ASSERT_EQUAL_INT(1, c.bag[0].src); /* follower replies */
|
||||
TEST_ASSERT_EQUAL_INT(0, c.bag[0].dst); /* back to leader */
|
||||
TEST_ASSERT_EQUAL_INT(1, c.bag[0].success);
|
||||
/* Handler ran on dst: node 1 replicated the single entry. */
|
||||
TEST_ASSERT_EQUAL_INT(1, c.nodes[1].log_count);
|
||||
TEST_ASSERT_EQUAL_UINT64(c.nodes[0].log[0].term, c.nodes[1].log[0].term);
|
||||
|
||||
/* ---- partitioned dst is NOT delivered ---- */
|
||||
c.bag_count = 0;
|
||||
raft_sim_partition(&c, 2, 1); /* isolate the voter */
|
||||
int term2_before = (int)c.nodes[2].state.term;
|
||||
int votedfor2_before = c.nodes[2].state.voted_for;
|
||||
|
||||
raft_sim_msg_t vreq2;
|
||||
memset(&vreq2, 0, sizeof(vreq2));
|
||||
vreq2.kind = RAFT_SIM_MSG_VOTE_REQ;
|
||||
vreq2.src = 1;
|
||||
vreq2.dst = 2; /* partitioned */
|
||||
vreq2.term = c.nodes[2].state.term + 9;
|
||||
TEST_ASSERT_EQUAL_INT(0, raft_sim_bag_push(&c, &vreq2));
|
||||
TEST_ASSERT_EQUAL_INT(1, c.bag_count);
|
||||
|
||||
/* Delivery to a partitioned endpoint is a no-op: distinct non-zero status,
|
||||
* the request stays in the bag, no reply pushed, dst state unchanged. */
|
||||
TEST_ASSERT_NOT_EQUAL(0, raft_sim_bag_deliver(&c, 0));
|
||||
TEST_ASSERT_EQUAL_INT(1, c.bag_count); /* request not consumed */
|
||||
TEST_ASSERT_EQUAL_INT(RAFT_SIM_MSG_VOTE_REQ, c.bag[0].kind); /* still the request */
|
||||
TEST_ASSERT_EQUAL_INT(term2_before, (int)c.nodes[2].state.term);
|
||||
TEST_ASSERT_EQUAL_INT(votedfor2_before, c.nodes[2].state.voted_for);
|
||||
}
|
||||
|
||||
/* ---------- Group A: Basic Election Correctness (task 5.1) ---------- */
|
||||
|
||||
/*
|
||||
|
|
@ -7108,6 +7210,9 @@ void test_raft(void)
|
|||
/* conformance init + in-memory adapter callbacks (task 1.2) */
|
||||
RUN_TEST(test_sim_conformance_init_append_readback);
|
||||
|
||||
/* conformance bag push/deliver routing (task 2.1) */
|
||||
RUN_TEST(test_sim_conformance_bag_deliver_routes_rpcs);
|
||||
|
||||
/* Group A: basic election correctness (task 5.1) */
|
||||
RUN_TEST(test_proto_A1_single_node_self_elects);
|
||||
RUN_TEST(test_proto_A2_3node_one_leader);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue