forked from lei.chen/myxce
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:
parent
6d798df35d
commit
87ce7be917
2 changed files with 95 additions and 1 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue