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:
parent
c1960457f8
commit
6110d12e5a
4 changed files with 217 additions and 46 deletions
|
|
@ -50,9 +50,12 @@
|
|||
* every other shape -- robust regardless of exactly how many ReplayEvent
|
||||
* pass-through messages land between sessions on either side.
|
||||
*
|
||||
* Comparator: reuses sim_verify.c's own leaf-level structural comparators
|
||||
* (sim_verify_job_alloc_eq()/sim_verify_job_preason_eq(), both `static` but
|
||||
* visible in this TU via the white-box #include below), the same technique
|
||||
* Comparator: uses the public libxce leaf-level structural comparators
|
||||
* (job_alloc_eq() from xcealloc.h, compares `from`; full-match
|
||||
* job_preason_eq() from preason.h -- valid because neither side runs with
|
||||
* the unsatisfiable-allocation cache), printing their first-difference
|
||||
* description on failure. The white-box #include of ../src/sim_verify.c
|
||||
* below stays for the decision-level functions sim_loop.c calls. Same technique
|
||||
* test_sim_equivalence.c's own replay_decision_content_eq() already
|
||||
* establishes -- duplicated here (this file family's own established
|
||||
* per-file-duplication convention; no shared test-utility header exists
|
||||
|
|
@ -119,7 +122,9 @@
|
|||
|
||||
#include "controller.capnp.h"
|
||||
#include "kvmgr.h"
|
||||
#include "preason.h"
|
||||
#include "scheduler.h"
|
||||
#include "xcealloc.h"
|
||||
#include "xstring.h"
|
||||
|
||||
/* Pull in the real functions under test into this TU (white-box #include,
|
||||
|
|
@ -712,37 +717,79 @@ static void free_all_sessions(replay_session_t** sessions, int count)
|
|||
* replay_decision_content_eq - structural equality between two DECODED
|
||||
* ReplayDecision entries (batch's vs the REPL's own, at the same session
|
||||
* and position). Same technique test_sim_equivalence.c's own function of
|
||||
* the same name establishes (delegating to sim_verify.c's leaf comparators,
|
||||
* the same name establishes (delegating to the public libxce comparators
|
||||
* job_alloc_eq()/job_preason_eq(), with an optional first-difference
|
||||
* description in *why that the caller prints and free()s;
|
||||
* duplicated here per this file family's own no-shared-header convention --
|
||||
* see this file's header comment).
|
||||
*/
|
||||
static int 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;
|
||||
}
|
||||
}
|
||||
|
|
@ -947,11 +994,19 @@ test_repl_step_continue_to_completion_matches_batch_decision_sequence(void)
|
|||
TEST_ASSERT_EQUAL_INT((int)ReplayDecision_body_pend,
|
||||
(int)rd->body_which);
|
||||
|
||||
TEST_ASSERT_TRUE_MESSAGE(
|
||||
replay_decision_content_eq(bd, rd),
|
||||
"REPL step/continue-to-completion must produce a "
|
||||
"byte-identical decision to batch mode at this session "
|
||||
"and position");
|
||||
{
|
||||
char* why = NULL;
|
||||
char msg[512];
|
||||
int eq = replay_decision_content_eq(bd, rd, &why);
|
||||
|
||||
snprintf(msg, sizeof(msg),
|
||||
"REPL step/continue-to-completion must produce a "
|
||||
"byte-identical decision to batch mode 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue