feat(controller-status): allow ctrlstatus through ha_dispatch_gate in all roles incl no-quorum (task 2.2)
This commit is contained in:
parent
a6e03d87ab
commit
e56409cbd4
3 changed files with 89 additions and 3 deletions
|
|
@ -791,6 +791,77 @@ static void test_election_stagger_desyncs_by_priority(void)
|
|||
printf("test_election_stagger_desyncs_by_priority: PASS\n");
|
||||
}
|
||||
|
||||
/* ── controller-status task 2.2: dispatch gate admits OPCode_ctrlstatus in
|
||||
* EVERY role — STANDBY, ELECTING, INIT, and PRIMARY-without-quorum — so the
|
||||
* read-only status query always answers (even fenced / without quorum),
|
||||
* rather than being rejected as -XCE_ERR_STANDBY / -XCE_ERR_NOT_READY.
|
||||
*
|
||||
* Requirements: controller-status 7.1, 7.2 (failover-aware, any-node delivery);
|
||||
* design §"Dispatch-gate allow-lists — Service contract".
|
||||
*
|
||||
* Scope guard: the change must be strictly scoped to OPCode_ctrlstatus — no
|
||||
* other opcode's gating may widen. This test also asserts that a previously
|
||||
* primary-only-when-serving read (OPCode_clusterconf) is STILL rejected on a
|
||||
* STANDBY after the change, proving the allow-list was not broadened.
|
||||
*
|
||||
* Note on PRIMARY-without-quorum: ha_has_write_quorum() returns false when the
|
||||
* connected-standby count is below n_peers/2. With n_peers == 0 (default
|
||||
* ha_init) the threshold is 0 and quorum is trivially satisfied, so to exercise
|
||||
* the no-quorum branch we set n_peers high enough that 0 connected standbys
|
||||
* fail the >= n_peers/2 test. */
|
||||
static void test_dispatch_gate_allows_ctrlstatus_in_every_role(void)
|
||||
{
|
||||
ha_state_t ha;
|
||||
ha_config_t cfg = {
|
||||
.heartbeat_interval_ms = 3000,
|
||||
.heartbeat_timeout_ms = 10000,
|
||||
.election_timeout_ms = 2000,
|
||||
.probe_connect_timeout_ms = 500,
|
||||
.max_promotion_retries = 5,
|
||||
};
|
||||
TEST_ASSERT_EQUAL_INT(0, ha_init(&ha, &cfg, 0));
|
||||
|
||||
/* CTRL_STANDBY — must allow ctrlstatus (Req 7.1, 7.2) */
|
||||
atomic_store_explicit(&ha.role, (int32_t)CTRL_STANDBY, memory_order_release);
|
||||
TEST_ASSERT_EQUAL_INT_MESSAGE(0,
|
||||
ha_dispatch_gate(&ha, OPCode_ctrlstatus),
|
||||
"CTRL_STANDBY must allow OPCode_ctrlstatus (Req 7.1, 7.2)");
|
||||
|
||||
/* CTRL_ELECTING — must allow ctrlstatus */
|
||||
atomic_store_explicit(&ha.role, (int32_t)CTRL_ELECTING, memory_order_release);
|
||||
TEST_ASSERT_EQUAL_INT_MESSAGE(0,
|
||||
ha_dispatch_gate(&ha, OPCode_ctrlstatus),
|
||||
"CTRL_ELECTING must allow OPCode_ctrlstatus (Req 7.1, 7.2)");
|
||||
|
||||
/* CTRL_INIT — must allow ctrlstatus */
|
||||
atomic_store_explicit(&ha.role, (int32_t)CTRL_INIT, memory_order_release);
|
||||
TEST_ASSERT_EQUAL_INT_MESSAGE(0,
|
||||
ha_dispatch_gate(&ha, OPCode_ctrlstatus),
|
||||
"CTRL_INIT must allow OPCode_ctrlstatus (Req 7.1, 7.2)");
|
||||
|
||||
/* CTRL_PRIMARY without write quorum — must allow ctrlstatus.
|
||||
* Force the no-quorum branch: with no replicator and zero connected
|
||||
* standby_endpoints, ha_has_write_quorum() returns false once n_peers > 1
|
||||
* (connected 0 < n_peers/2). */
|
||||
ha.n_peers = 3; /* threshold = n_peers/2 = 1; connected = 0 → no quorum */
|
||||
atomic_store_explicit(&ha.role, (int32_t)CTRL_PRIMARY, memory_order_release);
|
||||
TEST_ASSERT_EQUAL_INT_MESSAGE(0,
|
||||
ha_dispatch_gate(&ha, OPCode_ctrlstatus),
|
||||
"CTRL_PRIMARY without quorum must allow OPCode_ctrlstatus (Req 7.1, 7.2)");
|
||||
|
||||
/* Scope guard (Req: change strictly scoped to ctrlstatus): a read that is
|
||||
* primary-only-when-serving (OPCode_clusterconf) must STILL be rejected on
|
||||
* a STANDBY — proving the allow-list was not widened for any other opcode. */
|
||||
atomic_store_explicit(&ha.role, (int32_t)CTRL_STANDBY, memory_order_release);
|
||||
TEST_ASSERT_EQUAL_INT_MESSAGE(-XCE_ERR_STANDBY,
|
||||
ha_dispatch_gate(&ha, OPCode_clusterconf),
|
||||
"CTRL_STANDBY must STILL reject OPCode_clusterconf — gate change must "
|
||||
"be scoped strictly to OPCode_ctrlstatus");
|
||||
|
||||
ha_fini(&ha);
|
||||
printf("test_dispatch_gate_allows_ctrlstatus_in_every_role: PASS\n");
|
||||
}
|
||||
|
||||
void test_ha_role(void)
|
||||
{
|
||||
RUN_TEST(test_ha_init_default_role_is_standby);
|
||||
|
|
@ -835,6 +906,8 @@ void test_ha_role(void)
|
|||
RUN_TEST(test_dispatch_gate_allows_prevote_in_voter_roles);
|
||||
/* raft/ha-prevote (bug-606): failover election stagger desyncs survivors */
|
||||
RUN_TEST(test_election_stagger_desyncs_by_priority);
|
||||
/* controller-status task 2.2: dispatch gate admits ctrlstatus in every role */
|
||||
RUN_TEST(test_dispatch_gate_allows_ctrlstatus_in_every_role);
|
||||
}
|
||||
|
||||
/* test_am_i_primary suite deleted — am_i_primary() removed (election-iomgr-refactor) */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue