feat: ha_state_t, ha_config_t, ha_init/fini, role enum + config validation (P1-2)
- Full ha.h: ctrl_role_t enum (CTRL_PRIMARY/CTRL_STANDBY), ha_config_t, ha_state_t with _Atomic fields (term, role, applied_lsn, promotion counters, watchdog_stop), pthread_mutex_t lock, and public API. - endpoint_t* omitted from ha_state_t — including netio.h would pull OpenSSL headers and risk circular deps; watchdog (P1-3) includes netio.h directly where needed. - ha_init validates: heartbeat_interval_ms >= 2000, heartbeat_timeout_ms >= heartbeat_interval_ms, election_timeout_ms >= 500; returns -EINVAL on bad config; zeros struct and sets initial role to CTRL_STANDBY. - ha_fini destroys mutex; watchdog thread join deferred to P1-3. - am_i_primary / ha_promote_to_primary / ha_demote_to_standby are no-op stubs; cluster_t->ha field not yet wired (P1-5), so these avoid incomplete-type dereferences until then. - TDD: 5 new tests in test_ha_role.c confirmed RED before implementation, all 5 GREEN after; all prior controller tests remain green.
This commit is contained in:
parent
f155b1ef97
commit
a289edb777
5 changed files with 255 additions and 2 deletions
94
src/controller/testsuite/test_ha_role.c
Normal file
94
src/controller/testsuite/test_ha_role.c
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
#include <stdatomic.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <unity/unity.h>
|
||||
|
||||
#include "ha.h"
|
||||
|
||||
static void test_ha_init_default_role_is_standby(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));
|
||||
TEST_ASSERT_EQUAL_INT(CTRL_STANDBY,
|
||||
(int)atomic_load_explicit(&ha.role, memory_order_acquire));
|
||||
ha_fini(&ha);
|
||||
printf("test_ha_init_default_role_is_standby: PASS\n");
|
||||
}
|
||||
|
||||
static void test_ha_init_rejects_fast_heartbeat(void)
|
||||
{
|
||||
ha_state_t ha;
|
||||
ha_config_t cfg = {
|
||||
.heartbeat_interval_ms = 1999, /* below 2000ms floor */
|
||||
.heartbeat_timeout_ms = 10000,
|
||||
.election_timeout_ms = 2000,
|
||||
.probe_connect_timeout_ms = 500,
|
||||
.max_promotion_retries = 5,
|
||||
};
|
||||
TEST_ASSERT_NOT_EQUAL(0, ha_init(&ha, &cfg, 0));
|
||||
printf("test_ha_init_rejects_fast_heartbeat: PASS\n");
|
||||
}
|
||||
|
||||
static void test_ha_init_rejects_short_election_timeout(void)
|
||||
{
|
||||
ha_state_t ha;
|
||||
ha_config_t cfg = {
|
||||
.heartbeat_interval_ms = 3000,
|
||||
.heartbeat_timeout_ms = 10000,
|
||||
.election_timeout_ms = 499, /* below 500ms floor */
|
||||
.probe_connect_timeout_ms = 500,
|
||||
.max_promotion_retries = 5,
|
||||
};
|
||||
TEST_ASSERT_NOT_EQUAL(0, ha_init(&ha, &cfg, 0));
|
||||
printf("test_ha_init_rejects_short_election_timeout: PASS\n");
|
||||
}
|
||||
|
||||
static void test_ha_init_rejects_timeout_less_than_interval(void)
|
||||
{
|
||||
ha_state_t ha;
|
||||
ha_config_t cfg = {
|
||||
.heartbeat_interval_ms = 5000,
|
||||
.heartbeat_timeout_ms = 4999, /* must be >= heartbeat_interval_ms */
|
||||
.election_timeout_ms = 2000,
|
||||
.probe_connect_timeout_ms = 500,
|
||||
.max_promotion_retries = 5,
|
||||
};
|
||||
TEST_ASSERT_NOT_EQUAL(0, ha_init(&ha, &cfg, 0));
|
||||
printf("test_ha_init_rejects_timeout_less_than_interval: PASS\n");
|
||||
}
|
||||
|
||||
static void test_ha_promote_sets_primary_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);
|
||||
/* Directly set role to PRIMARY (stub path — full promotion in P1-3a) */
|
||||
atomic_store_explicit(&ha.role, (int32_t)CTRL_PRIMARY, memory_order_release);
|
||||
TEST_ASSERT_EQUAL_INT(CTRL_PRIMARY,
|
||||
(int)atomic_load_explicit(&ha.role, memory_order_acquire));
|
||||
ha_fini(&ha);
|
||||
printf("test_ha_promote_sets_primary_role: PASS\n");
|
||||
}
|
||||
|
||||
void test_ha_role(void)
|
||||
{
|
||||
RUN_TEST(test_ha_init_default_role_is_standby);
|
||||
RUN_TEST(test_ha_init_rejects_fast_heartbeat);
|
||||
RUN_TEST(test_ha_init_rejects_short_election_timeout);
|
||||
RUN_TEST(test_ha_init_rejects_timeout_less_than_interval);
|
||||
RUN_TEST(test_ha_promote_sets_primary_role);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue