forked from lei.chen/myxce
test(raft-sim-conformance): randomized M-seed sweep + all scenarios, zero violations (task 6.1)
This commit is contained in:
parent
a2933c274d
commit
47f68032b7
2 changed files with 102 additions and 1 deletions
|
|
@ -168,7 +168,7 @@
|
|||
|
||||
## 6. CI batch and randomized seed sweep
|
||||
|
||||
- [ ] 6.1 RED+GREEN: randomized M-seed sweep with zero violations
|
||||
- [x] 6.1 RED+GREEN: randomized M-seed sweep with zero violations
|
||||
- Test: run `raft_sim_run` for a fixed `max_steps` across M seeds (M ≥ configured minimum) plus all targeted scenarios; fail if any seed/scenario violates any invariant
|
||||
- Implement the sweep harness in `test_raft.c`; bound `max_steps`, M, and array sizes so the target fits the library test-suite budget
|
||||
- Observable completion: the full batch runs clean and within budget
|
||||
|
|
|
|||
|
|
@ -8526,6 +8526,106 @@ static void test_sim_5_5_stale_rejoin(void)
|
|||
"post-stale-rejoin cluster reports more than one leader (Election Safety)");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* test_sim_6_1_seed_sweep (raft-sim-conformance task 6.1; Req 6.1, 6.2, 6.4)
|
||||
*
|
||||
* CI conformance batch: run the randomized action scheduler (raft_sim_run) across a
|
||||
* configured minimum of seeds for several cluster sizes, then run ALL FIVE targeted
|
||||
* scenarios across a handful of seeds each — asserting ZERO invariant violations
|
||||
* anywhere (R6.2).
|
||||
*
|
||||
* raft_sim_run drives raft_sim_step up to RAFT_SIM_SWEEP_STEPS actions, halting and
|
||||
* returning < 0 on the FIRST invariant violation (the step already dumps the
|
||||
* replayable trace to stderr) and returning 0 on a clean run. The library is correct
|
||||
* (bug-1095/1096 fixed), so the entire batch MUST be clean: any rc < 0 here is a REAL
|
||||
* divergence — NOT something to mask by shrinking M or skipping the offending seed.
|
||||
* The failure message names the exact (seed, n) so the failing run is reproducible
|
||||
* (R5/6.2): re-run raft_sim_conformance_init(&c, n, 2000, seed) + raft_sim_run.
|
||||
*
|
||||
* Bounds (R6.4): RAFT_SIM_SWEEP_M seeds (the configured minimum) over a small set of
|
||||
* cluster sizes, each capped at RAFT_SIM_SWEEP_STEPS steps; the harness is fixed-array
|
||||
* (no allocation) so the whole batch stays within the lib test-suite time budget.
|
||||
*/
|
||||
#define RAFT_SIM_SWEEP_M 32 /* configured minimum number of randomized seeds (R6.2) */
|
||||
#define RAFT_SIM_SWEEP_STEPS 400 /* per-run step cap — bounded for the suite budget (R6.4) */
|
||||
|
||||
static void test_sim_6_1_seed_sweep(void)
|
||||
{
|
||||
/* Cluster sizes swept for the randomized batch. Raft rejects even peer counts
|
||||
* (no quorum benefit, raft_init -EINVAL), so only ODD sizes <= RAFT_SIM_MAX_NODES. */
|
||||
static const int sizes[] = { 3, 5, 7 };
|
||||
const int election_timeout = 2000;
|
||||
|
||||
/* --- Randomized seed sweep: M >= configured minimum seeds x each cluster size --- */
|
||||
for (int s = 0; s < RAFT_SIM_SWEEP_M; s++) {
|
||||
/* Deterministic, well-spread seeds derived from the index s (documented):
|
||||
* a large odd multiplier + offset so consecutive seeds differ in many bits. */
|
||||
uint64_t seed = (uint64_t)s * 0x9E3779B97F4A7C15ULL + 0xD1B54A32D192ED03ULL;
|
||||
|
||||
for (size_t z = 0; z < sizeof(sizes) / sizeof(sizes[0]); z++) {
|
||||
int n = sizes[z];
|
||||
|
||||
raft_sim_cluster_t c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(0,
|
||||
raft_sim_conformance_init(&c, n, election_timeout, seed));
|
||||
|
||||
int rc = raft_sim_run(&c, RAFT_SIM_SWEEP_STEPS);
|
||||
|
||||
/* Zero violations through the whole run. On failure, name (seed, n) so the
|
||||
* run is reproducible — the step already dumped the replayable trace. */
|
||||
if (rc != 0) {
|
||||
char msg[160];
|
||||
snprintf(msg, sizeof(msg),
|
||||
"seed sweep surfaced invariant violation rc=%d at seed=%llu n=%d "
|
||||
"(reproduce: raft_sim_conformance_init(&c,%d,%d,%lluULL); "
|
||||
"raft_sim_run(&c,%d))",
|
||||
rc, (unsigned long long)seed, n,
|
||||
n, election_timeout, (unsigned long long)seed, RAFT_SIM_SWEEP_STEPS);
|
||||
TEST_FAIL_MESSAGE(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* --- All five targeted scenarios over a handful of seeds each (R6.2). Each
|
||||
* scenario inits the caller's cluster internally from (n, seed) and returns 0 on
|
||||
* zero violations, < 0 (dumping its trace) on any violation. --- */
|
||||
static const uint64_t scen_seeds[] = { 1ULL, 3ULL, 7ULL, 0x4A33ULL, 0xBEEFULL };
|
||||
|
||||
for (size_t k = 0; k < sizeof(scen_seeds) / sizeof(scen_seeds[0]); k++) {
|
||||
uint64_t seed = scen_seeds[k];
|
||||
|
||||
/* n chosen per seed index, alternating 3- and 5-node clusters. */
|
||||
int n = (k % 2 == 0) ? 3 : 5;
|
||||
|
||||
struct { const char *name; int (*fn)(raft_sim_cluster_t *, int, uint64_t); } scenarios[] = {
|
||||
{ "partition_heal", raft_sim_scenario_partition_heal },
|
||||
{ "restart_churn", raft_sim_scenario_restart_churn },
|
||||
{ "drop_dup_reorder",raft_sim_scenario_drop_dup_reorder},
|
||||
{ "figure8", raft_sim_scenario_figure8 },
|
||||
{ "stale_rejoin", raft_sim_scenario_stale_rejoin },
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < sizeof(scenarios) / sizeof(scenarios[0]); i++) {
|
||||
raft_sim_cluster_t c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
|
||||
int rc = scenarios[i].fn(&c, n, seed);
|
||||
|
||||
if (rc != 0) {
|
||||
char msg[192];
|
||||
snprintf(msg, sizeof(msg),
|
||||
"scenario '%s' surfaced violation rc=%d at seed=%lluULL n=%d "
|
||||
"(reproduce: raft_sim_scenario_%s(&c,%d,%lluULL))",
|
||||
scenarios[i].name, rc, (unsigned long long)seed, n,
|
||||
scenarios[i].name, n, (unsigned long long)seed);
|
||||
TEST_FAIL_MESSAGE(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* XCE_TESTING */
|
||||
|
||||
/* ---------- test_raft entry point ---------- */
|
||||
|
|
@ -8741,6 +8841,7 @@ void test_raft(void)
|
|||
RUN_TEST(test_sim_5_3_drop_dup_reorder);
|
||||
RUN_TEST(test_sim_5_4_figure8);
|
||||
RUN_TEST(test_sim_5_5_stale_rejoin);
|
||||
RUN_TEST(test_sim_6_1_seed_sweep);
|
||||
|
||||
/* Group A: basic election correctness (task 5.1) */
|
||||
RUN_TEST(test_proto_A1_single_node_self_elects);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue