test(raft-adapter-conformance): dormant AppendEntries sender stays uncalled in production

New test drives repl_broadcast and ha_stream_wal_to_standby through
real production fixtures (reused from tasks 2.3/6.2), asserts both
actually fired (non-vacuous), and asserts
ha_send_append_entries_stub_call_count stays 0 throughout -- the
Requirement 3.3 non-regression guard. RED-verified: manually invoking
ha_cb_send_append_entries_for_test inside the test reliably trips the
assertion; reverted for GREEN.

1064 -> 1065 tests, 0 failures. Task 4 (dormant sender documentation +
guard) now complete.
This commit is contained in:
Rongsong Shen 2026-07-29 15:35:08 +00:00
parent 6d798df35d
commit 87ce7be917
2 changed files with 95 additions and 1 deletions

View file

@ -55,7 +55,7 @@
- Observable: the counter exists and is queryable from a test; the doc-comment names both the dormant path and the live substitute explicitly
- _Requirements: 3.3_
- [ ] 4.2 Test that the dormant sender stays uncalled in production
- [x] 4.2 Test that the dormant sender stays uncalled in production
- Drive the production heartbeat/replication path end-to-end in a test and assert the new call counter stays at zero
- In the same test, confirm `repl_broadcast`/`ha_stream_wal_to_standby` did fire for the same scenario, proving the assertion isn't vacuous
- Observable: the test fails if a future change accidentally gives `raft_send_append_entries` a production caller

View file

@ -2677,6 +2677,95 @@ static void test_4_1_send_append_entries_stub_call_count_increments(void)
printf("test_4_1_send_append_entries_stub_call_count_increments: PASS\n");
}
/* Task 4.2 (raft-adapter-conformance, Requirement 3.3): the fuller
* non-regression guard task 4.1's doc-comment promises — drive BOTH real
* production AppendEntries-equivalent senders (repl_broadcast for live
* in-term replication, ha_stream_wal_to_standby for catch-up streaming) end
* to end and assert ha_send_append_entries_stub_call_count stays at 0
* throughout, while independently confirming each real sender actually fired
* for this scenario — so the zero-count assertion is not vacuously true
* because nothing ran. Reuses the exact fixtures/hooks task 6.2's
* test_6_2_real_senders_never_produce_termblind_shape already established for
* driving these same two real senders (repl_broadcast_send_hook +
* hcs_6_2_broadcast_hook/g_hcs62_bcast_n for sender 1;
* xce_wal_stream_request_hook + hcs_2_3_capture_hook/g_sends_n for sender 2).
* If a future change ever gives raft_send_append_entries a production
* caller, this test catches it. */
static void test_4_2_dormant_sender_stays_uncalled_in_production(void)
{
/* Reset first: an earlier test in this same process (task 4.1's own
* sanity test, which runs immediately before this one in the suite)
* already drove ha_cb_send_append_entries_for_test directly and left the
* counter non-zero — Unity tests share process state. */
ha_send_append_entries_stub_call_count = 0;
/* ── Real sender 1: repl_broadcast (live in-term replication) ─────────── */
replicator_t r;
TEST_ASSERT_EQUAL_INT(0, repl_init(&r));
int dummy_ep = 0;
TEST_ASSERT_TRUE(repl_add_standby(&r, (void*)&dummy_ep, "standby", 7101) >= 0);
uint8_t full[HCS_FULL_LEN];
hcs_fill_body(full);
wal_entry_hdr_t hdr;
memset(&hdr, 0, sizeof(hdr));
hdr.lsn = 1;
hdr.type = WAL_JOB_SUBMIT;
hdr.term = 3;
g_hcs62_bcast_n = 0;
repl_broadcast_send_hook = hcs_6_2_broadcast_hook;
int brc = repl_broadcast(&r, &hdr, full, HCS_FULL_LEN, /*prev_log_term=*/0);
repl_broadcast_send_hook = NULL;
repl_fini(&r);
TEST_ASSERT_EQUAL_INT(0, brc);
TEST_ASSERT_EQUAL_INT_MESSAGE(1, g_hcs62_bcast_n,
"repl_broadcast must have actually sent to the registered standby — "
"otherwise the counter-stays-zero assertion below would be vacuous");
/* ── Real sender 2: ha_stream_wal_to_standby (catch-up streaming) ──────── */
hcs_member_t src, rcv;
TEST_ASSERT_EQUAL_INT(0, hcs_member_up(&src, "42src"));
TEST_ASSERT_EQUAL_INT(0, hcs_member_up(&rcv, "42rcv"));
TEST_ASSERT_EQUAL_INT(0, hcs_wal_put(&src, 1, /*term=*/3, WAL_JOB_SUBMIT,
full, HCS_FULL_LEN));
atomic_store_explicit(&src.p->committed_lsn, 1, memory_order_release);
hcs_2_3_reset(&rcv, /*fault_lsn=*/0 /* no fault injected — happy path */);
xce_wal_stream_request_hook = hcs_2_3_capture_hook;
int src_rc = ha_stream_wal_to_standby((endpoint_t*)NULL, src.wal_dir, src.p,
/*leader_term=*/3, /*standby_lsn=*/0,
/*committed_lsn=*/1);
xce_wal_stream_request_hook = NULL;
TEST_ASSERT_EQUAL_INT(0, src_rc);
TEST_ASSERT_TRUE_MESSAGE(g_sends_n >= 1,
"ha_stream_wal_to_standby must have actually streamed at least one "
"entry — otherwise the counter-stays-zero assertion below would be "
"vacuous");
hcs_member_down(&src);
hcs_member_down(&rcv);
/* ── The Requirement 3.3 non-regression guard itself ────────────────────
* Both real production AppendEntries-equivalent senders just fired
* (proven non-vacuous above) — yet the dormant
* ha_cb_send_append_entries_stub callback, reachable only via
* raft_send_append_entries (zero production callers), must never have
* been invoked by driving this real path. */
TEST_ASSERT_EQUAL_UINT64_MESSAGE(0, ha_send_append_entries_stub_call_count,
"driving the production heartbeat/replication path end-to-end must "
"NEVER increment ha_send_append_entries_stub_call_count — a nonzero "
"count here means raft_send_append_entries acquired a production "
"caller, invalidating the Requirement 3.3 'documented dormant' "
"resolution");
printf("test_4_2_dormant_sender_stays_uncalled_in_production: PASS\n");
}
/* ── Suite entry point ─────────────────────────────────────────────────────*/
void test_ha_core_safety(void)
@ -2777,4 +2866,9 @@ void test_ha_core_safety(void)
* itself increments correctly. Task 4.2 owns the fuller "stays at zero
* across a real production replication drive" assertion. */
RUN_TEST(test_4_1_send_append_entries_stub_call_count_increments);
/* Task 4.2 (raft-adapter-conformance): the fuller non-regression guard —
* drive repl_broadcast and ha_stream_wal_to_standby (the two real
* production senders) end-to-end and confirm the dormant stub's counter
* never moves off zero, while proving each real sender actually fired. */
RUN_TEST(test_4_2_dormant_sender_stays_uncalled_in_production);
}