feat: implement real am_i_primary() with election probing, ha_is_primary(), ha_check_priority_stepdown()
- Replace stub am_i_primary() with real election probe logic - probe_thread(): non-blocking TCP connect with optional SSL handshake - wait_any_probe(): deadline-based spin-poll across all probe threads - am_i_primary(): priority-0 always primary; higher priorities probe lower-priority peers and self-promote if deadline expires - ha_is_primary(): lock-free role check - ha_check_priority_stepdown(): simultaneous-boot stepdown at term=0 - start/stop_heartbeat_listener(): stubs for Task 7 - ha_init(): explicit initialization of ssl_ctx/jitter_seed/standby_endpoints - TDD: add test_am_i_primary suite with 3 tests covering p0/p1 paths
This commit is contained in:
parent
8d86a1bcfe
commit
fe3cc57f27
3 changed files with 337 additions and 6 deletions
|
|
@ -20,6 +20,7 @@ extern void test_e2e_hooks(void);
|
|||
extern void test_e2e_gc(void);
|
||||
extern void test_e2e_capnp(void);
|
||||
extern void test_ha_role(void);
|
||||
extern void test_am_i_primary(void);
|
||||
extern void test_ha_cluster(void);
|
||||
extern void test_ha_redirect(void);
|
||||
extern void test_p1_integration(void);
|
||||
|
|
@ -121,6 +122,7 @@ int main(int argc, char* argv[])
|
|||
TEST(test_e2e_gc);
|
||||
TEST(test_e2e_capnp);
|
||||
TEST(test_ha_role);
|
||||
TEST(test_am_i_primary);
|
||||
TEST(test_ha_cluster);
|
||||
TEST(test_ha_redirect);
|
||||
TEST(test_p1_integration);
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@
|
|||
#include <unity/unity.h>
|
||||
|
||||
#include "ha.h"
|
||||
#include "myconf.h"
|
||||
#include "xce/cluster_def.h"
|
||||
|
||||
static void test_ha_init_default_role_is_standby(void)
|
||||
{
|
||||
|
|
@ -232,6 +234,92 @@ static void test_sigusr1_sets_failover_requested(void)
|
|||
printf("test_sigusr1_sets_failover_requested: PASS\n");
|
||||
}
|
||||
|
||||
/* ── P1-6: am_i_primary() election tests ────────────────────────────── */
|
||||
|
||||
/* test: priority-0 with no peers → immediately primary (no probing needed) */
|
||||
void test_am_i_primary_p0_no_peers(void)
|
||||
{
|
||||
cluster_t c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
myconf_t myconf;
|
||||
memset(&myconf, 0, sizeof(myconf));
|
||||
c.myconf = &myconf;
|
||||
|
||||
ha_config_t cfg = {
|
||||
.heartbeat_interval_ms = HA_DEFAULT_HEARTBEAT_INTERVAL_MS,
|
||||
.heartbeat_timeout_ms = HA_DEFAULT_HEARTBEAT_TIMEOUT_MS,
|
||||
.election_timeout_ms = 500, /* minimum valid value */
|
||||
.probe_connect_timeout_ms = 100,
|
||||
.max_promotion_retries = 1,
|
||||
.election_jitter_max_ms = 0,
|
||||
.election_priority_step_ms = 0,
|
||||
};
|
||||
TEST_ASSERT_EQUAL_INT(0, ha_init(&c.ha, &cfg, 0));
|
||||
TEST_ASSERT_EQUAL_INT(1, am_i_primary(&c));
|
||||
ha_fini(&c.ha);
|
||||
printf("test_am_i_primary_p0_no_peers: PASS\n");
|
||||
}
|
||||
|
||||
/* test: priority-0 with peers → still primary (never probes higher-priority nodes) */
|
||||
void test_am_i_primary_p0_with_peers(void)
|
||||
{
|
||||
cluster_t c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
myconf_t myconf;
|
||||
memset(&myconf, 0, sizeof(myconf));
|
||||
myconf.peers_cfg.candidates_count = 2;
|
||||
strncpy(myconf.peers_cfg.candidates[0].hostname, "127.0.0.1", XCE_MAXNAME_LEN - 1);
|
||||
myconf.peers_cfg.candidates[0].port = 19900;
|
||||
strncpy(myconf.peers_cfg.candidates[1].hostname, "127.0.0.1", XCE_MAXNAME_LEN - 1);
|
||||
myconf.peers_cfg.candidates[1].port = 19901;
|
||||
c.myconf = &myconf;
|
||||
|
||||
ha_config_t cfg = {
|
||||
.heartbeat_interval_ms = HA_DEFAULT_HEARTBEAT_INTERVAL_MS,
|
||||
.heartbeat_timeout_ms = HA_DEFAULT_HEARTBEAT_TIMEOUT_MS,
|
||||
.election_timeout_ms = 500, /* minimum valid value */
|
||||
.probe_connect_timeout_ms = 100,
|
||||
.max_promotion_retries = 1,
|
||||
.election_jitter_max_ms = 0,
|
||||
.election_priority_step_ms = 0,
|
||||
};
|
||||
TEST_ASSERT_EQUAL_INT(0, ha_init(&c.ha, &cfg, 0));
|
||||
TEST_ASSERT_EQUAL_INT(1, am_i_primary(&c));
|
||||
ha_fini(&c.ha);
|
||||
printf("test_am_i_primary_p0_with_peers: PASS\n");
|
||||
}
|
||||
|
||||
/* test: priority-1 with no higher-priority peer alive → deadline expires → primary */
|
||||
void test_am_i_primary_p1_deadline_expires(void)
|
||||
{
|
||||
cluster_t c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
myconf_t myconf;
|
||||
memset(&myconf, 0, sizeof(myconf));
|
||||
/* Point to ports where nothing is listening */
|
||||
myconf.peers_cfg.candidates_count = 2;
|
||||
strncpy(myconf.peers_cfg.candidates[0].hostname, "127.0.0.1", XCE_MAXNAME_LEN - 1);
|
||||
myconf.peers_cfg.candidates[0].port = 19910; /* nothing listening */
|
||||
strncpy(myconf.peers_cfg.candidates[1].hostname, "127.0.0.1", XCE_MAXNAME_LEN - 1);
|
||||
myconf.peers_cfg.candidates[1].port = 19911;
|
||||
c.myconf = &myconf;
|
||||
|
||||
ha_config_t cfg = {
|
||||
.heartbeat_interval_ms = HA_DEFAULT_HEARTBEAT_INTERVAL_MS,
|
||||
.heartbeat_timeout_ms = HA_DEFAULT_HEARTBEAT_TIMEOUT_MS,
|
||||
.election_timeout_ms = 600, /* expires quickly; > 500ms floor */
|
||||
.probe_connect_timeout_ms = 200,
|
||||
.max_promotion_retries = 1,
|
||||
.election_jitter_max_ms = 0,
|
||||
.election_priority_step_ms = 0,
|
||||
};
|
||||
TEST_ASSERT_EQUAL_INT(0, ha_init(&c.ha, &cfg, 1)); /* priority 1 — must probe priority 0 */
|
||||
int result = am_i_primary(&c);
|
||||
TEST_ASSERT_EQUAL_INT(1, result); /* no peer responded → self-declare primary */
|
||||
ha_fini(&c.ha);
|
||||
printf("test_am_i_primary_p1_deadline_expires: PASS\n");
|
||||
}
|
||||
|
||||
void test_ha_role(void)
|
||||
{
|
||||
RUN_TEST(test_ha_init_default_role_is_standby);
|
||||
|
|
@ -247,3 +335,12 @@ void test_ha_role(void)
|
|||
RUN_TEST(test_demote_sets_standby_role);
|
||||
RUN_TEST(test_sigusr1_sets_failover_requested);
|
||||
}
|
||||
|
||||
/* ── P1-6 suite: am_i_primary() election ─────────────────────────────── */
|
||||
|
||||
void test_am_i_primary(void)
|
||||
{
|
||||
RUN_TEST(test_am_i_primary_p0_no_peers);
|
||||
RUN_TEST(test_am_i_primary_p0_with_peers);
|
||||
RUN_TEST(test_am_i_primary_p1_deadline_expires);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue