Only 21 of 86 test_*.c group functions called their own nested UNITY_BEGIN()/UNITY_END(). Each nested call reset Unity's global NumberOfTests/TestFailures counters, so controller_test.c's final `return UNITY_END();` -- the value meson test actually gates on -- only ever reflected whichever small window of tests ran since the LAST nested reset, silently discarding pass/fail evidence for everything before it (measured: 16 of 972 total tests in one run). The same nested-BEGIN calls also caused PASS/FAIL banners to show the wrong source file for tests in files that don't reset it themselves (Unity.TestFile just carries over from whichever group last called UNITY_BEGIN()). Fix: replace every nested UNITY_BEGIN() with UnitySetTestFile(__FILE__) (sets file attribution only, no counter reset) and drop the matching UNITY_END(); add the same UnitySetTestFile(__FILE__) as the first statement to the other group functions that had neither. The 2 genuinely standalone binaries (test_job_array_sched_push.c, test_job_array_apiserver_push.c -- each has its own int main(), not registered via controller_test.c's TEST() macro) are untouched. Verified: single consolidated summary now reads "972 Tests 0 Failures 0 Ignored OK", exactly matching the ground-truth RUN_TEST call-site count across all 83 registered group files (976 total minus 4 belonging to the 2 standalone binaries). Every PASS/FAIL banner now names its own true source file. Full xce-build.sh all regression pass clean (Ok: 9, Fail: 0). No production code touched -- test-harness plumbing only.
135 lines
4.1 KiB
C
135 lines
4.1 KiB
C
/*
|
|
* test_repl_catchup.c — P2-5: standby catch-up state machine tests.
|
|
* Tests repl_start_catchup, repl_complete_catchup, repl_needs_snapshot.
|
|
* No live network I/O — pure state machine logic.
|
|
*/
|
|
#include <errno.h>
|
|
#include <stdatomic.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#include <unity/unity.h>
|
|
|
|
#include "config.h"
|
|
#include "repl.h"
|
|
|
|
static void test_start_catchup_sets_in_catch_up(void)
|
|
{
|
|
replicator_t r;
|
|
int ep = 0;
|
|
repl_init(&r);
|
|
repl_add_standby(&r, (void *)&ep, "sb", 7001);
|
|
|
|
repl_start_catchup(&r, (void *)&ep, /*join_applied_lsn=*/5);
|
|
|
|
/* in_catch_up must be set */
|
|
TEST_ASSERT_EQUAL_INT(
|
|
1,
|
|
(int)atomic_load_explicit(&r.standbys[0].in_catch_up,
|
|
memory_order_acquire));
|
|
/* join_applied_lsn must be stored */
|
|
TEST_ASSERT_EQUAL_UINT64(5, r.standbys[0].join_applied_lsn);
|
|
|
|
repl_fini(&r);
|
|
printf("test_start_catchup_sets_in_catch_up: PASS\n");
|
|
}
|
|
|
|
static void test_complete_catchup_clears_in_catch_up(void)
|
|
{
|
|
replicator_t r;
|
|
int ep = 0;
|
|
repl_init(&r);
|
|
repl_add_standby(&r, (void *)&ep, "sb", 7001);
|
|
repl_start_catchup(&r, (void *)&ep, 5);
|
|
|
|
repl_complete_catchup(&r, (void *)&ep);
|
|
|
|
TEST_ASSERT_EQUAL_INT(
|
|
0,
|
|
(int)atomic_load_explicit(&r.standbys[0].in_catch_up,
|
|
memory_order_acquire));
|
|
|
|
repl_fini(&r);
|
|
printf("test_complete_catchup_clears_in_catch_up: PASS\n");
|
|
}
|
|
|
|
static void test_wait_ack_excludes_catching_up_standby(void)
|
|
{
|
|
replicator_t r;
|
|
int ep = 0;
|
|
repl_init(&r);
|
|
repl_add_standby(&r, (void *)&ep, "sb", 7001);
|
|
repl_start_catchup(&r, (void *)&ep, 5); /* mark as catching up */
|
|
|
|
/* repl_wait_ack must return -ENODEV (no non-catching-up standbys) */
|
|
int rc = repl_wait_ack(&r, 10, 50);
|
|
TEST_ASSERT_EQUAL_INT(-ENODEV, rc);
|
|
|
|
repl_fini(&r);
|
|
printf("test_wait_ack_excludes_catching_up_standby: PASS\n");
|
|
}
|
|
|
|
static void test_complete_catchup_allows_ack(void)
|
|
{
|
|
replicator_t r;
|
|
int ep = 0;
|
|
repl_init(&r);
|
|
repl_add_standby(&r, (void *)&ep, "sb", 7001);
|
|
repl_start_catchup(&r, (void *)&ep, 5);
|
|
repl_complete_catchup(&r, (void *)&ep);
|
|
|
|
/* After catch-up completes, the standby's ACK must count */
|
|
repl_on_ack(&r, (void *)&ep, 20);
|
|
int rc = repl_wait_ack(&r, 10, 50);
|
|
TEST_ASSERT_EQUAL_INT(0, rc);
|
|
|
|
repl_fini(&r);
|
|
printf("test_complete_catchup_allows_ack: PASS\n");
|
|
}
|
|
|
|
static void test_repl_needs_snapshot_no_wal(void)
|
|
{
|
|
/* When standby LSN is 0 and no WAL exists, needs_snapshot returns 0
|
|
* (empty state = fresh standby, can start from empty — no snapshot needed) */
|
|
replicator_t r;
|
|
repl_init(&r);
|
|
int needs = repl_needs_snapshot(&r, /*standby_lsn=*/0, /*oldest_wal_lsn=*/0);
|
|
TEST_ASSERT_EQUAL_INT(0, needs);
|
|
repl_fini(&r);
|
|
printf("test_repl_needs_snapshot_no_wal: PASS\n");
|
|
}
|
|
|
|
static void test_repl_needs_snapshot_standby_behind_wal(void)
|
|
{
|
|
/* Standby LSN 5, oldest WAL segment starts at LSN 10 — snapshot required */
|
|
replicator_t r;
|
|
repl_init(&r);
|
|
int needs = repl_needs_snapshot(&r, /*standby_lsn=*/5, /*oldest_wal_lsn=*/10);
|
|
TEST_ASSERT_EQUAL_INT(1, needs);
|
|
repl_fini(&r);
|
|
printf("test_repl_needs_snapshot_standby_behind_wal: PASS\n");
|
|
}
|
|
|
|
static void test_repl_needs_snapshot_standby_within_wal(void)
|
|
{
|
|
/* Standby LSN 15, oldest WAL starts at LSN 10 — WAL replay sufficient */
|
|
replicator_t r;
|
|
repl_init(&r);
|
|
int needs = repl_needs_snapshot(&r, /*standby_lsn=*/15, /*oldest_wal_lsn=*/10);
|
|
TEST_ASSERT_EQUAL_INT(0, needs);
|
|
repl_fini(&r);
|
|
printf("test_repl_needs_snapshot_standby_within_wal: PASS\n");
|
|
}
|
|
|
|
void test_repl_catchup(void)
|
|
{
|
|
UnitySetTestFile(__FILE__);
|
|
RUN_TEST(test_start_catchup_sets_in_catch_up);
|
|
RUN_TEST(test_complete_catchup_clears_in_catch_up);
|
|
RUN_TEST(test_wait_ack_excludes_catching_up_standby);
|
|
RUN_TEST(test_complete_catchup_allows_ack);
|
|
RUN_TEST(test_repl_needs_snapshot_no_wal);
|
|
RUN_TEST(test_repl_needs_snapshot_standby_behind_wal);
|
|
RUN_TEST(test_repl_needs_snapshot_standby_within_wal);
|
|
}
|