feat(election-iomgr-refactor): restructure myapp_run to fully non-blocking async startup — task 5.1
This commit is contained in:
parent
757558bb33
commit
2e5681387a
4 changed files with 256 additions and 134 deletions
|
|
@ -41,6 +41,12 @@ int validate_vcpus(int vcpus);
|
|||
int validate_startup_config(const char *config_path,
|
||||
char *warn_buf, size_t warn_len);
|
||||
|
||||
/* Task 5.1 — ha_start_election_async (implemented in ha.c, task 2.4) */
|
||||
void ha_start_election_async(ha_state_t *ha, cluster_t *c,
|
||||
int n_peers, xce_candidate_t **peers,
|
||||
uint64_t my_config_tag, uint64_t my_lsn,
|
||||
const char *my_name);
|
||||
|
||||
/* ── Dispatch gate (task 3.3) — does NOT exist yet; linker failure expected ──
|
||||
*
|
||||
* ha_dispatch_gate: role-based operation filter for the vtaskmgr dispatch loop.
|
||||
|
|
@ -583,6 +589,105 @@ static void test_dispatch_gate_committing_allows_repl_ops(void)
|
|||
printf("test_dispatch_gate_committing_allows_repl_ops: PASS\n");
|
||||
}
|
||||
|
||||
/* ── Task 5.1: myapp_run startup sequence ────────────────────────────────
|
||||
*
|
||||
* Req 1.1, 9.3, 9.4: myapp_run must call ha_start_election_async (non-blocking)
|
||||
* and then cluster_run without any intervening blocking calls.
|
||||
*
|
||||
* These tests verify the call-sequence contract by checking that:
|
||||
* 1. ha_start_election_async with n_peers=1 sets ha->n_peers = 1 (single-node
|
||||
* path — the same path myapp_run takes for a single-node cluster).
|
||||
* 2. The role after ha_start_election_async(n_peers=1) is CTRL_PRIMARY_COMMITTING
|
||||
* (not CTRL_PRIMARY) — matching what myapp_run would produce in the new design.
|
||||
* 3. ha_start_election_async completes in < 10ms — confirming myapp_run does not
|
||||
* block before entering cluster_run.
|
||||
*
|
||||
* These tests are intentionally thin: myapp_run itself is an integration entry
|
||||
* point that requires a live network socket. The unit tests here verify that
|
||||
* the building blocks behave correctly; the integration test is test 13 in the
|
||||
* design testing strategy (regression: single-node self-elects).
|
||||
*/
|
||||
|
||||
static ha_config_t g_startup_cfg = {
|
||||
.heartbeat_interval_ms = 3000,
|
||||
.heartbeat_timeout_ms = 10000,
|
||||
.election_timeout_ms = 2000,
|
||||
.probe_connect_timeout_ms = 500,
|
||||
.max_promotion_retries = 5,
|
||||
.election_jitter_max_ms = 0,
|
||||
.election_priority_step_ms = 500,
|
||||
.committing_timeout_ms = 10000,
|
||||
};
|
||||
|
||||
static void test_nonblocking_single_node_election_sets_n_peers(void)
|
||||
{
|
||||
/* Req 1.1, 9.3: the new myapp_run path calls ha_start_election_async with
|
||||
* n_peers=1 for a single-node cluster. This test verifies the call stores
|
||||
* n_peers in ha->n_peers, matching the new myapp_run contract. */
|
||||
ha_state_t ha;
|
||||
ha_init(&ha, &g_startup_cfg, 0);
|
||||
ha.n_peers = 0;
|
||||
ha.phase2_done = 0;
|
||||
|
||||
ha_start_election_async(&ha, NULL, 1, NULL, 0ULL, 0ULL, "ctrl-a");
|
||||
|
||||
TEST_ASSERT_EQUAL_INT_MESSAGE(1, ha.n_peers,
|
||||
"myapp_run path: ha_start_election_async must store n_peers=1 for single-node");
|
||||
|
||||
ha_fini(&ha);
|
||||
printf("test_nonblocking_single_node_election_sets_n_peers: PASS\n");
|
||||
}
|
||||
|
||||
static void test_nonblocking_single_node_election_enters_committing(void)
|
||||
{
|
||||
/* Req 9.3, 8.1: After ha_start_election_async(n_peers=1) the role must be
|
||||
* CTRL_PRIMARY_COMMITTING, NOT CTRL_PRIMARY.
|
||||
* This validates that the new myapp_run path (without blocking for(;;) loop)
|
||||
* correctly transitions through the COMMITTING state. */
|
||||
ha_state_t ha;
|
||||
ha_init(&ha, &g_startup_cfg, 0);
|
||||
ha.phase2_done = 0;
|
||||
atomic_store_explicit(&ha.role, (int32_t)CTRL_ELECTING, memory_order_release);
|
||||
|
||||
ha_start_election_async(&ha, NULL, 1, NULL, 100ULL, 50ULL, "ctrl-a");
|
||||
|
||||
ctrl_role_t role = (ctrl_role_t)atomic_load_explicit(
|
||||
&ha.role, memory_order_acquire);
|
||||
TEST_ASSERT_EQUAL_INT_MESSAGE((int)CTRL_PRIMARY_COMMITTING, (int)role,
|
||||
"myapp_run path: single-node must enter CTRL_PRIMARY_COMMITTING after election");
|
||||
|
||||
ha_fini(&ha);
|
||||
printf("test_nonblocking_single_node_election_enters_committing: PASS (role=%d)\n",
|
||||
(int)role);
|
||||
}
|
||||
|
||||
static void test_nonblocking_election_returns_in_under_10ms(void)
|
||||
{
|
||||
/* Req 9.4, 1.1: ha_start_election_async must return in < 5ms (design spec).
|
||||
* Observable: myapp_run exits into cluster_run within 5ms of startup;
|
||||
* no blocking calls visible between ha_start_election_async and cluster_run. */
|
||||
ha_state_t ha;
|
||||
ha_init(&ha, &g_startup_cfg, 0);
|
||||
ha.phase2_done = 0;
|
||||
|
||||
struct timespec t0;
|
||||
clock_gettime(CLOCK_MONOTONIC, &t0);
|
||||
|
||||
ha_start_election_async(&ha, NULL, 1, NULL, 0ULL, 0ULL, "ctrl-a");
|
||||
|
||||
struct timespec t1;
|
||||
clock_gettime(CLOCK_MONOTONIC, &t1);
|
||||
long elapsed_ms_val = (t1.tv_sec - t0.tv_sec) * 1000L
|
||||
+ (t1.tv_nsec - t0.tv_nsec) / 1000000L;
|
||||
|
||||
TEST_ASSERT_LESS_OR_EQUAL_INT_MESSAGE(5, (int)elapsed_ms_val,
|
||||
"myapp_run path: ha_start_election_async must return in < 5ms (design spec)");
|
||||
|
||||
ha_fini(&ha);
|
||||
printf("test_nonblocking_election_returns_in_under_10ms: PASS (%ldms)\n",
|
||||
elapsed_ms_val);
|
||||
}
|
||||
|
||||
/* ── Test suite entry point ───────────────────────────────────────────── */
|
||||
|
||||
void test_ha_startup(void)
|
||||
|
|
@ -634,4 +739,9 @@ void test_ha_startup(void)
|
|||
/* Task 3.1 — dispatch gate: CTRL_PRIMARY_COMMITTING */
|
||||
RUN_TEST(test_dispatch_gate_committing_denies_job_ops);
|
||||
RUN_TEST(test_dispatch_gate_committing_allows_repl_ops);
|
||||
|
||||
/* Task 5.1 — myapp_run non-blocking startup sequence (Req 1.1, 9.3, 9.4) */
|
||||
RUN_TEST(test_nonblocking_single_node_election_sets_n_peers);
|
||||
RUN_TEST(test_nonblocking_single_node_election_enters_committing);
|
||||
RUN_TEST(test_nonblocking_election_returns_in_under_10ms);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue