feat(libxce-alloc-preason-equality): white-box equivalence tests use public job_alloc_eq/job_preason_eq (task 4.1)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Rongsong Shen 2026-09-28 10:27:46 +00:00
parent c1960457f8
commit 6110d12e5a
Signed by untrusted user: rshen
GPG key ID: 80533536B0EB651C
4 changed files with 217 additions and 46 deletions

View file

@ -63,8 +63,10 @@
#include "controller.capnp.h"
#include "group.h"
#include "kvmgr.h"
#include "preason.h"
#include "scheduler.h"
#include "xce/types.h"
#include "xcealloc.h"
#include "xcelimit.h"
#include "xstring.h"
@ -2644,33 +2646,81 @@ static void det_free_all_sessions(replay_session_t** sessions, int count)
free(sessions);
}
/*
* det_replay_decision_content_eq - structural equality between two decoded
* ReplayDecision entries (baseline vs 'info limit' run), delegating the
* payload to the public libxce comparators job_alloc_eq() (xcealloc.h) and
* the full-match job_preason_eq() (preason.h). On mismatch, *why (when
* `why` is non-NULL) is a malloc'd first-difference description that the
* caller prints and free()s.
*/
static int det_replay_decision_content_eq(const replay_decision_t* a,
const replay_decision_t* b)
const replay_decision_t* b,
char** why)
{
char buf[128];
if (why != NULL) {
*why = NULL;
}
if ((a == NULL) || (b == NULL)) {
if (why != NULL) {
*why = strdup("decision: NULL argument");
}
return 0;
}
if (a->body_which != b->body_which) {
if (why != NULL) {
snprintf(buf, sizeof(buf), "body_which: %d != %d",
(int)a->body_which, (int)b->body_which);
*why = strdup(buf);
}
return 0;
}
switch (a->body_which) {
case ReplayDecision_body_dispatch:
if ((a->body.dispatch == NULL) || (b->body.dispatch == NULL)) {
if (why != NULL) {
*why = strdup("dispatch: NULL body");
}
return 0;
}
return sim_verify_job_alloc_eq(a->body.dispatch->alloc,
b->body.dispatch->alloc);
/* Public libxce comparator: compares `from` too (both sides stamp it
* from the deciding session's start), excludes only instid. */
return job_alloc_eq(a->body.dispatch->alloc,
b->body.dispatch->alloc, why);
case ReplayDecision_body_pend:
if ((a->body.pend == NULL) || (b->body.pend == NULL)) {
if (why != NULL) {
*why = strdup("pend: NULL body");
}
return 0;
}
return (a->body.pend->jobid == b->body.pend->jobid)
&& sim_verify_job_preason_eq(a->body.pend->reason,
b->body.pend->reason);
if (a->body.pend->jobid != b->body.pend->jobid) {
if (why != NULL) {
snprintf(buf, sizeof(buf), "pend.jobid: %llu != %llu",
(unsigned long long)a->body.pend->jobid,
(unsigned long long)b->body.pend->jobid);
*why = strdup(buf);
}
return 0;
}
/* Full match (main reason + host- and resource-based detail lists)
* is valid here, unlike --sim-verify's main-reason-only PEND check
* (bug-1845): this test registers no unsatisfiable_lookup_cb, so
* neither side has the unsatisfiable-allocation cache and both build
* the detail lists with the same full per-host computation. */
return job_preason_eq(a->body.pend->reason,
b->body.pend->reason, why);
default:
if (why != NULL) {
snprintf(buf, sizeof(buf), "body_which: unsupported %d",
(int)a->body_which);
*why = strdup(buf);
}
return 0;
}
}
@ -2875,11 +2925,20 @@ test_repl_step_continue_with_info_limit_interleaved_matches_baseline_decision_se
TEST_ASSERT_EQUAL_INT((int)ReplayDecision_body_pend,
(int)id->body_which);
TEST_ASSERT_TRUE_MESSAGE(
det_replay_decision_content_eq(bd, id),
"Requirement 5.2: 'info limit' issued mid-session must "
"produce a byte-identical decision to the baseline at this "
"session and position");
{
char* why = NULL;
char msg[512];
int eq = det_replay_decision_content_eq(bd, id, &why);
snprintf(msg, sizeof(msg),
"Requirement 5.2: 'info limit' issued mid-session "
"must produce a byte-identical decision to the "
"baseline at this session and position (session "
"%d, decision %d): %s",
i, j, (why != NULL) ? why : "(no description)");
free(why);
TEST_ASSERT_TRUE_MESSAGE(eq, msg);
}
}
}