feat(raft-sim-conformance): raft_sim_check_all first-failure composition (task 3.5)

This commit is contained in:
Rongsong Shen 2026-06-24 13:00:10 +00:00
parent a38d9a7271
commit f0be46fb32
4 changed files with 171 additions and 1 deletions

View file

@ -833,6 +833,42 @@ int raft_sim_check_leader_completeness(const raft_sim_cluster_t *c);
*/
int raft_sim_check_state_machine_safety(const raft_sim_cluster_t *c);
/*
* raft_sim_invariant_t: identifier for the four Raft safety invariants checked by
* the conformance harness, in the FIXED evaluation order used by
* raft_sim_check_all (Req 3.5). RAFT_SIM_INV_NONE (0) means "all invariants hold".
* The ordinal order mirrors the requirements/design listing so the trace dumper
* (task 4.1) and scheduler (task 4.2) can report the failing invariant by name.
*/
typedef enum {
RAFT_SIM_INV_NONE = 0, /* all four invariants hold */
RAFT_SIM_INV_ELECTION_SAFETY, /* 1: raft_sim_check_election_safety */
RAFT_SIM_INV_LOG_MATCHING, /* 2: raft_sim_check_log_matching */
RAFT_SIM_INV_LEADER_COMPLETENESS, /* 3: raft_sim_check_leader_completeness */
RAFT_SIM_INV_STATE_MACHINE_SAFETY,/* 4: raft_sim_check_state_machine_safety */
} raft_sim_invariant_t;
/*
* raft_sim_check_all: evaluate the four Raft safety invariants over the cluster in
* the FIXED order (1) Election Safety, (2) Log Matching, (3) Leader Completeness,
* (4) State Machine Safety, and return the identifier of the FIRST one that is
* violated (Req 3.5 — "halt the run immediately and report the failing invariant").
*
* Short-circuits: once a checker reports a violation, later checkers are NOT
* evaluated, so the reported "first failing invariant" is deterministic. Returns
* RAFT_SIM_INV_NONE (0) when every invariant holds. Pure read-only over c (no I/O,
* no Unity assertions) so the lib stays test-framework-agnostic; the caller (trace
* dumper / scheduler) consumes the returned identity.
*/
raft_sim_invariant_t raft_sim_check_all(const raft_sim_cluster_t *c);
/*
* raft_sim_invariant_name: human-readable name for a raft_sim_invariant_t, for the
* trace dumper (task 4.1) and scheduler diagnostics. Returns a static string; never
* NULL (an out-of-range value maps to "unknown").
*/
const char *raft_sim_invariant_name(raft_sim_invariant_t inv);
/*
* raft_sim_advance_commit: drive raft_advance_commit on node_idx (task 6.1).
*

View file

@ -909,6 +909,34 @@ int raft_sim_check_state_machine_safety(const raft_sim_cluster_t *c)
return 1; /* holds */
}
raft_sim_invariant_t raft_sim_check_all(const raft_sim_cluster_t *c)
{
/* Evaluate the four invariants in the FIXED order required by Req 3.5 and
* short-circuit on the FIRST violation, so the reported failing invariant is
* deterministic. Each checker returns 1=holds / 0=violated. */
if (!raft_sim_check_election_safety(c))
return RAFT_SIM_INV_ELECTION_SAFETY;
if (!raft_sim_check_log_matching(c))
return RAFT_SIM_INV_LOG_MATCHING;
if (!raft_sim_check_leader_completeness(c))
return RAFT_SIM_INV_LEADER_COMPLETENESS;
if (!raft_sim_check_state_machine_safety(c))
return RAFT_SIM_INV_STATE_MACHINE_SAFETY;
return RAFT_SIM_INV_NONE; /* all four hold */
}
const char *raft_sim_invariant_name(raft_sim_invariant_t inv)
{
switch (inv) {
case RAFT_SIM_INV_NONE: return "none";
case RAFT_SIM_INV_ELECTION_SAFETY: return "election-safety";
case RAFT_SIM_INV_LOG_MATCHING: return "log-matching";
case RAFT_SIM_INV_LEADER_COMPLETENESS: return "leader-completeness";
case RAFT_SIM_INV_STATE_MACHINE_SAFETY: return "state-machine-safety";
}
return "unknown";
}
int raft_sim_restart_node(raft_sim_cluster_t *c, int node_idx)
{
if (node_idx < 0 || node_idx >= c->n)