myxce/src/controller/testsuite/test_ha_bootstrap_support.c

114 lines
3.9 KiB
C

/* test_ha_bootstrap_support.c — Test fixture for bootstrap probe injection.
*
* This file is compiled into the controller_unit_test binary under XCE_TESTING.
* It installs a mock probe function via __attribute__((constructor)) before any
* test runs, so that test_ha_bootstrap.c tests do not need real network peers.
*
* Mock probe behaviour (keyed by port):
* port 59901 → tag = 0xDEAD0001 (non-zero: peer has a config)
* port 59902 → tag = 0 (zero: peer has no config)
* port 59900 → tag = 0 (zero: peer has no config)
* any other → tag = 0 (zero: treat as unconfigured)
*
* Requirements: 3.2 (any peer tag>0 → defer), 3.3 (all-zero → no defer)
*/
#ifdef XCE_TESTING
#include <stdint.h>
#include "config_repl.h"
static int mock_xce_probe_config_tag(const char *host, uint16_t port,
uint64_t *tag_out)
{
(void)host;
/* Port 59901: simulate a peer that already has a config (non-zero tag) */
if (port == 59901) {
*tag_out = 0xDEAD000100000001ULL;
return 0;
}
/* All other test ports return tag=0 (unconfigured peer) */
*tag_out = 0;
return 0;
}
__attribute__((constructor))
static void install_bootstrap_probe_mock(void)
{
xce_probe_config_tag_hook = mock_xce_probe_config_tag;
}
/* ── Stub: bootstrap_config_if_needed ───────────────────────────────────────
*
* The production implementation was removed in task 5.3 (Req 1.1, 9.2).
* This stub satisfies the linker for test_ha_bootstrap.c which still exercises
* the bootstrap contracts via the hook seam above.
*
* Behaviour mirrors the simplified production logic: if config_tag is already
* non-zero, return immediately; otherwise set defer_config_fetch and return 0.
*/
#include "cluster.h"
int bootstrap_config_if_needed(cluster_t *c)
{
if (c->myconf->config_version_tag != 0)
return 0;
c->ha.defer_config_fetch = true;
return 0;
}
/* ── Stub: am_i_primary_quorum ──────────────────────────────────────────────
*
* The production implementation (blocking pthread election) was removed in
* task 5.3 (Req 1.1, 9.2). This stub satisfies the linker for
* test_ha_election.c tests that still exercise election contracts via
* ha_elect_evaluate_and_signal directly (peers==NULL path).
*
* Single-node (n_peers==1): self-elect, bump term, return CTRL_PRIMARY.
* Multi-node without peers (peers==NULL, unit-test mode): allocate
* ha_elect_ctx_t, call ha_elect_evaluate_and_signal, free ctx.
* Multi-node with peers != NULL is not exercised in unit tests.
*/
#include <stdatomic.h>
#include <stdlib.h>
#include <string.h>
#include "ha.h"
#include "xce/cluster_def.h"
ctrl_role_t am_i_primary_quorum(ha_state_t *ha, int n_peers,
xce_candidate_t **peers,
uint64_t my_config_tag, uint64_t my_lsn,
const char *my_name)
{
(void)peers; (void)my_name;
atomic_fetch_add_explicit(&ha->term, 1, memory_order_acq_rel);
if (n_peers == 1)
return CTRL_PRIMARY;
int n_other = n_peers - 1;
ha_elect_ctx_t *ctx = calloc(1, sizeof(*ctx) +
(size_t)n_other * sizeof(ctx->votes[0]));
if (!ctx)
return CTRL_STANDBY;
ctx->n_peers = n_other;
ctx->votes_granted = 1;
ctx->c = NULL;
if (n_other > 0) {
ctx->votes[0].my_tag = my_config_tag;
ctx->votes[0].my_lsn = my_lsn;
}
pthread_mutex_init(&ctx->lock, NULL);
sem_init(&ctx->done, 0, 0);
ctrl_role_t role = ha_elect_evaluate_and_signal(ha, ctx);
pthread_mutex_destroy(&ctx->lock);
sem_destroy(&ctx->done);
free(ctx);
return role;
}
#endif /* XCE_TESTING */