feat(raft-adapter-conformance): route post-connect vote/PreVote failures to production tally
Splits vote_ep_err_handler into a real-vote handler and a new pre_vote_ep_err_handler, each registered at its existing (already separate) connection-setup call site. Extracts the identical CTRL_PRIMARY-role cleanup into a shared vote_ep_handle_promoted_disconnect helper, behavior unchanged. Each handler's election-phase branch now routes a post-connect failure (RDHUP/SSL-error/remote-close after connect, before any reply) through the same production tally the connect-time failure branches already use (vote_reply_dispatch / pre_vote_reply_dispatch, bug-1423/1424's fix), instead of the legacy handle_request_vote_reply that never updated the tally. Closes the one failure window bug-1423 didn't cover. 1060 -> 1061 tests, 0 failures. PreVote-specific test coverage is task 3.2's scope (pre_vote_reply_dispatch has no hook seam analogous to xce_vote_reply_hook; verified only by code symmetry + full-suite regression here).
This commit is contained in:
parent
65afa04aaf
commit
fce73b5b58
3 changed files with 160 additions and 33 deletions
|
|
@ -654,6 +654,68 @@ static void test_bug1417_middle_index_real_vote_from_peer2_not_dropped(void)
|
|||
printf("test_bug1417_middle_index_real_vote_from_peer2_not_dropped: PASS\n");
|
||||
}
|
||||
|
||||
/* ── raft-adapter-conformance task 3.1: post-connect vote failure routing ──
|
||||
*
|
||||
* vote_ep_err_handler's election-phase branch (the iomgr err_handler fired
|
||||
* when an already-connected outgoing vote endpoint fails/closes before a
|
||||
* reply arrives) must count that outcome through vote_reply_dispatch -- the
|
||||
* SAME production tally path a connect-time failure (raft_cb_send_vote_request's
|
||||
* own rc<0 branches, bug-1423) or a delivered denial (vote_reply_msg_handler)
|
||||
* uses -- not the legacy handle_request_vote_reply, which bypasses
|
||||
* raft_on_vote_reply entirely and, critically for this test, never reaches the
|
||||
* xce_vote_reply_hook seam vote_reply_dispatch checks.
|
||||
*
|
||||
* Test seam: xce_vote_reply_hook (checked ONLY inside vote_reply_dispatch) lets
|
||||
* us observe, without a live iomgr/raft election, whether the post-connect
|
||||
* failure reached the production tally path. Pre-fix, this hook is never
|
||||
* invoked by vote_ep_err_handler's election branch -- proving the bug.
|
||||
*/
|
||||
|
||||
extern int vote_ep_err_handler_for_test(endpoint_t *ep);
|
||||
|
||||
static void test_post_connect_vote_failure_routes_through_production_tally(void)
|
||||
{
|
||||
reset_reply_mock();
|
||||
|
||||
ha_state_t ha;
|
||||
TEST_ASSERT_EQUAL_INT(0, ha_init(&ha, &g_vote_cfg, 0));
|
||||
/* Election phase, not CTRL_PRIMARY -- exercises the "else" branch. */
|
||||
atomic_store_explicit(&ha.role, CTRL_ELECTING, memory_order_release);
|
||||
atomic_store_explicit(&ha.term, 4ULL, memory_order_release);
|
||||
|
||||
ha_elect_ctx_t *ctx = alloc_ctx_for_vote(2);
|
||||
pthread_mutex_init(&ctx->lock, NULL);
|
||||
|
||||
endpoint_t ep;
|
||||
make_endpoint(&ep);
|
||||
|
||||
/* Build a real-vote endpoint context as if raft_cb_send_vote_request had
|
||||
* already connected it (on_vote_connected fired, request sent) -- then
|
||||
* the connection fails before any reply arrives: iomgr invokes the
|
||||
* registered err_handler on this same ep. */
|
||||
vote_ep_ctx_build_for_test(&ep, &ha, ctx, /*peer_idx=*/0,
|
||||
4ULL, 100ULL, 50ULL, "ctrl-a");
|
||||
|
||||
int rc = vote_ep_err_handler_for_test(&ep);
|
||||
TEST_ASSERT_EQUAL_INT(0, rc);
|
||||
|
||||
TEST_ASSERT_EQUAL_INT_MESSAGE(1, g_reply_hook_calls,
|
||||
"post-connect vote failure must reach vote_reply_dispatch's tally "
|
||||
"(xce_vote_reply_hook), not the legacy handle_request_vote_reply path "
|
||||
"which never invokes this hook");
|
||||
TEST_ASSERT_EQUAL_INT_MESSAGE(0, g_reply_granted,
|
||||
"a post-connect failure must be counted as a denied vote (granted=0)");
|
||||
TEST_ASSERT_EQUAL_UINT64_MESSAGE(4ULL, g_reply_term,
|
||||
"the synthesized denial must carry the candidate's own term");
|
||||
TEST_ASSERT_EQUAL_INT_MESSAGE(0, g_reply_peer_idx,
|
||||
"peer_idx must match the failed endpoint's vote_ep_ctx_t peer_idx");
|
||||
|
||||
free(ep.data);
|
||||
free_ctx_for_vote(ctx);
|
||||
ha_fini(&ha);
|
||||
printf("test_post_connect_vote_failure_routes_through_production_tally: PASS\n");
|
||||
}
|
||||
|
||||
/* ── Suite entry point ───────────────────────────────────────────────────── */
|
||||
|
||||
void test_ha_vote_send(void)
|
||||
|
|
@ -670,4 +732,6 @@ void test_ha_vote_send(void)
|
|||
RUN_TEST(test_vote_reply_handler_no_uaf);
|
||||
/* bug-1417 */
|
||||
RUN_TEST(test_bug1417_middle_index_real_vote_from_peer2_not_dropped);
|
||||
/* raft-adapter-conformance task 3.1 */
|
||||
RUN_TEST(test_post_connect_vote_failure_routes_through_production_tally);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue