feat: ha_do_promote/demote + SIGUSR1 atomic flag handler (P1-3a)
- ha_do_promote(): atomic_fetch_add term, set role=PRIMARY, reset last_received_crc to WAL_CRC_NONE (COH-5 chain restart on promotion) - ha_do_demote(): set role=STANDBY, reset hooks_registered idempotency guard - ha_install_sigusr1(): sigaction handler stores only atomic int — async-signal-safe per POSIX.1-2017 §2.4.3; global g_sigusr1_ha set once before signals are enabled - ha_promote_to_primary() / ha_demote_to_standby() remain (void)c stubs pending P1-5 cluster wiring Tests: 3 new cases in test_ha_role.c test_promote_increments_term: term > term_before, role == PRIMARY test_demote_sets_standby_role: role reverts to STANDBY after promote+demote test_sigusr1_sets_failover_requested: raise(SIGUSR1) sets atomic flag Result: 100 Tests 0 Failures 0 Ignored (controller suite)
This commit is contained in:
parent
2fae4c3df5
commit
652b015458
3 changed files with 165 additions and 0 deletions
|
|
@ -1,3 +1,4 @@
|
|||
#include <signal.h>
|
||||
#include <stdatomic.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
|
@ -151,6 +152,86 @@ static void test_heartbeat_stale_no_crash_without_primary(void)
|
|||
printf("test_heartbeat_stale_no_crash_without_primary: PASS\n");
|
||||
}
|
||||
|
||||
/* ── P1-3a tests ─────────────────────────────────────────────── */
|
||||
|
||||
/* Term must increment on each promotion attempt */
|
||||
static void test_promote_increments_term(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,
|
||||
};
|
||||
ha_init(&ha, &cfg, 0);
|
||||
uint64_t term_before = atomic_load_explicit(&ha.term, memory_order_acquire);
|
||||
|
||||
ha_do_promote(&ha); /* internal promotion logic — no cluster_t needed */
|
||||
|
||||
uint64_t term_after = atomic_load_explicit(&ha.term, memory_order_acquire);
|
||||
TEST_ASSERT_TRUE(term_after > term_before);
|
||||
TEST_ASSERT_EQUAL_INT(CTRL_PRIMARY,
|
||||
(int)atomic_load_explicit(&ha.role, memory_order_acquire));
|
||||
|
||||
ha_fini(&ha);
|
||||
printf("test_promote_increments_term: PASS\n");
|
||||
}
|
||||
|
||||
/* Demotion must set role back to STANDBY */
|
||||
static void test_demote_sets_standby_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,
|
||||
};
|
||||
ha_init(&ha, &cfg, 0);
|
||||
ha_do_promote(&ha);
|
||||
TEST_ASSERT_EQUAL_INT(CTRL_PRIMARY,
|
||||
(int)atomic_load_explicit(&ha.role, memory_order_acquire));
|
||||
|
||||
ha_do_demote(&ha);
|
||||
TEST_ASSERT_EQUAL_INT(CTRL_STANDBY,
|
||||
(int)atomic_load_explicit(&ha.role, memory_order_acquire));
|
||||
|
||||
ha_fini(&ha);
|
||||
printf("test_demote_sets_standby_role: PASS\n");
|
||||
}
|
||||
|
||||
/* SIGUSR1 must set failover_requested via async-signal-safe atomic store */
|
||||
static void test_sigusr1_sets_failover_requested(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,
|
||||
};
|
||||
ha_init(&ha, &cfg, 0);
|
||||
|
||||
/* Install real SIGUSR1 handler that uses only the atomic flag */
|
||||
ha_install_sigusr1(&ha);
|
||||
|
||||
/* Send SIGUSR1 to self */
|
||||
raise(SIGUSR1);
|
||||
|
||||
/* Handler must have set failover_requested */
|
||||
TEST_ASSERT_TRUE(
|
||||
atomic_load_explicit(&ha.failover_requested, memory_order_acquire) != 0);
|
||||
|
||||
/* Restore default SIGUSR1 handler */
|
||||
signal(SIGUSR1, SIG_DFL);
|
||||
ha_fini(&ha);
|
||||
printf("test_sigusr1_sets_failover_requested: PASS\n");
|
||||
}
|
||||
|
||||
void test_ha_role(void)
|
||||
{
|
||||
RUN_TEST(test_ha_init_default_role_is_standby);
|
||||
|
|
@ -161,4 +242,8 @@ void test_ha_role(void)
|
|||
RUN_TEST(test_watchdog_starts_and_stops);
|
||||
RUN_TEST(test_heartbeat_no_action_when_no_primary);
|
||||
RUN_TEST(test_heartbeat_stale_no_crash_without_primary);
|
||||
/* P1-3a */
|
||||
RUN_TEST(test_promote_increments_term);
|
||||
RUN_TEST(test_demote_sets_standby_role);
|
||||
RUN_TEST(test_sigusr1_sets_failover_requested);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue