feat(raft-sim-conformance): optional TLC-consumable trace export, default-off (task 8.1)
This commit is contained in:
parent
ffeb7c2cf5
commit
95629797f8
4 changed files with 242 additions and 1 deletions
|
|
@ -5362,6 +5362,98 @@ static void test_sim_4_1_trace_record_and_dump(void)
|
|||
setenv("RAFT_SIM_VERBOSE", saved_copy, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* test_sim_8_1_export_trace_named_and_gated (raft-sim-conformance task 8.1;
|
||||
* Req 8.1, 8.2, 8.3)
|
||||
*
|
||||
* raft_sim_export_trace emits a STABLE, line-oriented, machine-readable record of
|
||||
* the harness's tracked raft.tla variables, gated OFF by default via the
|
||||
* RAFT_SIM_EXPORT environment variable (mirroring the RAFT_SIM_VERBOSE idiom):
|
||||
* - Export ON (RAFT_SIM_EXPORT set): a post-run cluster's export CONTAINS the
|
||||
* spec-named tokens (currentTerm, state, log, commitIndex, messages — R8.2),
|
||||
* the seed/n header, and at least one action name from the recorded trace
|
||||
* (R8.1). Two exports of the same post-run state are byte-identical (stable).
|
||||
* - Default OFF (RAFT_SIM_EXPORT unset): the export emits NOTHING (R8.3).
|
||||
* The env var is saved and restored around the test so the rest of the suite is
|
||||
* unperturbed.
|
||||
*/
|
||||
static void test_sim_8_1_export_trace_named_and_gated(void)
|
||||
{
|
||||
/* Save + clear the gate so we control it deterministically. */
|
||||
char *saved_export = getenv("RAFT_SIM_EXPORT");
|
||||
char saved_copy[256];
|
||||
int had_export = (saved_export != NULL);
|
||||
if (had_export) {
|
||||
strncpy(saved_copy, saved_export, sizeof(saved_copy) - 1);
|
||||
saved_copy[sizeof(saved_copy) - 1] = '\0';
|
||||
}
|
||||
|
||||
/* Drive a short deterministic run so trace[] holds actions and nodes carry
|
||||
* observable state (term/log/commit). Seed 3 is the one the 4.2 test proves
|
||||
* completes a clean run on the correct library. */
|
||||
raft_sim_cluster_t c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
TEST_ASSERT_EQUAL_INT(0, raft_sim_conformance_init(&c, 3, 2000, 3ULL));
|
||||
for (int step = 0; step < 80; step++) {
|
||||
int rc = raft_sim_step(&c);
|
||||
TEST_ASSERT_TRUE(rc >= 0);
|
||||
}
|
||||
TEST_ASSERT_TRUE(c.trace_len > 0); /* the run recorded actions to export */
|
||||
|
||||
/* ---- Export ON (R8.1, R8.2) ---- */
|
||||
setenv("RAFT_SIM_EXPORT", "1", 1);
|
||||
|
||||
char buf[8192];
|
||||
memset(buf, 0, sizeof(buf));
|
||||
FILE *fp = fmemopen(buf, sizeof(buf), "w");
|
||||
TEST_ASSERT_NOT_NULL(fp);
|
||||
raft_sim_export_trace(&c, fp);
|
||||
fclose(fp);
|
||||
|
||||
TEST_ASSERT_TRUE(strlen(buf) > 0);
|
||||
/* raft.tla-named tracked variables (R8.2). */
|
||||
TEST_ASSERT_NOT_NULL(strstr(buf, "currentTerm"));
|
||||
TEST_ASSERT_NOT_NULL(strstr(buf, "state"));
|
||||
TEST_ASSERT_NOT_NULL(strstr(buf, "log"));
|
||||
TEST_ASSERT_NOT_NULL(strstr(buf, "commitIndex"));
|
||||
TEST_ASSERT_NOT_NULL(strstr(buf, "messages"));
|
||||
/* seed/n header (R8.1). */
|
||||
{
|
||||
char seedtok[32];
|
||||
snprintf(seedtok, sizeof(seedtok), "%llu", (unsigned long long)c.seed);
|
||||
TEST_ASSERT_NOT_NULL(strstr(buf, seedtok));
|
||||
TEST_ASSERT_NOT_NULL(strstr(buf, "seed"));
|
||||
TEST_ASSERT_NOT_NULL(strstr(buf, "n="));
|
||||
}
|
||||
/* At least one raft.tla Next action name appears (R8.1/R8.2). The scheduler
|
||||
* always drives Timeout, so it is reliably present. */
|
||||
TEST_ASSERT_NOT_NULL(strstr(buf, "Timeout"));
|
||||
|
||||
/* Stability: a second export of the same post-run state is byte-identical. */
|
||||
char buf2[8192];
|
||||
memset(buf2, 0, sizeof(buf2));
|
||||
FILE *fp2 = fmemopen(buf2, sizeof(buf2), "w");
|
||||
TEST_ASSERT_NOT_NULL(fp2);
|
||||
raft_sim_export_trace(&c, fp2);
|
||||
fclose(fp2);
|
||||
TEST_ASSERT_EQUAL_INT(0, strcmp(buf, buf2)); /* deterministic / stable */
|
||||
|
||||
/* ---- Default OFF (R8.3): gate unset => emit NOTHING ---- */
|
||||
unsetenv("RAFT_SIM_EXPORT");
|
||||
char qbuf[256];
|
||||
memset(qbuf, 0, sizeof(qbuf));
|
||||
FILE *qfp = fmemopen(qbuf, sizeof(qbuf), "w");
|
||||
TEST_ASSERT_NOT_NULL(qfp);
|
||||
raft_sim_export_trace(&c, qfp);
|
||||
fclose(qfp);
|
||||
TEST_ASSERT_EQUAL_INT(0, (int)strlen(qbuf)); /* silent unless explicitly enabled */
|
||||
|
||||
if (had_export)
|
||||
setenv("RAFT_SIM_EXPORT", saved_copy, 1);
|
||||
else
|
||||
unsetenv("RAFT_SIM_EXPORT");
|
||||
}
|
||||
|
||||
/* ---------- Group A: Basic Election Correctness (task 5.1) ---------- */
|
||||
|
||||
/*
|
||||
|
|
@ -9020,6 +9112,7 @@ void test_raft(void)
|
|||
RUN_TEST(test_sim_2_2_drop_duplicate_preserve_node_state);
|
||||
RUN_TEST(test_sim_2_2_reorder_prng_deterministic);
|
||||
RUN_TEST(test_sim_4_1_trace_record_and_dump);
|
||||
RUN_TEST(test_sim_8_1_export_trace_named_and_gated);
|
||||
RUN_TEST(test_sim_4_2_step_liveness_and_coverage);
|
||||
RUN_TEST(test_sim_4_2_step_halts_on_forced_violation);
|
||||
RUN_TEST(test_sim_4_3_restart_preserves_persistence);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue