feat(raft-sim-conformance): runtime fault-injection switch (G1 term-stamp, G3 truncate) (task 7.1)
This commit is contained in:
parent
7087dc19d9
commit
62523892d9
4 changed files with 156 additions and 1 deletions
|
|
@ -8547,6 +8547,99 @@ static void test_sim_5_5_stale_rejoin(void)
|
|||
* cluster sizes, each capped at RAFT_SIM_SWEEP_STEPS steps; the harness is fixed-array
|
||||
* (no allocation) so the whole batch stays within the lib test-suite time budget.
|
||||
*/
|
||||
/*
|
||||
* test_sim_7_1_fault_switch_mechanism (raft-sim-conformance task 7.1; Req 7.1, 7.3):
|
||||
* the deliberately-broken-build fault switch is RUNTIME-togglable, DEFAULT OFF, and
|
||||
* observably corrupts the harness adapter (term->0 / truncate no-op) only when set.
|
||||
* This is the MECHANISM check; the full both-directions invariant-violation demo is
|
||||
* task 7.2. Single-node conformance cluster so raft_start_election forces LEADER
|
||||
* without depending on bag delivery, mirroring test_sim_conformance_init_append_readback.
|
||||
*/
|
||||
static void test_sim_7_1_fault_switch_mechanism(void)
|
||||
{
|
||||
/* ---- DEFAULT OFF: the switch does not perturb a correct run ---- */
|
||||
{
|
||||
raft_sim_cluster_t c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
TEST_ASSERT_EQUAL_INT(0, raft_sim_conformance_init(&c, 1, 2000, 0x7A17ULL));
|
||||
/* fault_inject is zero-initialized -> OFF by default. */
|
||||
TEST_ASSERT_EQUAL_UINT(0u, c.fault_inject);
|
||||
|
||||
raft_start_election(&c.nodes[0].state);
|
||||
TEST_ASSERT_EQUAL_INT(RAFT_LEADER, c.nodes[0].state.role);
|
||||
|
||||
uint64_t value = 0xABCDEF0011223344ULL;
|
||||
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);
|
||||
/* With the switch OFF the persisted term equals the leader's term (not 0). */
|
||||
raft_sim_node_t *L = &c.nodes[0];
|
||||
TEST_ASSERT_EQUAL_UINT64(L->state.term, L->log[0].term);
|
||||
TEST_ASSERT_NOT_EQUAL(0, L->log[0].term);
|
||||
}
|
||||
|
||||
/* ---- RAFT_SIM_BREAK_TERM_STAMP: on_persist_entry writes term 0 (emulates G1) ---- */
|
||||
{
|
||||
raft_sim_cluster_t c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
TEST_ASSERT_EQUAL_INT(0, raft_sim_conformance_init(&c, 1, 2000, 0x7A17ULL));
|
||||
raft_sim_set_fault_inject(&c, RAFT_SIM_BREAK_TERM_STAMP);
|
||||
TEST_ASSERT_EQUAL_UINT(RAFT_SIM_BREAK_TERM_STAMP, c.fault_inject);
|
||||
|
||||
raft_start_election(&c.nodes[0].state);
|
||||
TEST_ASSERT_EQUAL_INT(RAFT_LEADER, c.nodes[0].state.role);
|
||||
|
||||
uint64_t value = 0xABCDEF0011223344ULL;
|
||||
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);
|
||||
raft_sim_node_t *L = &c.nodes[0];
|
||||
/* The leader's term is non-zero, yet the adapter stamped the entry term 0. */
|
||||
TEST_ASSERT_NOT_EQUAL(0, L->state.term);
|
||||
TEST_ASSERT_EQUAL_UINT64(0, L->log[0].term);
|
||||
/* on_get_entry_term reads back the corrupted term (0 => indistinguishable). */
|
||||
TEST_ASSERT_EQUAL_UINT64(0, L->cbs.on_get_entry_term(L, 1));
|
||||
|
||||
/* Clearing the flag restores correct stamping within the SAME binary. */
|
||||
raft_sim_set_fault_inject(&c, 0);
|
||||
TEST_ASSERT_EQUAL_UINT(0u, c.fault_inject);
|
||||
uint64_t value2 = 0x55667788AABBCCDDULL;
|
||||
TEST_ASSERT_EQUAL_INT(RAFT_OK,
|
||||
raft_log_append(&c.nodes[0].state, &value2, sizeof(value2), &out_index));
|
||||
TEST_ASSERT_EQUAL_UINT64(2, out_index);
|
||||
TEST_ASSERT_EQUAL_UINT64(L->state.term, L->log[1].term); /* term again correct */
|
||||
TEST_ASSERT_NOT_EQUAL(0, L->log[1].term);
|
||||
}
|
||||
|
||||
/* ---- RAFT_SIM_BREAK_TRUNCATE: on_truncate_from is a no-op (emulates G3) ---- */
|
||||
{
|
||||
raft_sim_cluster_t c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
TEST_ASSERT_EQUAL_INT(0, raft_sim_conformance_init(&c, 1, 2000, 0x7A17ULL));
|
||||
raft_sim_node_t *L = &c.nodes[0];
|
||||
|
||||
/* Seed two entries directly via the persist adapter (term != 0). */
|
||||
uint64_t e1 = 0x1111111111111111ULL, e2 = 0x2222222222222222ULL;
|
||||
TEST_ASSERT_EQUAL_INT(0, L->cbs.on_persist_entry(L, 1, 7, &e1, sizeof(e1)));
|
||||
TEST_ASSERT_EQUAL_INT(0, L->cbs.on_persist_entry(L, 2, 7, &e2, sizeof(e2)));
|
||||
TEST_ASSERT_EQUAL_INT(2, L->log_count);
|
||||
|
||||
/* With the switch OFF, truncate-from index 2 drops the suffix. */
|
||||
TEST_ASSERT_EQUAL_INT(0, L->cbs.on_truncate_from(L, 2));
|
||||
TEST_ASSERT_EQUAL_INT(1, L->log_count);
|
||||
|
||||
/* Re-seed, then with the switch ON the same truncate is a no-op: suffix stays. */
|
||||
TEST_ASSERT_EQUAL_INT(0, L->cbs.on_persist_entry(L, 2, 7, &e2, sizeof(e2)));
|
||||
TEST_ASSERT_EQUAL_INT(2, L->log_count);
|
||||
raft_sim_set_fault_inject(&c, RAFT_SIM_BREAK_TRUNCATE);
|
||||
TEST_ASSERT_EQUAL_INT(0, L->cbs.on_truncate_from(L, 2)); /* reports success */
|
||||
TEST_ASSERT_EQUAL_INT(2, L->log_count); /* but suffix lingers */
|
||||
TEST_ASSERT_EQUAL_UINT64(7, L->log[1].term); /* entry 2 still present */
|
||||
}
|
||||
}
|
||||
|
||||
#define RAFT_SIM_SWEEP_M 32 /* configured minimum number of randomized seeds (R6.2) */
|
||||
#define RAFT_SIM_SWEEP_STEPS 400 /* per-run step cap — bounded for the suite budget (R6.4) */
|
||||
|
||||
|
|
@ -8841,6 +8934,7 @@ void test_raft(void)
|
|||
RUN_TEST(test_sim_5_3_drop_dup_reorder);
|
||||
RUN_TEST(test_sim_5_4_figure8);
|
||||
RUN_TEST(test_sim_5_5_stale_rejoin);
|
||||
RUN_TEST(test_sim_7_1_fault_switch_mechanism);
|
||||
RUN_TEST(test_sim_6_1_seed_sweep);
|
||||
|
||||
/* Group A: basic election correctness (task 5.1) */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue