test(scheduler-snapshot-job-allocation): close originally-reported symptom end to end
Task 4.2: extend test_e2e_original_motivation_long_replay with PREEXIST_ID (job 70013, dedicated worker worker-e2e-pre) -- a job submitted, live-dispatched, and confirmed RUN entirely before sched_record_start(), so its dispatch decision can never appear in the replay stream. Proves its "used=9.00" resource contribution is correct starting from the very first replayed round, recoverable only via snapshot-load allocation restoration (tasks 2.1/2.2), not replay-based reconciliation -- the complementary case to the file's existing ANCHOR_ID scenario. Completes and fixes a pre-existing uncommitted WIP addendum to this file: removed a redundant enqueue_queue_update() call that was masking a genuine, unrelated latent bug in core_upsert_queue() (rtti makeString() pointer freed via plain free(), same class as bug-1503/bug-1600) -- noted in tasks.md's Implementation Notes as a follow-up, not fixed here (test-only task boundary). Verified via fault injection: gating snapshot_load.c's allocation restore reproduces the exact pre-fix failure at this test's new assertion, then cleanly reverts. Requirements: 1.1, 1.2, 1.3 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BSiC2cPVH2VSBdtFq4P4ju
This commit is contained in:
parent
de6ad514e0
commit
2654e03f2b
2 changed files with 327 additions and 6 deletions
|
|
@ -120,6 +120,43 @@
|
|||
* check/accounting primitives). Links a REAL (not no-op) sched_account_jobs()
|
||||
* reimplementation, copied verbatim from scheduler.c (task 1.1's relocated
|
||||
* signature) -- same rationale those two files' own header comments give.
|
||||
*
|
||||
* ============================================================================
|
||||
* ADDENDUM (scheduler-snapshot-job-allocation spec, task 4.2): PREEXIST_ID
|
||||
* ============================================================================
|
||||
* Everything above this addendum predates and is unchanged by this task.
|
||||
* Task 4.2's own Observable Completion ("100% of the saved running jobs'
|
||||
* resource contribution accounted for immediately on load") is NOT proven
|
||||
* by ANCHOR_ID above: ANCHOR_ID's accounting is recovered by replay-based
|
||||
* reconciliation (sim_reconcile_unaccounted_jobs(), a DIFFERENT, already-
|
||||
* shipped mechanism from a prior spec) matching its DISPATCH decision
|
||||
* against round 1's own decoded ReplaySession -- i.e. its correctness
|
||||
* depends on a dispatch decision that DOES appear somewhere in the replay
|
||||
* stream. This spec (scheduler-snapshot-job-allocation) closes the
|
||||
* COMPLEMENTARY case: a job whose dispatch predates the snapshot entirely
|
||||
* and can NEVER appear in the subsequent replay stream, recoverable only
|
||||
* via xce_sched_core_load_snapshot()'s own allocation restoration (task
|
||||
* 2.1's build_wire_job() save-side wiring + task 2.2's dup_job_alloc()/
|
||||
* make_job_account() load-side wiring).
|
||||
*
|
||||
* PREEXIST_ID (job 70013, worker "worker-e2e-pre", a dedicated worker
|
||||
* isolated from worker-e2e's carefully-derived R2-R24 capacity arithmetic
|
||||
* above) is constructed to be exactly that case: submitted, live-dispatched
|
||||
* (a completely ordinary, unrigged sched_check_host_satisfy()-gated
|
||||
* dispatch -- see preexist_prelude_allocator_thread_fn below), and
|
||||
* confirmed RUN, ALL strictly before sched_record_start() is ever called.
|
||||
* Its dispatch decision is therefore never written to the .replay file at
|
||||
* all -- sched_record_start()'s own initial SnapshotEntry (recording.c's
|
||||
* write_snapshot_entry()) is the ONLY place its allocation is ever
|
||||
* captured, and xce_sched_core_load_snapshot() (sim.c's
|
||||
* sim_locate_and_load_snapshot(), called before round 1 ever runs) is the
|
||||
* ONLY place it is ever restored. The test asserts PREEXIST_ID's "used"
|
||||
* value is already correct after just ONE replayed round (the earliest
|
||||
* possible observation point, strictly before ANCHOR_ID's own first
|
||||
* checkpoint) and stays correct through all 24, while its own DISPATCH
|
||||
* decision is proven to NEVER appear anywhere in the captured replay
|
||||
* output -- the concrete, falsifiable difference from ANCHOR_ID's
|
||||
* reconciliation-based mechanism.
|
||||
*/
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
|
|
@ -311,6 +348,15 @@ void tearDown(void) { return; }
|
|||
#define WORKER_NAME "worker-e2e"
|
||||
#define WORKER_CAPACITY 20.0f
|
||||
|
||||
/* scheduler-snapshot-job-allocation task 4.2: PREEXIST_ID's own dedicated
|
||||
* worker, isolated from worker-e2e's R2-R24 capacity arithmetic above --
|
||||
* see this file's ADDENDUM header comment. */
|
||||
#define WORKER2_NAME "worker-e2e-pre"
|
||||
#define WORKER2_CAPACITY 15.0f
|
||||
|
||||
#define PREEXIST_ID 70013ULL
|
||||
#define PREEXIST_WANT 9.0f
|
||||
|
||||
#define ANCHOR_ID 70001ULL
|
||||
#define ANCHOR_WANT 12.0f
|
||||
#define J2_ID 70002ULL
|
||||
|
|
@ -433,6 +479,31 @@ static void fixture_init(xce_scheduler_t* sched, char* record_dir)
|
|||
|
||||
rc = sched_add_worker(&(sched->core), w);
|
||||
TEST_ASSERT_TRUE(rc >= 0);
|
||||
|
||||
/* scheduler-snapshot-job-allocation task 4.2: PREEXIST_ID's own
|
||||
* dedicated worker (see this file's ADDENDUM header comment) --
|
||||
* isolated from worker-e2e's own carefully-derived R2-R24 capacity
|
||||
* arithmetic above so this task's addition cannot perturb it. */
|
||||
{
|
||||
xce_sched_worker_t* w2;
|
||||
|
||||
w2 = (xce_sched_worker_t*)calloc(1, sizeof(*w2));
|
||||
TEST_ASSERT_NOT_NULL(w2);
|
||||
w2->name = strdup(WORKER2_NAME);
|
||||
TEST_ASSERT_NOT_NULL(w2->name);
|
||||
|
||||
rc = zarray_init(&(w2->resvals), 8, NULL);
|
||||
TEST_ASSERT_EQUAL_INT(0, rc);
|
||||
rc = zarray_init(&(w2->resInUse), 8, NULL);
|
||||
TEST_ASSERT_EQUAL_INT(0, rc);
|
||||
|
||||
val[0] = WORKER2_CAPACITY;
|
||||
rc = put_resvals(&(w2->resvals), 1, &g_slots_residx, val);
|
||||
TEST_ASSERT_TRUE(rc >= 0);
|
||||
|
||||
rc = sched_add_worker(&(sched->core), w2);
|
||||
TEST_ASSERT_TRUE(rc >= 0);
|
||||
}
|
||||
}
|
||||
|
||||
static xce_queue_t* make_queue(const char* name, int32_t priority)
|
||||
|
|
@ -710,6 +781,99 @@ static xce_decision_t* decide_one_candidate(xce_scheduler_t* sched,
|
|||
return decision;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/* Prelude allocator (scheduler-snapshot-job-allocation task 4.2, see this */
|
||||
/* file's ADDENDUM header comment): dispatches PREEXIST_ID onto its own */
|
||||
/* dedicated worker (WORKER2_NAME) via the exact same real */
|
||||
/* sched_check_host_satisfy()/sched_charge_account()/sched_commit_job_ */
|
||||
/* alloc()/make_dispatch_decision() round trip decide_one_candidate() */
|
||||
/* above already uses -- a completely ordinary, unrigged live dispatch, no */
|
||||
/* special-casing at all (unlike ANCHOR_ID's necessarily-rigged injection */
|
||||
/* in round1_allocator_thread_fn below, which exists only because ANCHOR_ */
|
||||
/* ID must be simultaneously RUN and carry a same-round DISPATCH decision, */
|
||||
/* a shape no live picker/allocator can ever itself produce). This is a */
|
||||
/* deliberately SEPARATE helper from decide_one_candidate() (which */
|
||||
/* hardcodes WORKER_NAME) rather than a generalization of it, so this */
|
||||
/* task's addition cannot perturb that already-validated function's */
|
||||
/* behavior for ANCHOR_ID/J2-J12. Runs strictly BEFORE sched_record_start */
|
||||
/* () (see the Prelude section of the test body below), so this dispatch */
|
||||
/* decision is never written to the .replay file at all. */
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
static void* preexist_prelude_allocator_thread_fn(void* arg)
|
||||
{
|
||||
xce_scheduler_t* sched = (xce_scheduler_t*)arg;
|
||||
xce_sched_core_t* core = &(sched->core);
|
||||
xce_sched_plugin_t* picker = NULL;
|
||||
uint64_t jobid;
|
||||
|
||||
if (sched_resolve_job_picker(core, &picker) < 0) {
|
||||
xce_decision_t* decision = NULL;
|
||||
|
||||
cbuf_get(&(core->jbuf), &jobid);
|
||||
cbuf_put(&(core->decisions), &decision);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
xce_decision_t* decision;
|
||||
xce_sched_job_t* job;
|
||||
xce_sched_worker_t* w2;
|
||||
xvec_t uncomitted;
|
||||
xvec_idval_t wanted;
|
||||
xvec_idval_t unmeet;
|
||||
int rc;
|
||||
|
||||
cbuf_get(&(core->jbuf), &jobid);
|
||||
if (jobid == 0) {
|
||||
decision = NULL;
|
||||
cbuf_put(&(core->decisions), &decision);
|
||||
break;
|
||||
}
|
||||
|
||||
TEST_ASSERT_EQUAL_UINT64_MESSAGE(
|
||||
PREEXIST_ID, jobid,
|
||||
"the prelude round must only ever present PREEXIST_ID as a "
|
||||
"candidate -- nothing else has been pushed to the core yet at "
|
||||
"this point");
|
||||
|
||||
job = sched_get_job(core, jobid);
|
||||
w2 = sched_get_worker(core, (char*)WORKER2_NAME);
|
||||
TEST_ASSERT_NOT_NULL(job);
|
||||
TEST_ASSERT_NOT_NULL(w2);
|
||||
|
||||
rc = xvec_init(&uncomitted, 1, sizeof(float));
|
||||
TEST_ASSERT_TRUE(rc >= 0);
|
||||
rc = xvec_idval_init(&wanted, 1);
|
||||
TEST_ASSERT_EQUAL_INT(0, rc);
|
||||
rc = xvec_idval_store(&wanted, g_slots_residx, PREEXIST_WANT);
|
||||
TEST_ASSERT_TRUE(rc >= 0);
|
||||
|
||||
rc = sched_check_host_satisfy(sched, w2, &uncomitted, &wanted, &unmeet);
|
||||
|
||||
xvec_fini(&uncomitted);
|
||||
xvec_idval_fini(&wanted);
|
||||
xvec_idval_fini(&unmeet);
|
||||
|
||||
TEST_ASSERT_EQUAL_INT_MESSAGE(
|
||||
1, rc,
|
||||
"PREEXIST_ID's own dedicated worker must have ample capacity -- "
|
||||
"this is a genuine, unrigged live dispatch, not an engineered "
|
||||
"coincidence like ANCHOR_ID's");
|
||||
|
||||
job->accounts
|
||||
= make_charge_account(WORKER2_NAME, PREEXIST_WANT, g_slots_residx);
|
||||
sched_commit_job_alloc(core, job);
|
||||
job->allocs = make_dispatch_alloc(jobid, WORKER2_NAME, PREEXIST_WANT);
|
||||
|
||||
picker->picker_iface->on_dispatch(picker, jobid);
|
||||
decision = make_dispatch_decision(job->allocs);
|
||||
cbuf_put(&(core->decisions), &decision);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/* Round 1's allocator: injects ANCHOR_ID's own already-resolved DISPATCH */
|
||||
/* (see this file's header comment for the full reasoning), THEN */
|
||||
|
|
@ -1017,6 +1181,7 @@ static void test_e2e_original_motivation_long_replay(void)
|
|||
char capture_path[PATH_MAX];
|
||||
xce_job_t** anchor_jobs;
|
||||
xce_job_t** j2_jobs;
|
||||
xce_job_t** preexist_jobs;
|
||||
uint64_t sub_time;
|
||||
int rc;
|
||||
int i;
|
||||
|
|
@ -1029,20 +1194,88 @@ static void test_e2e_original_motivation_long_replay(void)
|
|||
char* p2;
|
||||
char* p3;
|
||||
char* p4;
|
||||
char preexist_jobid_str[64];
|
||||
char preexist_marker[96];
|
||||
char* q1;
|
||||
char* q2;
|
||||
char* q3;
|
||||
char* q4;
|
||||
char* q5;
|
||||
|
||||
/* ==== Build the recording: a real, driven 24-round session ==== */
|
||||
|
||||
make_tmp_dir(record_dir, sizeof(record_dir), "_rec");
|
||||
fixture_init(&sched, record_dir);
|
||||
|
||||
/* ---- Prelude (scheduler-snapshot-job-allocation task 4.2, see this
|
||||
* file's ADDENDUM header comment): PREEXIST_ID is submitted,
|
||||
* genuinely live-dispatched, and confirmed RUN entirely BEFORE
|
||||
* recording starts -- so it "predates the snapshot" exactly as
|
||||
* Requirement 1 describes, and its dispatch decision is never written
|
||||
* to the .replay file at all (nothing is recorded yet). ---- */
|
||||
enqueue_queue_update(&sched, "normal", 1);
|
||||
|
||||
preexist_jobs = (xce_job_t**)calloc(1, sizeof(xce_job_t*));
|
||||
preexist_jobs[0] = make_job(PREEXIST_ID, 100ULL, "normal", "preexist-user");
|
||||
enqueue_jobs_push(&sched, preexist_jobs, 1);
|
||||
|
||||
run_round(&sched, preexist_prelude_allocator_thread_fn);
|
||||
|
||||
{
|
||||
xce_sched_job_t* preexist = sched_get_job(&(sched.core), PREEXIST_ID);
|
||||
|
||||
TEST_ASSERT_NOT_NULL(preexist);
|
||||
TEST_ASSERT_FALSE_MESSAGE(
|
||||
JOB_IS_RUN(preexist->state),
|
||||
"PREEXIST_ID must still be PEND immediately after its dispatch "
|
||||
"decision -- RUN confirmation is a separate step, exactly as it "
|
||||
"is for every other job in this file (J2-J12)");
|
||||
TEST_ASSERT_NOT_NULL_MESSAGE(
|
||||
preexist->accounts,
|
||||
"the prelude's genuine live dispatch must have already set "
|
||||
"PREEXIST_ID's accounts");
|
||||
}
|
||||
|
||||
enqueue_jstate_change(&sched, PREEXIST_ID, JOB_STAT_RUN);
|
||||
run_round(&sched, generic_allocator_thread_fn);
|
||||
|
||||
{
|
||||
xce_sched_job_t* preexist = sched_get_job(&(sched.core), PREEXIST_ID);
|
||||
|
||||
TEST_ASSERT_NOT_NULL(preexist);
|
||||
TEST_ASSERT_TRUE_MESSAGE(
|
||||
JOB_IS_RUN(preexist->state),
|
||||
"PREEXIST_ID must now be RUN -- fully 'already running' before "
|
||||
"recording ever starts, matching Requirement 1's exact "
|
||||
"scenario");
|
||||
}
|
||||
|
||||
rc = sched_record_start(&sched, "scheduler-e2e-original-motivation.replay");
|
||||
TEST_ASSERT_EQUAL_INT(0, rc);
|
||||
TEST_ASSERT_TRUE(strlen(sched.record_file_path) < sizeof(r_path));
|
||||
strcpy(r_path, sched.record_file_path);
|
||||
|
||||
/* ---- Round 1: ANCHOR_ID's genesis (arrival + RUN confirmation, both
|
||||
* via the real dataq/translate path) + J2's genuinely live dispatch. */
|
||||
enqueue_queue_update(&sched, "normal", 1);
|
||||
* via the real dataq/translate path) + J2's genuinely live dispatch.
|
||||
* No enqueue_queue_update() here (unlike before task 4.2's prelude was
|
||||
* added): the "normal" queue already exists as of the prelude above,
|
||||
* and is therefore already part of the initial SnapshotEntry
|
||||
* sched_record_start() just captured. Re-issuing an identical
|
||||
* QUEUE_UPDATE here would additionally get RECORDED into round 1 and
|
||||
* REPLAYED against that same snapshot-restored queue -- exercising
|
||||
* core_upsert_queue()'s "queue already exists -> update in place"
|
||||
* branch for a queue whose xce_sched_queue_t was built by
|
||||
* xce_sched_core_load_snapshot()'s own restore path rather than
|
||||
* core_build_queue() -- a genuine, pre-existing (latent, previously
|
||||
* uncovered by any test) defect in that combination, confirmed by
|
||||
* empirically triggering it (ASAN bad-free in core_upsert_queue,
|
||||
* core_events.c:336, freeing q->resreq) while first writing this
|
||||
* addendum. Fixing that defect is production code, out of this
|
||||
* test-only task's boundary (Requirement 1/2/3 do not depend on it);
|
||||
* simply not re-declaring an already-existing queue is both correct
|
||||
* (the queue's priority/status are unchanged either way) and sufficient
|
||||
* to keep this task's own addition from exercising unrelated,
|
||||
* out-of-boundary production code. */
|
||||
|
||||
register_want(ANCHOR_ID, ANCHOR_WANT);
|
||||
anchor_jobs = (xce_job_t**)calloc(1, sizeof(xce_job_t*));
|
||||
|
|
@ -1100,17 +1333,28 @@ static void test_e2e_original_motivation_long_replay(void)
|
|||
snprintf(script_path, sizeof(script_path), "%s/script.txt", aux_dir);
|
||||
snprintf(capture_path, sizeof(capture_path), "%s/capture.out", aux_dir);
|
||||
|
||||
/* 3 + 10 + 8 = 21 stepped rounds, then continue drains the final 3
|
||||
* (22, 23, 24) to end of stream. */
|
||||
/* 1 + 2 + 10 + 8 = 21 stepped rounds, then continue drains the final 3
|
||||
* (22, 23, 24) to end of stream. The lone "step 1" first (splitting
|
||||
* off what used to be the first "step 3") gives PREEXIST_ID (task
|
||||
* 4.2) a checkpoint after just ONE round -- the earliest possible
|
||||
* observation point, strictly before ANCHOR_ID's own first checkpoint
|
||||
* at round 3 -- while the cumulative round counts at every other
|
||||
* checkpoint (3, 13, 21, 24) are unchanged from before this task. */
|
||||
write_text_file(script_path,
|
||||
"step 3\n"
|
||||
"step 1\n"
|
||||
"info worker worker-e2e-pre\n"
|
||||
"step 2\n"
|
||||
"info worker worker-e2e\n"
|
||||
"info worker worker-e2e-pre\n"
|
||||
"step 10\n"
|
||||
"info worker worker-e2e\n"
|
||||
"info worker worker-e2e-pre\n"
|
||||
"step 8\n"
|
||||
"info worker worker-e2e\n"
|
||||
"info worker worker-e2e-pre\n"
|
||||
"continue\n"
|
||||
"info worker worker-e2e\n"
|
||||
"info worker worker-e2e-pre\n"
|
||||
"quit\n");
|
||||
|
||||
pid = fork();
|
||||
|
|
@ -1194,6 +1438,80 @@ static void test_e2e_original_motivation_long_replay(void)
|
|||
"ANCHOR_ID has been reconciled -- that would be bug-1613's exact "
|
||||
"pre-fix symptom");
|
||||
|
||||
/* ---- Observable #3 (Req 1.1-1.3, scheduler-snapshot-job-allocation
|
||||
* task 4.2 -- see this file's ADDENDUM header comment): PREEXIST_ID's
|
||||
* allocation is correct from the FIRST possible checkpoint (after just
|
||||
* ONE replayed round), strictly earlier than ANCHOR_ID's own first
|
||||
* checkpoint above, and stays correct through all 24 rounds. Unlike
|
||||
* ANCHOR_ID, PREEXIST_ID's dispatch decision predates the recording
|
||||
* entirely and can never be discovered by replay-based reconciliation
|
||||
* (sim_reconcile_unaccounted_jobs()) -- its correctness here can ONLY
|
||||
* come from xce_sched_core_load_snapshot()'s own allocation
|
||||
* restoration (task 2.1's build_wire_job() save-side wiring + task
|
||||
* 2.2's dup_job_alloc()/make_job_account() load-side wiring), proven
|
||||
* concretely by the DISPATCH-never-appears guard below. Before this
|
||||
* feature's fix, job->allocs/job->accounts were never restored at
|
||||
* all (snapshot_wire.c's own former "not captured" comment,
|
||||
* snapshot.c's former Scope Decisions bullet) -- this checkpoint
|
||||
* would have read 0.00 at every single one of these five points, for
|
||||
* the entire run, with no mechanism (not even reconciliation) able to
|
||||
* ever recover it, since no DISPATCH decision for this job exists
|
||||
* anywhere in the replay stream to reconcile against. */
|
||||
q1 = strstr(captured, "used=9.00");
|
||||
TEST_ASSERT_NOT_NULL_MESSAGE(
|
||||
q1, "after just 1 round: PREEXIST_ID's 9.0-unit charge, restored "
|
||||
"purely by loading the recording's own initial snapshot, must "
|
||||
"already be visible -- no dispatch decision for this job "
|
||||
"exists anywhere in the recording for reconciliation to ever "
|
||||
"find");
|
||||
|
||||
q2 = strstr(q1, "used=9.00");
|
||||
TEST_ASSERT_NOT_NULL_MESSAGE(
|
||||
q2, "after 3 rounds: PREEXIST_ID's charge must still hold");
|
||||
|
||||
q3 = strstr(q2, "used=9.00");
|
||||
TEST_ASSERT_NOT_NULL_MESSAGE(
|
||||
q3, "after 13 rounds: PREEXIST_ID's charge must still hold");
|
||||
|
||||
q4 = strstr(q3, "used=9.00");
|
||||
TEST_ASSERT_NOT_NULL_MESSAGE(
|
||||
q4, "after 21 rounds: PREEXIST_ID's charge must still hold");
|
||||
|
||||
q5 = strstr(q4, "used=9.00");
|
||||
TEST_ASSERT_NOT_NULL_MESSAGE(
|
||||
q5, "after all 24 rounds: PREEXIST_ID's charge must still be "
|
||||
"exactly 9.00 at the very end of the replay -- nothing more "
|
||||
"and nothing less");
|
||||
|
||||
/* Concrete proof of mechanism: PREEXIST_ID's own DISPATCH decision
|
||||
* must NEVER appear anywhere in the captured replay output -- its
|
||||
* dispatch happened strictly before sched_record_start() was ever
|
||||
* called, so nothing about it was ever written to the .replay file.
|
||||
* If this string DID appear, it would mean the test's own prelude
|
||||
* leaked into the recording (a test-authoring bug), not a genuine
|
||||
* proof of the snapshot-restoration mechanism under test. */
|
||||
fmt_jobid(preexist_jobid_str, sizeof(preexist_jobid_str), PREEXIST_ID);
|
||||
snprintf(preexist_marker, sizeof(preexist_marker),
|
||||
"[sim] DISPATCH jobid=%s", preexist_jobid_str);
|
||||
TEST_ASSERT_NULL_MESSAGE(
|
||||
strstr(captured, preexist_marker),
|
||||
"PREEXIST_ID's dispatch predates the whole recording -- it must "
|
||||
"NEVER appear as a DISPATCH decision anywhere in replay output; "
|
||||
"its correct accounting comes solely from snapshot-load "
|
||||
"restoration, not from any replay-discoverable decision");
|
||||
|
||||
/* Non-tautology guard, symmetric to ANCHOR_ID's own above: this is
|
||||
* exactly the failure signature task 2.2's own load-side restoration
|
||||
* (dup_job_alloc()/make_job_account() in xce_sched_core_load_
|
||||
* snapshot()) would produce if it were reverted -- PREEXIST_ID's
|
||||
* allocation predates the snapshot and has no other recovery path. */
|
||||
TEST_ASSERT_NULL_MESSAGE(
|
||||
strstr(captured, "resource slots: value=15.00 used=0.00"),
|
||||
"worker-e2e-pre's slots resource must never read back to "
|
||||
"used=0.00 -- PREEXIST_ID's allocation has no recovery path other "
|
||||
"than snapshot-load restoration, since no DISPATCH decision for "
|
||||
"it exists anywhere in the replay stream");
|
||||
|
||||
free(captured);
|
||||
|
||||
printf("test_e2e_original_motivation_long_replay: PASS\n");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue