feat(ha-config-bootstrap): implement xce_retry_config_t and xce_request_with_retry (tasks 10.1, 10.2)

This commit is contained in:
Rongsong Shen 2026-05-29 03:00:34 +00:00
parent bb8e531a12
commit 0ec0ffa7e3
4 changed files with 163 additions and 12 deletions

View file

@ -50,7 +50,7 @@ static const xce_retry_config_t g_fast_cfg = {
struct mock_reply {
int32_t status; /* xce_reply_t.status to return */
int send_rc; /* return code from the hook (0 or -errno) */
char *redirect_host; /* non-NULL if status == -XCE_ERR_STANDBY */
char *redirect_host; /* non-NULL if status == -E_XCE_STANDBY */
uint16_t redirect_port;
};
@ -61,6 +61,10 @@ static int g_call_count = 0;
static void reset_mock(void)
{
for (int i = 0; i < g_reply_count; i++) {
free(g_replies[i].redirect_host);
g_replies[i].redirect_host = NULL;
}
g_reply_count = 0;
g_reply_idx = 0;
g_call_count = 0;
@ -108,16 +112,16 @@ static void install_mock(void)
/* ── Tests ──────────────────────────────────────────────────────── */
/* Req 7.1: XCE_ERR_NOT_READY → retry with backoff, eventually succeed */
/* Req 7.1: E_XCE_NOT_READY → retry with backoff, eventually succeed */
static void test_not_ready_retries_then_succeeds(void)
{
install_mock();
reset_mock();
/* 3 NOT_READY responses, then success */
add_reply(-XCE_ERR_NOT_READY, 0, NULL, 0);
add_reply(-XCE_ERR_NOT_READY, 0, NULL, 0);
add_reply(-XCE_ERR_NOT_READY, 0, NULL, 0);
add_reply(-E_XCE_NOT_READY, 0, NULL, 0);
add_reply(-E_XCE_NOT_READY, 0, NULL, 0);
add_reply(-E_XCE_NOT_READY, 0, NULL, 0);
add_reply(0, 0, NULL, 0); /* success */
xce_request_t req;
@ -130,14 +134,14 @@ static void test_not_ready_retries_then_succeeds(void)
printf("test_not_ready_retries_then_succeeds: PASS\n");
}
/* Req 7.2: XCE_ERR_STANDBY with redirect → reconnect to redirect, retry */
/* Req 7.2: E_XCE_STANDBY with redirect → reconnect to redirect, retry */
static void test_standby_with_redirect_reconnects_and_retries(void)
{
install_mock();
reset_mock();
/* Standby response with redirect */
add_reply(-XCE_ERR_STANDBY, 0, "primary.host", 9990);
add_reply(-E_XCE_STANDBY, 0, "primary.host", 9990);
add_reply(0, 0, NULL, 0); /* success on redirect target */
xce_request_t req;
@ -150,14 +154,14 @@ static void test_standby_with_redirect_reconnects_and_retries(void)
printf("test_standby_with_redirect_reconnects_and_retries: PASS\n");
}
/* Req 7.2 fallback: XCE_ERR_STANDBY without redirect → backoff, retry same */
/* Req 7.2 fallback: E_XCE_STANDBY without redirect → backoff, retry same */
static void test_standby_without_redirect_falls_back_to_backoff(void)
{
install_mock();
reset_mock();
/* STANDBY without redirect, then success */
add_reply(-XCE_ERR_STANDBY, 0, NULL, 0);
add_reply(-E_XCE_STANDBY, 0, NULL, 0);
add_reply(0, 0, NULL, 0);
xce_request_t req;
@ -199,7 +203,7 @@ static void test_max_retries_exhausted_returns_last_error(void)
/* Fill with NOT_READY beyond max_retries */
for (int i = 0; i <= g_fast_cfg.max_retries + 1; i++)
add_reply(-XCE_ERR_NOT_READY, 0, NULL, 0);
add_reply(-E_XCE_NOT_READY, 0, NULL, 0);
xce_request_t req;
memset(&req, 0, sizeof(req));
@ -284,7 +288,7 @@ static int concurrent_mock_send(endpoint_t *ep, xce_request_t *req,
* Since we can't track per-client state here, use a simple global
* threshold: first 100 calls NOT_READY, rest succeed. */
if (n < 100)
reply_out->status = -XCE_ERR_NOT_READY;
reply_out->status = -E_XCE_NOT_READY;
else
reply_out->status = 0;
return 0;