114 lines
3.9 KiB
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 */
|