scheduler_test_src = [ 'test.c', ] # libedit_dep (defined in the parent meson.build, task 12.1, Req 5 AC 22): # every white-box test TU that #includes ../src/sim_loop.c now transitively # pulls in repl.h's inline wrappers, which reference repl.c's real # readline()/add_history() calls the moment ANY such TU also #includes # ../src/repl.c (already required at link time regardless -- sim_loop.c's # own repl.h wrappers reference xce_repl_start()/xce_repl_post_session_check() # unconditionally). Added to the shared deps list rather than per-test so # every current and future sim-family white-box test picks it up # automatically. scheduler_test_deps = [libxce_deps, librtti_dep, unity_dep, libxce_dep, libedit_dep] incdir = include_directories('../include', '../../include', '.', '../src', '../../lib') scheduler_test = executable('sched_test', scheduler_test_src, include_directories:[incdir], dependencies: [scheduler_test_deps], install: false) # White-box test for the notify single-job in-place update path # (sched_update_existing_job). It #includes ../src/schedobj.c directly, so it # is a standalone TU with its own main() — built as a separate executable. sched_job_update_test = executable('sched_job_update_test', ['test_job_update.c'], include_directories:[incdir], dependencies: [scheduler_test_deps], install: false) # White-box test for the notify/dataset enqueue handlers. It #includes # ../src/handler.c directly (enq_pend_update + the static handlers), so it is a # standalone TU with its own main() — built as a separate executable. sched_handlers_test = executable('sched_handlers_test', ['test_handlers.c'], include_directories:[incdir], dependencies: [scheduler_test_deps], install: false) # White-box test for the compact job-array push receive/expand path # (job-array-single-wal-record task 5.3). It also #includes ../src/handler.c # directly, but additionally needs a REAL sched->jobs kvmgr (sched_get_job/ # sched_add_job) to exercise the per-element dedup check for real — kept as # its own binary rather than folded into sched_handlers_test so that file's # "self-contained, only sched_init_config stubbed" story stays accurate. sched_job_array_test = executable('sched_job_array_test', ['test_job_array_expand.c'], include_directories:[incdir], dependencies: [scheduler_test_deps], install: false) # Cross-daemon integration test (job-array-single-wal-record task 5.5): the # REAL xce_encode()/xce_decode()/extract_data() -> scheduler_req_handler() # chain (the top-level function vtask_entry() registers as its handler), # proving one-push/N-tasks/log-once and redelivery-safety under genuinely # re-decoded wire bytes -- one layer more real than sched_job_array_test's # own wire-dispatch case, which stops at sched_handle_dataset(). Kept as its # own binary for the same reason sched_job_array_test is separate from # sched_handlers_test: it needs a REAL sched->jobs kvmgr for the dedup check. sched_job_array_wire_e2e_test = executable('sched_job_array_wire_e2e_test', ['test_job_array_wire_e2e.c'], include_directories:[incdir], dependencies: [scheduler_test_deps], install: false) # Compile-check for the job picker plugin contract, xce_job_picker_iface_t # (scheduler-core spec, task 1.1). Only #includes plugin.h -- no picker # implementation exists yet (that's task 2.x). -Werror on incompatible # pointer types so a hook signature drift in plugin.h fails the build, not # just an assertion: the test's real content is "this compiles at all". sched_picker_iface_test = executable('sched_picker_iface_test', ['test_picker_iface.c'], include_directories:[incdir], dependencies: [scheduler_test_deps], c_args: ['-Werror=incompatible-pointer-types'], install: false) # White-box test for the picker plugin registration category and the # job_elect_fn compatibility wrapper (scheduler-core spec, task 1.2). It # #includes ../src/plugin.c directly (same white-box pattern as # sched_handlers_test/sched_job_array_test) so it exercises the real # plugin_register() and the real legacy_picker_wrapper_iface, and needs a # REAL sched->plugins kvmgr (same setup scheduler.c's sched_plugin_init() # uses) to register plugins through it for real. sched_picker_registration_test = executable('sched_picker_registration_test', ['test_plugin_picker_registration.c'], include_directories:[incdir], dependencies: [scheduler_test_deps], install: false) # White-box test for the picker configuration fields added to # xce_scheduler_t/xce_sched_queue_t/xce_sched_project_t (scheduler-core # spec, task 1.3). It #includes ../src/schedobj.c directly (same white-box # pattern as sched_job_update_test) so it exercises the real # make_sched_queue/make_sched_project/sched_set_default_job_pick_plugin, # not a re-implementation of any of them. sched_picker_config_fields_test = executable('sched_picker_config_fields_test', ['test_picker_config_fields.c'], include_directories:[incdir], dependencies: [scheduler_test_deps], install: false) # White-box test for builtin_fcfs's xce_job_picker_iface_t lifecycle hooks # (scheduler-core spec, task 2.1). It #includes ../src/plugins/builtin_fcfs.c # directly (same white-box pattern as sched_picker_registration_test) so it # exercises the real builtin_fcfs_init()/builtin_fcfs_fini() and the real # private fcfs_plugin_data_t layout, not a re-implementation of either. sched_picker_fcfs_test = executable('sched_picker_fcfs_test', ['test_picker_fcfs.c'], include_directories:[incdir], dependencies: [scheduler_test_deps], install: false) # White-box test for builtin_fcfs's session hooks (begin_session/next_job/ # end_session) and post-allocation hooks (on_dispatch/on_pend) (scheduler-core # spec, task 2.3). Split out of test_picker_fcfs.c rather than appended to it # -- that file was already ~765 lines after tasks 2.1/2.2, against this # project's 800-line ceiling. Also #includes ../src/plugins/builtin_fcfs.c # directly (same white-box pattern as sched_picker_fcfs_test), and supplies # its own sched_queue_is_ready()/sched_job_is_ready() test doubles since this # translation unit does not link scheduler.c (see the file header comment). sched_picker_fcfs_session_test = executable('sched_picker_fcfs_session_test', ['test_picker_fcfs_session.c'], include_directories:[incdir], dependencies: [scheduler_test_deps], install: false) # White-box test for wiring builtin_fcfs in as the registered default picker # and removing the hardcoded "xce_sched_fcfs" picker string (scheduler-core # spec, task 2.4). It #includes ../src/plugin.c, ../src/schedobj.c, and # ../src/plugins/builtin_fcfs.c directly (same white-box pattern as the # other picker tests) so it exercises the real plugin_register(), # register_builtin_fcfs(), sched_set_default_job_pick_plugin(), and # sched_resolve_job_picker() together -- not a re-implementation of any of # them. See the file's own header comment for why sched_job_picker() itself # (scheduler.c) is covered at the resolved-plugin level rather than by # whole-file-including scheduler.c. sched_picker_wiring_test = executable('sched_picker_wiring_test', ['test_picker_wiring.c'], include_directories:[incdir], dependencies: [scheduler_test_deps], install: false) # Regression guard for the core scheduling loop boundary (scheduler-core # spec, task 2.5, Req 1 AC 1 / AC 7): "the core loop calls only # picker->next_job() ... no project/queue/job iteration or ordering logic # remains in the loop itself." Does NOT #include scheduler.c (that file's # external dependency surface is why test_picker_wiring.c's own header # comment already ruled out driving sched_job_picker() directly) -- instead # it reads scheduler.c's real on-disk text at test run time and mechanically # checks sched_job_picker()'s body for required picker-interface call sites # and absent direct-traversal symbols. XCE_SCHEDULER_C_PATH bakes in the # absolute path via meson.current_source_dir() so the check has no # dependency on the test's cwd at run time. sched_picker_core_loop_boundary_test = executable( 'sched_picker_core_loop_boundary_test', ['test_picker_core_loop_boundary.c'], include_directories:[incdir], dependencies: [scheduler_test_deps], c_args: ['-DXCE_SCHEDULER_C_PATH="' + (meson.current_source_dir() / '..' / 'src' / 'scheduler.c') + '"'], install: false) # Regression guard for Req 6 AC 2 (scheduler-core spec, task 2.6): "All pend # reason allocation shall go through make_pendreason() (lib/preason.c). # Callers never calloc(sizeof(xce_pendreason_t)) directly." Same genre as # sched_picker_core_loop_boundary_test above (reads real on-disk source at # test run time rather than linking the huge dependency surface a live # scheduler pulls in), but scans every non-testsuite .c/.h file under # src/scheduler for the forbidden pattern rather than one function's body. # XCE_SCHEDULER_ROOT_PATH bakes in src/scheduler's absolute path; # the scanned file list itself lives in the test source (see that file's # header comment for why a fixed list, not a directory walk). sched_pendreason_factory_audit_test = executable( 'sched_pendreason_factory_audit_test', ['test_picker_pendreason_factory_audit.c'], include_directories:[incdir], dependencies: [scheduler_test_deps], c_args: ['-DXCE_SCHEDULER_ROOT_PATH="' + (meson.current_source_dir() / '..') + '"'], install: false) # Regression guard for task 4.1's Observable (scheduler-core spec, Req # 5.1/5.2): "the core structure compiles and links with zero symbols from # the networking/API libraries ... a build-time or link-time check # confirms this." Same source-text-scan genre as # sched_picker_core_loop_boundary_test / sched_pendreason_factory_audit_test # above, PLUS a genuine link-time proof: it inspects the undefined-symbol # table (via nm(1)) of sched_core_isolation_lib (defined in the parent # meson.build -- core.c compiled alone, isolated from the rest of the # scheduler). link_with establishes the build-order dependency so that # archive exists before this test runs; XCE_CORE_LIB_PATH bakes in its # absolute path the same way XCE_SCHEDULER_C_PATH does above. sched_core_isolation_test = executable( 'sched_core_isolation_test', ['test_core_isolation.c'], include_directories:[incdir], dependencies: [scheduler_test_deps], link_with: [sched_core_isolation_lib], c_args: ['-DXCE_CORE_H_PATH="' + (meson.current_source_dir() / '..' / 'include' / 'core.h') + '"', '-DXCE_CORE_C_PATH="' + (meson.current_source_dir() / '..' / 'src' / 'core.c') + '"', '-DXCE_CORE_EVENTS_C_PATH="' + (meson.current_source_dir() / '..' / 'src' / 'core_events.c') + '"', '-DXCE_CORE_SESSION_C_PATH="' + (meson.current_source_dir() / '..' / 'src' / 'core_session.c') + '"', '-DXCE_CORE_LIB_PATH="' + sched_core_isolation_lib.full_path() + '"'], install: false) # Regression guard (2026-08-20) for the "PEND/DISPATCH/PREEMPT lines carried # an unexpected tlog prefix" bug -- see test_no_bare_printf.c's own header # comment for the full rationale (xce_scheduler link-wraps printf via # wrap_link_args above; fprintf(stdout, ...) is the required convention). # Directory-path defines (not one per file, like XCE_CORE_C_PATH above) so # a future new .c file in either directory is automatically covered. sched_no_bare_printf_test = executable( 'sched_no_bare_printf_test', ['test_no_bare_printf.c'], include_directories:[incdir], dependencies: [scheduler_test_deps], c_args: ['-DXCE_SCHEDULER_SRC_DIR="' + (meson.current_source_dir() / '..' / 'src') + '"', '-DXCE_SCHEDULER_PLUGINS_DIR="' + (meson.current_source_dir() / '..' / 'src' / 'plugins') + '"'], install: false) # Regression guard for task 4.2's jbuf-capacity half (scheduler-core spec, # Req 5 AC 7): "cbuf capacity=1 serialization ... this capacity is a # determinism invariant, not a tuning knob." Same white-box #include # pattern as test_picker_config_fields.c (pulls the real # xce_sched_core_init()/xce_sched_core_fini() from ../src/core.c into this # TU) PLUS the source-text-scan genre used by test_picker_core_loop_boundary_test/ # test_core_isolation_test above -- a real runtime call proving # core.jbuf.ncap == 1, and a scan of core.c's actual on-disk text proving # the cbuf_init() capacity argument is the literal 1 (never a variable), # that the former `njobs` local is gone, and that the separate/unrelated # `ndecisions` FIXME was left untouched. XCE_CORE_C_PATH reuses the same # absolute-path constant as sched_core_isolation_test above. sched_core_jbuf_capacity_pin_test = executable( 'sched_core_jbuf_capacity_pin_test', ['test_core_jbuf_capacity_pin.c'], include_directories:[incdir], dependencies: [scheduler_test_deps], c_args: ['-DXCE_CORE_C_PATH="' + (meson.current_source_dir() / '..' / 'src' / 'core.c') + '"'], install: false) # Contract test for the core event interface and batch event push # (scheduler-core spec, task 4.3, Req 5 AC 4 / AC 8): xce_core_push_events() # fires the resolved picker's corresponding state-change hook exactly once # per event, synchronously, before it returns, and rejects with -EBUSY (no # event applied) when a session is active. Same white-box #include pattern # as test_core_jbuf_capacity_pin.c/test_core_isolation.c (pulls the real # ../src/core.c into this TU) -- see the test's own header comment for why # it provides its own real sched_resolve_job_picker() rather than # #include-ing schedobj.c. sched_core_events_test = executable( 'sched_core_events_test', ['test_core_events.c'], include_directories:[incdir], dependencies: [scheduler_test_deps], install: false) # Contract test for the session-start signal and decision callback protocol # (scheduler-core spec, task 4.4, Req 5 AC 5 / AC 6): xce_core_go() signals # the picker thread non-blockingly and rejects reentrant calls with # -EINVAL; decisions placed on core->decisions reach the driver-registered # on_decision callback once each, in order, followed by the end-of-session # NULL marker terminating the drain loop; xce_core_end_session() clears # session_active. Same white-box #include pattern as test_core_events.c # (pulls ../src/core.c, ../src/core_session.c, and ../src/decision.c into # this TU) -- see the test's own header comment for why this file needs no # picker-plugin fixture (xce_core_go()/xce_core_end_session() never call # sched_resolve_job_picker()). sched_core_session_test = executable( 'sched_core_session_test', ['test_core_session.c'], include_directories:[incdir], dependencies: [scheduler_test_deps], install: false) # Contract test for clock virtualization and session timing (scheduler-core # spec, task 4.5, Req 5 AC 3 / AC 12): xce_core_now()'s two-anchor + speed # formula for all four documented modes, xce_core_tlog_format()'s tlog # integration (frozen virtual time shown instead of info->time's real # wall-clock read), and session_start/session_duration_ns tracking across a # real xce_core_go()/xce_core_end_session() cycle. Same white-box #include # pattern as test_core_session.c (pulls ../src/core.c, ../src/core_session.c, # and ../src/decision.c into this TU) PLUS ../src/core_clock.c (this task's # new file -- see that file's own header comment for why xce_core_now()/ # the tlog format function live there, not in core.c). sched_core_clock_test = executable( 'sched_core_clock_test', ['test_clock.c'], include_directories:[incdir], dependencies: [scheduler_test_deps], install: false) # Core contract test for the full push-events -> start-session -> # drain-decisions -> end-session cycle (scheduler-core spec, task 4.6, Req 5 # AC 1 / AC 2), against a real picker thread + a stand-in allocator (this # test's own driver thread) driving a minimal stub picker plugin through # xce_core_push_events()/xce_core_go()/xce_core_end_session() end to end -- # also proving, mid-cycle against a GENUINELY active session, both the # reentrant xce_core_go() rejection (Req 5 AC 5) and the xce_core_push_events() # -EBUSY rejection (Req 5 AC 8) compose correctly with the rest of the # cycle. Same white-box #include pattern as test_core_events.c/ # test_core_session.c (pulls ../src/core.c, ../src/core_events.c, # ../src/core_session.c, ../src/core_clock.c, and ../src/decision.c into # this TU) -- see the test's own header comment for the allocator-thread- # vs-direct-jbuf-drain design call. sched_core_full_cycle_test = executable( 'sched_core_full_cycle_test', ['test_core_full_cycle.c'], include_directories:[incdir], dependencies: [scheduler_test_deps], install: false) # Contract test for the normal-mode driver's controller event translation # path (scheduler-core spec, task 5.1, Req 5 AC 8 / AC 9's translation # half): xce_sched_driver_translate_pending_events() drains core->pend_updates # (the same dataq-swap mechanism handler.c already populates and # scheduler.c's sched_update() already drains), translates each dequeued # xce_sched_update_request_t into the matching xce_core_event_t for all 10 # op types, and pushes the batch through a genuine xce_core_push_events() # call. Same white-box #include pattern as test_core_events.c (pulls the # real ../src/core.c and ../src/core_events.c into this TU) PLUS the new # ../src/driver.c under test -- see that test's own header comment for why # it provides its own real sched_resolve_job_picker() rather than # #include-ing schedobj.c. sched_driver_translate_test = executable( 'sched_driver_translate_test', ['test_driver_translate.c'], include_directories:[incdir], dependencies: [scheduler_test_deps], install: false) # Regression test for bug-1585's true root cause: a live heap-use-after-free # in the RESVALS_FULL/RESVALS_DELTA event-application path (core_events.c), # triggered by every second periodic resval report for the same # worker+resource on ANY real deployment. Same white-box #include set as # sched_driver_translate_test (its sibling), but with a REAL (non-stubbed) # kill_sched_resval -- see test_resval_ownership.c's own header comment for # why that distinction is exactly what makes this test able to catch the bug # sched_driver_translate_test's own no-op stub cannot. sched_resval_ownership_test = executable( 'sched_resval_ownership_test', ['test_resval_ownership.c'], include_directories:[incdir], dependencies: [scheduler_test_deps], install: false) # Contract test for the normal-mode driver's decision-publish callback # (scheduler-core spec, task 5.2, Req 5 AC 6 / AC 9's publishing half): # xce_sched_driver_on_decision() forwards DISPATCH/PEND decisions to # sched_publish_dispatch()/sched_publish_pend_reason() exactly once each, # with the same single-item njobs=1/nreasons=1 wrapping; PREEMPT fails # loudly (-ENOSYS, no publish) rather than fabricating a nonexistent # xcecli_preempt() call; NULL driver_ctx/decision each return -EINVAL, no # publish. Same white-box #include pattern as test_driver_translate.c # (pulls ../src/core.c, ../src/core_clock.c, ../src/core_events.c, and the # new ../src/driver.c into this TU) PLUS ../src/decision.c for the real # make_dispatch_decision()/make_pend_decision()/make_preempt_decision() # constructors this file's fixtures use. sched_publish_dispatch()/ # sched_publish_pend_reason() are SPY test doubles (this file never links # scheduler.c), same rationale as test_driver_translate.c's own stubs. sched_driver_decision_cb_test = executable( 'sched_driver_decision_cb_test', ['test_driver_decision_cb.c'], include_directories:[incdir], dependencies: [scheduler_test_deps], install: false) # Safety-property proof for the begin/end-session ordering seam task 5.2 # introduced (Req 1 AC 7 / Req 5 AC 9): xce_sched_driver_run_normal_mode_round() # (driver.c) must call plugin_begin_session()/sched_account_jobs() strictly # AFTER xce_core_begin_session()'s resval reset and strictly BEFORE # xce_core_signal_go() wakes the picker thread -- otherwise the picker could # observe a session whose resource-in-use accounting was reset to zero but # not yet re-summed from running jobs. Drives the REAL # xce_sched_driver_run_normal_mode_round() (white-box #include of # ../src/driver.c, same TU as test_driver_translate.c/ # test_driver_decision_cb.c, PLUS ../src/core_session.c for the real # xce_core_begin_session()/xce_core_signal_go()/xce_core_end_session() # under test) against a real picker pthread (same design as # test_core_full_cycle.c's test_picker_thread_fn -- see that file's own # header comment for the full "why a real thread, not a sequential drain" # rationale: jbuf's hardcoded capacity-1 rendezvous requires one). Uses the # REAL plugin_begin_session()/plugin_end_session() (../src/plugin.c) driven # through a genuinely test-registered xce_sched_plugin_t whose # begin_session_fn/end_session_fn set/check an ordering flag -- per this # task's own suggested technique, this is a stronger proof than spying on # plugin_begin_session() itself. sched_account_jobs() (scheduler.c, defined # on xce_sched_core_t* as of scheduler-sim-decision-parity task 1.1, pulls # in resource.c's sched_charge_account()) is instead a SPY test double # recording an order index -- this test's target is the DRIVER's ordering # discipline, not sched_account_jobs()'s own resource-accounting # correctness (out of this task's scope, same "spy the collaborator" # rationale test_driver_decision_cb.c/test_driver_translate.c already # established for the xce_scheduler_t*-coupled # sched_publish_dispatch()/sched_publish_pend_reason()). sched_driver_session_ordering_test = executable( 'sched_driver_session_ordering_test', ['test_driver_session_ordering.c'], include_directories:[incdir], dependencies: [scheduler_test_deps], install: false) # Requirement 1.4 proof for the Core-Level Resource Accounting component # (scheduler-sim-decision-parity spec, task 1.1): sched_charge_account()/ # sched_uncharge_account()/sched_commit_job_alloc() (resource.c, relocated # from xce_scheduler_t* to xce_sched_core_t* by this task) produce # byte-identical resInUse/sharedInUse output whether `core` came from an # xce_scheduler_t (normal-mode driver) or an xce_sched_sim_driver_t # (simulation driver, sim.h) -- see test_resource_accounting.c's own file # header comment for why sched_account_jobs() itself (scheduler.c) is not # also white-box #included here (no existing test in this directory # white-box #includes scheduler.c, for the same reason documented there). sched_resource_accounting_test = executable( 'sched_resource_accounting_test', ['test_resource_accounting.c'], include_directories:[incdir], dependencies: [scheduler_test_deps], install: false) # Cross-core behavioral-equivalence proof for # xce_sched_core_save_snapshot()/xce_sched_core_load_snapshot() # (scheduler-core spec, task 8.1, Req 5 AC 21 / Req 6 AC 5): save immediately # followed by load into a freshly-initialized, completely separate core # produces a core whose observable scheduling behavior (next session's # decisions, given the same events) is identical to the pre-save core, plus # direct unit-level proof of both functions' -EBUSY (mid-session)/-EINVAL # (NULL args) guards. Same white-box #include pattern as # test_core_full_cycle.c (../src/core.c, ../src/core_clock.c, # ../src/core_events.c, ../src/core_session.c, ../src/decision.c) PLUS the # three files task 8.1's own 800-line-cap split produced: # ../src/snapshot.c, ../src/snapshot_wire.c, ../src/snapshot_load.c. See # that test's own header comment for the two-independent-picker-instance # design (xce_sched_plugin_t->data-scoped state) that lets this test drive # two fully independent xce_sched_core_t instances through the identical # session protocol without cross-contaminating a shared global. sched_snapshot_save_load_test = executable( 'sched_snapshot_save_load_test', ['test_snapshot_save_load.c'], include_directories:[incdir], dependencies: [scheduler_test_deps], install: false) # White-box test for the recording-directory path-validation function # (scheduler-core spec, task 9.1, Req 5 AC 10 "Record file path # validation"): rejects a recordFile containing a path separator or a ".." # segment BEFORE any filesystem access, and confirms containment beneath # record_dir via a genuine canonical-path (realpath()) comparison rather # than a textual prefix match -- including a symlink-escape case and the # "record_dir vs record_dir-evil sibling" prefix-match trap named in this # task's own security brief. Same white-box #include pattern as # test_job_update.c/test_handlers.c (pulls the real # ../src/recording.c into this TU) -- the function under test has no # scheduler-struct fixture dependency at all, so this is the simplest # white-box test in this directory. sched_recording_path_validation_test = executable( 'sched_recording_path_validation_test', ['test_recording_path_validation.c'], include_directories:[incdir], dependencies: [scheduler_test_deps], install: false) # Contract test for the record start/stop lifecycle and the driver-loop # recording-write hooks (scheduler-core spec, task 9.2, Req 5 AC 10): start # writes a decodable ReplayHeader then SnapshotEntry; a full start -> submit # event batch -> complete one real session (real picker + stand-in # allocator threads, same rendezvous design as # sched_driver_session_ordering_test) -> stop cycle produces exactly the # expected message stream ending in ReplayEvent{endSession}; recording # inactive costs zero file I/O; double-start/stop-when-not-recording fail # cleanly; a TOCTOU-style symlink/hard-link swap between path validation # and the eventual open() is rejected. Same white-box #include pattern as # sched_driver_session_ordering_test (core.c/core_clock.c/core_events.c/ # core_session.c/driver.c/plugin.c) PLUS ../src/recording.c/ # recording_events.c/recording_session.c (the code under test) PLUS # ../src/snapshot.c/snapshot_wire.c (task 8.1's real # xce_sched_core_save_snapshot(), needed by sched_record_start()). sched_record_lifecycle_test = executable( 'sched_record_lifecycle_test', ['test_record_lifecycle.c'], include_directories:[incdir], dependencies: [scheduler_test_deps], install: false) # Contract test for the scheduler-side OPCode_schedAdmin request handler # (scheduler-core spec, task 9.4, Req 5 AC 10): decodes a forwarded # SchedAdminRequest, dispatches by action to sched_record_start()/ # sched_record_stop()/sched_record_status(), and sends back a # SchedAdminReply matching requirements.md's field-semantics table. # recordStatus is proven synchronous (answered directly on the handler # thread, both idle and while genuinely recording); recordStart/recordStop # are proven deferred (enqueued, not executed, until a subsequent # xce_sched_driver_translate_pending_events() drain actually performs the # real sched_record_start()/sched_record_stop() call and sends the reply). # Same white-box #include pattern as sched_driver_translate_test # (core.c/core_clock.c/core_events.c/driver.c) PLUS ../src/recording.c/ # recording_events.c/snapshot.c/snapshot_wire.c (real record start/stop/ # status/write, task 9.1/9.2/9.3) PLUS ../src/handler.c (the code under # test). xcecli_reply_schedadmin() is a SPY test double, same pattern # sched_driver_decision_cb_test already establishes for # sched_publish_dispatch()/sched_publish_pend_reason(). sched_admin_request_test = executable( 'sched_admin_request_test', ['test_admin_request.c'], include_directories:[incdir], dependencies: [scheduler_test_deps], install: false) # Contract test for simulation-mode startup (scheduler-core spec, task 11.1, # Req 5 AC 13): opening and validating the replay file (first message must # be ReplayHeader, first data message must be SnapshotEntry), locating the # most recent SnapshotEntry at or before --sim-start-ts, loading it via the # real xce_sched_core_load_snapshot(), and setting the virtual clock's # anchors from the loaded snapshot's timestamp and requested speed. Same # white-box #include pattern as sched_snapshot_save_load_test (../src/core.c, # ../src/core_clock.c, ../src/snapshot.c, ../src/snapshot_wire.c, # ../src/snapshot_load.c) PLUS ../src/recording.c (used only to build real # `.replay` fixtures via sched_record_start()/sched_record_stop(), not under # test here) PLUS the new ../src/sim.c under test. No driver.c/plugin.c/ # core_events.c/core_session.c/decision.c: this task stops at "ready-to-run" # (task 11.2 owns the event loop), so no real scheduling session is ever # driven. sched_sim_startup_test = executable( 'sched_sim_startup_test', ['test_sim_startup.c'], include_directories:[incdir], dependencies: [scheduler_test_deps], install: false) # Contract test for the simulation-mode event loop and virtual clock # advancement (scheduler-core spec, task 11.2, Req 5 AC 14/18): the virtual # clock jumps to each ReplayEvent's own timestamp, in exact file order # (including a same-timestamp pair), at the moment it is queued; each # ReplaySession boundary triggers one complete push-events -> # start-session -> drain-decisions -> end-session round, in file order # across multiple rounds. Same white-box #include pattern as # sched_sim_startup_test (core.c, core_clock.c, recording.c, sim.c, # snapshot.c/snapshot_wire.c/snapshot_load.c) PLUS core_events.c, # core_session.c, decision.c (the real session/decision machinery this # task's event loop drives) PLUS plugin.c, plugins/builtin_fcfs.c (task # 11.2's own new core.h-scoped picker registration path, # plugin_register_core()/builtin_fcfs_new_plugin() -- deliberately NOT # schedobj.c, which needs a genuine xce_scheduler_t* this driver has none # of, Req 5 AC 17) PLUS the new ../src/sim_loop.c under test. sched_sim_event_loop_test = executable( 'sched_sim_event_loop_test', ['test_sim_event_loop.c'], include_directories:[incdir], dependencies: [scheduler_test_deps], install: false) # Regression guard for task 11.3's Observable (scheduler-core spec, Req 5 AC # 17, "Simulation isolation"): "a build-time or structural check confirms no # controller-facing symbol is reachable from the simulation driver's compiled # object", plus the AC's own "confirmed by the struct definition itself, not # runtime checks alone" clause. Extended by task 11.5 to also cover the new # sim_record.c (--sim-output writer) sibling file. Same source-text-scan + # nm(1) link-time-proof genre as sched_core_isolation_test above, PLUS a # third, narrower structural layer scanning ONLY xce_sched_sim_driver_t's own # struct body text for forbidden field types -- see the test's own header # comment for why a comment-stripping pass is required first (sim.h's own # boundary doc comment legitimately names xcecli_ctx_t/xce_cluster_config_t # in prose). link_with establishes the build-order dependency on # sched_sim_isolation_lib (parent meson.build -- sim.c + sim_loop.c + # sim_picker.c (bug-1567's sim_loop.c-cap-driven sibling) + sim_record.c # compiled together, isolated from the rest of the scheduler); # XCE_SIM_*_PATH bake in absolute paths the same way XCE_CORE_*_PATH does # above. sched_sim_isolation_test = executable( 'sched_sim_isolation_test', ['test_sim_isolation.c'], include_directories:[incdir], dependencies: [scheduler_test_deps], link_with: [sched_sim_isolation_lib], c_args: ['-DXCE_SIM_H_PATH="' + (meson.current_source_dir() / '..' / 'include' / 'sim.h') + '"', '-DXCE_SIM_C_PATH="' + (meson.current_source_dir() / '..' / 'src' / 'sim.c') + '"', '-DXCE_SIM_LOOP_C_PATH="' + (meson.current_source_dir() / '..' / 'src' / 'sim_loop.c') + '"', '-DXCE_SIM_PICKER_C_PATH="' + (meson.current_source_dir() / '..' / 'src' / 'sim_picker.c') + '"', '-DXCE_SIM_RECORD_C_PATH="' + (meson.current_source_dir() / '..' / 'src' / 'sim_record.c') + '"', '-DXCE_SIM_REPL_C_PATH="' + (meson.current_source_dir() / '..' / 'src' / 'repl.c') + '"', '-DXCE_SIM_REPL_H_PATH="' + (meson.current_source_dir() / '..' / 'include' / 'repl.h') + '"', '-DXCE_SIM_REPL_BREAK_C_PATH="' + (meson.current_source_dir() / '..' / 'src' / 'repl_break.c') + '"', '-DXCE_SIM_REPL_INFO_C_PATH="' + (meson.current_source_dir() / '..' / 'src' / 'repl_info.c') + '"', '-DXCE_SIM_REPL_INTERNAL_H_PATH="' + (meson.current_source_dir() / '..' / 'src' / 'repl_internal.h') + '"', '-DXCE_SIM_REPL_PARAMS_C_PATH="' + (meson.current_source_dir() / '..' / 'src' / 'repl_params.c') + '"', '-DXCE_SIM_REPL_ROLLUP_C_PATH="' + (meson.current_source_dir() / '..' / 'src' / 'repl_rollup.c') + '"', '-DXCE_SIM_REPL_FMT_C_PATH="' + (meson.current_source_dir() / '..' / 'src' / 'repl_fmt.c') + '"', '-DXCE_SIM_LIB_PATH="' + sched_sim_isolation_lib.full_path() + '"'], install: false) # Contract test for decision verification (scheduler-core spec, task 11.4, # Req 5 AC 15/18): each core-emitted decision is compared against the # corresponding recorded decision at the same logical position when # --sim-verify is set, and any mismatch is reported with the exact logical # time and decision detail. Unit-level: sim_decision_eq()/sim_log_mismatch() # (new ../src/sim_verify.c, task 11.4's sibling file to sim_loop.c) driven # directly against hand-built DISPATCH/PEND/PREEMPT decision pairs -- # including DISPATCH, which sim_loop.c's own real picker thread can never # produce live (Req 5 AC 17-adjacent scope boundary: real resource-matching # allocation belongs to the not-yet-designed scheduler-allocation spec), so # this is the only way to prove that comparator for real. Integration-level: # a full sched_sim_driver_run() run against a real QUEUE_UPDATE+JOBS_PUSH # fixture feeding the real builtin_fcfs picker to a genuine live PEND # decision, --sim-verify both on (self-match reports zero mismatches, # altered-copy reports the exact mismatch) and off (no mismatch reported # even against an altered fixture) -- mismatch output observed via the same # STDOUT_FILENO dup()/dup2() capture technique # test_apply_correctness_verification.c's own # test_apply_divergent_loud_fence_log_omits_false_peer_hwm_clause # establishes for ERROR()'s tlog early-print path. Same white-box #include # pattern as sched_sim_event_loop_test (core.c, core_clock.c, core_events.c, # core_session.c, decision.c, plugin.c, plugins/builtin_fcfs.c, recording.c, # sim.c, sim_loop.c, snapshot.c/snapshot_wire.c/snapshot_load.c) PLUS the # new ../src/sim_verify.c under test. sched_sim_verify_test = executable( 'sched_sim_verify_test', ['test_sim_verify.c'], include_directories:[incdir], dependencies: [scheduler_test_deps], install: false) # Contract test for what-if event-source branching (scheduler-core spec, # task 11.5, Req 5 AC 16): running with --sim-alt-events produces decisions # driven by the alternate events, not the base file's original events. A # baseline run (no --sim-alt-events) proves the base file's own events drive # scheduling by default; a --sim-alt-events run against the SAME base file's # snapshot proves the alternate file's events drive it instead, and that the # base file's own events are never read once --sim-alt-events is set. Same # white-box #include pattern as sched_sim_verify_test (core.c, core_clock.c, # core_events.c, core_session.c, decision.c, plugin.c, plugins/builtin_fcfs.c, # recording.c, sim.c, sim_loop.c, sim_verify.c, snapshot.c/snapshot_wire.c/ # snapshot_load.c) -- sim_verify.c is required at link time even though this # file never sets --sim-verify (sim_loop.c externs its two entry points # unconditionally, same reason sched_sim_event_loop_test needs it). sched_sim_alt_events_test = executable( 'sched_sim_alt_events_test', ['test_sim_alt_events.c'], include_directories:[incdir], dependencies: [scheduler_test_deps], install: false) # Contract test for the --sim-output `.replay` writer (scheduler-core spec, # task 11.5, Req 5 AC 19): the output file, when requested, is decodable by # the same reader used for normal-mode recordings (test_record_lifecycle.c's # own capn_getp(capn_root(&c), 0, 1) + read_X()/decode_X() technique, reused # verbatim here), with full ReplayHeader -> SnapshotEntry -> ReplayEvent* -> # ReplaySession -> ReplayEvent{endSession} stream symmetry (Req 5 AC 19's own # symmetry table). A second test proves --sim-output composes with # --sim-alt-events: the output reflects the alternate run's own events and # decision, not the base file's. Same white-box #include pattern as # sched_sim_verify_test PLUS ../src/recording_session.c (the scheduler_t-free # session-accumulator entry points sim_loop.c now calls) PLUS the new # ../src/sim_record.c (the code under test). sched_sim_record_output_test = executable( 'sched_sim_record_output_test', ['test_sim_record_output.c'], include_directories:[incdir], dependencies: [scheduler_test_deps], install: false) # Contract test for deterministic replay and normal-to-simulation # equivalence (scheduler-core spec, task 11.6, Req 5 AC 7.1) -- the spec's # own central regression test: a synthetic scheduling session recorded # through the REAL normal-mode driver (real builtin_fcfs picker + a # stand-in allocator producing real PEND decisions via the same # make_pend_decision()/make_pendreason() production constructors) is # replayed through the REAL, unmodified simulation driver, and the two # resulting `.replay` files' ReplaySession.decisions lists are asserted to # match identically (same jobid, same pend reason content, per decision), # while never comparing ReplayHeader or SessionSummary fields (AC 7.1's own # "only non-decision metadata may differ" carve-out). First test file in # this directory to combine BOTH the normal-mode driver stack and the full # simulation stack in one TU -- see the test's own header comment for the # combined white-box #include set (test_record_lifecycle.c's own set union # test_sim_record_output.c's own set), the full stub surface, and why every # decision in this fixture is PEND rather than a DISPATCH/PEND mix # (sim_loop.c's sim_picker_thread_fn() can never emit a live DISPATCH today # -- a documented, out-of-this-task's-scope gap, not a weakening of this # test). sched_sim_equivalence_test = executable( 'sched_sim_equivalence_test', ['test_sim_equivalence.c'], include_directories:[incdir], dependencies: [scheduler_test_deps], install: false) # Round-boundary ordering contract for the simulation driver # (scheduler-sim-decision-parity spec, task 2.1, Req 1.3/1.4, 5.1, 5.3): the # sim-mode counterpart to sched_driver_session_ordering_test above -- proves # sim_loop.c's sched_sim_driver_run() now calls the relocated # sched_account_jobs() (core.h, task 1.1) once per replayed round, strictly # inside that round's session-active window, mirroring driver.c's # xce_sched_driver_run_normal_mode_round() exactly. Before this task, # sim_loop.c called the older monolithic xce_core_go() with no interleaving # slot and never called sched_account_jobs() at all (bug-1613) -- every # worker's/shared resource's resInUse stayed permanently zero for the whole # `--sim`/`--interactive` run. Same combined white-box #include set as # sched_sim_equivalence_test (records two real normal-mode rounds via the # REAL normal-mode driver, then replays the same file through the REAL, # unmodified simulation driver) -- see the test's own header comment for why # a spy sched_account_jobs() (not the real one) is the right-strength proof # here, and why no cross-thread wbuf-rendezvous replica of # test_driver_session_ordering.c's own design is attempted (sim_loop.c's # picker thread is not independently substitutable from a test without # touching sim_picker.c, outside this task's boundary). sched_sim_session_ordering_test = executable( 'sched_sim_session_ordering_test', ['test_sim_session_ordering.c'], include_directories:[incdir], dependencies: [scheduler_test_deps], install: false) # Recorded-Decision Reconciliation trigger/lookup/not-found contract # (scheduler-sim-decision-parity spec, task 2.2, Req 4.1/4.2, "Recorded- # Decision Reconciliation" component). Calls the new sim_loop.c-local # sim_reconcile_unaccounted_jobs() directly (it is `static` and not yet # wired into any call site -- task 3's job) against hand-built # xce_sched_core_t/replay_session_t fixtures (core_build_job()+ # sched_add_job(), no `.replay` file or capnp round-trip needed). Same # white-box #include/stub set as sched_sim_event_loop_test -- sim_loop.c's # compiled TU unconditionally references every one of those externs # regardless of which functions this file's own tests call. sched_sim_reconcile_unaccounted_test = executable( 'sched_sim_reconcile_unaccounted_test', ['test_sim_reconcile_unaccounted.c'], include_directories:[incdir], dependencies: [scheduler_test_deps], install: false) # Resource-contention replay fixture (scheduler-sim-decision-parity spec, # task 1.2, Req 2.1/2.2): existing fixtures in this directory never have # scarce capacity, so none can exercise or prove capacity-check correctness. # This file records ONE real normal-mode session (real builtin_fcfs picker + # a capacity-aware stand-in allocator that drives the REAL # sched_check_host_satisfy()/sched_charge_account()/sched_commit_job_alloc() # (resource.c) against a real, finite-capacity worker) where three jobs # compete for 10.0 units of one resource -- two dispatch, one is genuinely # denied capacity the other two, now running, are consuming. First file in # this directory to combine resource.c with the full driver/sim/recording # stack (test_resource_accounting.c, task 1.1, deliberately pairs resource.c # with only core.c -- see that file's own header comment for why). The # resulting `.replay` file is dual-use: it IS a genuine normal-mode # recording, and this file's own second test proves it is also directly # replayable via the real, unmodified simulation driver -- see this file's # own header comment for the full rationale. sched_sim_resource_contention_test = executable( 'sched_sim_resource_contention_test', ['test_sim_resource_contention.c'], include_directories:[incdir], dependencies: [scheduler_test_deps], install: false) # End-to-end integration proof for task 3 (Req 1.3/1.4, 2.1/2.2, 5.2): wires # Recorded-Decision Reconciliation (tasks 2.2-2.4) into sim_loop.c's real # round-boundary sequence, before sched_account_jobs()/xce_core_signal_go(). # Unlike every other sim_loop.c-including file in this directory, this one # links a REAL (not no-op) sched_account_jobs() reimplementation (copied # verbatim from scheduler.c) plus resource.c, so it can prove the actual # resInUse/capacity-check outcome of the wired call site against the real, # unmodified sched_sim_driver_run() -- not just that reconciliation runs in # isolation (test_sim_reconcile_unaccounted.c) or that sched_account_jobs() # is called at the right point (test_sim_session_ordering.c, via a spy). # See this file's own header comment for the full scenario and rationale. sched_sim_round_boundary_reconciliation_test = executable( 'sched_sim_round_boundary_reconciliation_test', ['test_sim_round_boundary_reconciliation.c'], include_directories:[incdir], dependencies: [scheduler_test_deps], install: false) # Regression coverage for task 4.2 (Req 4.1, 4.2): a replay starting from a # SNAPSHOT that already has a job in RUN state, with no recorded decision # for it anywhere in this replay's own window, must degrade gracefully -- # job->accounts/allocs stay NULL (unavailable, never fabricated), the run # completes cleanly (rc == 0, no --sim-verify mismatch), and a second, # ordinary job elsewhere in the same replay is still decided normally. A # different trigger shape from sched_sim_verify_test's own already-resolved- # job case (that job transitions RUN mid-replay via a JOB_STATE_CHANGE # event WITH a matching recorded DISPATCH in the same round -- reconciled, # not left unavailable): this file's job is already RUN in the INITIAL # SNAPSHOT itself, with no recorded decision anywhere in-window to # reconcile from at all, so sim_reconcile_unaccounted_jobs()'s "not found" # branch (task 2.2) is the only path that can ever touch it -- see this # file's own header comment for the full scenario and rationale. sched_sim_snapshot_reconcile_gap_test = executable( 'sched_sim_snapshot_reconcile_gap_test', ['test_sim_snapshot_reconcile_gap.c'], include_directories:[incdir], dependencies: [scheduler_test_deps], install: false) # Record-then-replay-and-diff parity proof for task 4.1 (Req 1.4, 2.1, 2.2): # extends task 1.2's resource-contention scenario (worker capacity 10.0, # jobs wanting 8.0/5.0/2.0) to an actual round-by-round comparison between a # REAL, driven normal-mode recording (this file's own Part A: real # builtin_fcfs picker + a capacity-aware allocator, same technique as # sched_sim_resource_contention_test, extended across TWO real rounds) and # a hand-crafted simulation-mode `.replay` fixture (Part B: same # JOB_STATE_CHANGE-precedes-matching-DISPATCH-decision reconciliation # trigger sched_sim_round_boundary_reconciliation_test establishes, # extended to BOTH jobs A and C together). Links a REAL (not no-op) # sched_account_jobs() reimplementation, augmented with a round-boundary # resInUse snapshot side effect, giving genuine per-round observability # into simulation mode's own accounting -- not just the final state. See # this file's own header comment for the full two-fixture design and why a # straight replay of task 1.2's own recorded file (unmodified) cannot prove # this by itself. sched_sim_contention_parity_test = executable( 'sched_sim_contention_parity_test', ['test_sim_contention_parity.c'], include_directories:[incdir], dependencies: [scheduler_test_deps], install: false) # Live-verify for task 4.3 (Req 1.1-1.3, 3.1-3.3, FINAL task of this spec): a # real, driven 24-round, 12-job, resource-constrained recording (real # builtin_fcfs picker + a capacity-aware allocator, same technique as # sched_sim_resource_contention_test/sched_sim_contention_parity_test, but # extended far past a 1-2-round toy fixture) is replayed through the real, # unmodified interactive REPL. Asserts "info worker" reports the # arithmetically-correct, nonzero used= value at four checkpoints spanning # the whole replay, and that the one job modeling "already resolved before # this replay's own live decision-making reaches it" (Recorded-Decision # Reconciliation's own designed trigger, unreachable from a purely organic # session per this file's own header comment) has its DISPATCH decision # visible in step/continue output -- bug-1611's own documented symptom, # fixed. Substitutes for the original bug-1611/bug-1613 motivating # recording (`scheduler-replay-20260820-070103.replay`), confirmed absent # from this filesystem before this file was written -- see this file's own # header comment for the full transparency note. sched_sim_e2e_original_motivation_test = executable( 'sched_sim_e2e_original_motivation_test', ['test_sim_e2e_original_motivation.c'], include_directories:[incdir], dependencies: [scheduler_test_deps], install: false) # Contract test for the interactive simulation REPL's execution-control slice # (scheduler-core spec, task 12.1, Req 5 AC 22): starting simulation with # --interactive pauses before any event is processed, and a `step N` command # advances exactly N sessions before returning control to the prompt. Same # white-box #include pattern as sched_sim_alt_events_test/sched_sim_verify_test # (core.c, core_clock.c, core_events.c, core_session.c, decision.c, plugin.c, # plugins/builtin_fcfs.c, recording.c, recording_session.c, sim.c, sim_loop.c, # sim_record.c, sim_verify.c, snapshot.c/snapshot_wire.c/snapshot_load.c) PLUS # ../src/repl.c under test. Also pulls in ../src/repl_break.c/repl_info.c # (task 12.2's 800-line-cap split of repl.c -- repl_internal.h's own "Why a # split at all") -- required at link time since sim_loop.c's new breakpoint # hooks (repl.h) reference symbols repl_break.c defines, even though this # file's own tests exercise only the execution-control slice; task 12.2's # own breakpoint/inspection tests live in the sibling # test_repl_breakpoints_inspection.c. Needs libedit_dep (parent meson.build) # at link time -- repl.c's real readline()/add_history() calls are pulled # into this TU by the white-box #include. sched_repl_execution_control_test = executable( 'sched_repl_execution_control_test', ['test_repl_execution_control.c'], include_directories:[incdir], dependencies: [scheduler_test_deps, libedit_dep], install: false) # Contract test for the interactive simulation REPL's Round Rollup # component (scheduler-sim-repl-verbosity spec, task 2.1, Requirements 2 # and 3 "per-round decision summary"/"collapsing repetitive rounds"): a # round with at least one decision produces a summary naming decision # counts and affected jobids; idle or identical-outcome consecutive rounds # collapse into a single range notification; and the shared # repl_round_collapse_flush() entry point is exercised directly (a safe # no-op when nothing is active) and indirectly (flushed before a structural # event/replay-complete banner). Same white-box #include pattern as # sched_repl_execution_control_test above (core.c, core_clock.c, # core_events.c, core_session.c, decision.c, plugin.c, # plugins/builtin_fcfs.c, recording.c, recording_session.c, sim.c, # sim_loop.c, sim_record.c, sim_verify.c, # snapshot.c/snapshot_wire.c/snapshot_load.c, repl.c, repl_break.c, # repl_info.c, repl_params.c). Split into its own file rather than appended # to test_repl_execution_control.c -- that file was already 936 lines # (pre-existing, over this project's 800-line cap on its own), and this # task's own tests (seven forked-child, real-stdout-capture fixtures plus # their own fork/capture helper pair) would have pushed it to 1563 lines, # past the ~1000-line threshold this exact spec family already treats as a # split trigger (see sched_repl_snapshot_params_test's own comment below # for the precedent). See design.md's "**Correction (post-review, task # 2.1)**" note. sched_repl_round_rollup_test = executable( 'sched_repl_round_rollup_test', ['test_repl_round_rollup.c'], include_directories:[incdir], dependencies: [scheduler_test_deps, libedit_dep], install: false) # Contract test for the interactive simulation REPL's Event Echo Gate # component (scheduler-sim-repl-verbosity spec, task 3.1, Requirements 1 and # 3.5/3.6 "mode-aware event echo"/"ending an active collapsed range"): a # routine per-tick event (e.g. QUEUE_UPDATE) produces no line under # continue-mode execution but still prints while single-stepping; a # structural event (e.g. WORKERS_PUSH) still prints under continue and # flushes any active Round Rollup collapsed range first; a breakpoint hit # still interrupts continue-mode execution regardless of the matched # event's classification, and likewise flushes any active collapsed range # before the interruption is shown. Same white-box #include pattern as # sched_repl_round_rollup_test above (core.c, core_clock.c, core_events.c, # core_session.c, decision.c, plugin.c, plugins/builtin_fcfs.c, recording.c, # recording_session.c, sim.c, sim_loop.c, sim_record.c, sim_verify.c, # snapshot.c/snapshot_wire.c/snapshot_load.c, repl.c, repl_rollup.c, # repl_break.c, repl_info.c, repl_params.c). Split into its own file rather # than appended to test_repl_execution_control.c -- that file was already # 937 lines (pre-existing, over this project's 800-line cap) before this # feature began, and this task's own four behavioral cases would have # pushed it well past 1300 lines, the same reasoning that already split # test_repl_round_rollup.c out (task 2.1) -- see design.md's own # "**Correction (post-review, task 3.1)**" note. sched_repl_event_echo_test = executable( 'sched_repl_event_echo_test', ['test_repl_event_echo.c'], include_directories:[incdir], dependencies: [scheduler_test_deps, libedit_dep], install: false) # Contract test for the interactive simulation REPL's Event Echo Preamble # Deduplicator component (scheduler-sim-step-verbosity spec, task 1.1, # Requirements 1 and 2 "collapse the repeated timestamp/session preamble # across consecutive same-context echoed events"): two consecutive echoed # events sharing the same rendered (second-granularity) timestamp and # displayed session omit the second's preamble line while still printing # its own content line; events spanning a session boundary each print their # own full preamble; two events whose raw high-resolution timestamps differ # but whose rendered timestamp and session are identical still dedupe (the # design's central "rendered value, not raw ns" nuance); the first echoed # event of a fresh REPL session always prints its preamble; the same rule # applies to a structural event echoed under `continue` mode after a # stretch of suppressed routine events; and event content/ordering stay # unaffected by the preamble decision at N=3 consecutive same-context # events. THIS TASK (1.1) IS RED-PHASE ONLY -- see this file's own header # comment. Same white-box #include pattern and forked-child/real-stdout- # capture technique as sched_repl_event_echo_test above (core.c, # core_clock.c, core_events.c, core_session.c, decision.c, plugin.c, # plugins/builtin_fcfs.c, recording.c, recording_session.c, sim.c, # sim_loop.c, sim_record.c, sim_verify.c, # snapshot.c/snapshot_wire.c/snapshot_load.c, repl.c, repl_fmt.c, # repl_rollup.c, repl_break.c, repl_info.c, repl_params.c). Split into its # own file from the start rather than appended to test_repl_event_echo.c # (705 lines before this feature) -- design.md's File Structure Plan flags # this file's ~1000-line split trigger, and this task's six behavioral # cases plus their own preamble-construction helper would have pushed it # well past that threshold; the same reasoning that already split # test_repl_round_rollup.c/test_repl_event_echo.c/test_repl_prompt_context.c/ # test_sim_print_decision_gate.c out of test_repl_execution_control.c. sched_repl_step_verbosity_test = executable( 'sched_repl_step_verbosity_test', ['test_repl_step_verbosity.c'], include_directories:[incdir], dependencies: [scheduler_test_deps, libedit_dep], install: false) # Contract test for the interactive simulation REPL's Prompt Context # component (scheduler-sim-repl-verbosity spec, task 6.1, Requirement 5.5 # "REPL prompt shows session/timestamp"): the readline() prompt is the # plain "(sim) " before any session has completed, and becomes "(sim # session= t=) " (bare rs->session_count) once at least one # session has run, in both `step` and `continue` modes, without altering # any command's own printed output. Same white-box #include pattern as # sched_repl_execution_control_test above (core.c, core_clock.c, # core_events.c, core_session.c, decision.c, plugin.c, # plugins/builtin_fcfs.c, recording.c, recording_session.c, sim.c, # sim_loop.c, sim_record.c, sim_verify.c, # snapshot.c/snapshot_wire.c/snapshot_load.c, repl.c, repl_rollup.c, # repl_break.c, repl_info.c, repl_params.c). Split into its own file rather # than appended to test_repl_execution_control.c (948 lines today, already # over this project's 800-line cap and grown past the 937-line figure # design.md's own File Structure Plan cited when it named that file as this # task's home) -- same reasoning that already split test_repl_round_ # rollup.c/test_repl_event_echo.c out; see this file's own header comment # for the full rationale, including why a pty (openpty(), ) is # required instead of this file family's usual freopen()-from-a-file # capture technique to make readline()'s prompt text observable at all. sched_repl_prompt_context_test = executable( 'sched_repl_prompt_context_test', ['test_repl_prompt_context.c'], include_directories:[incdir], dependencies: [scheduler_test_deps, libedit_dep], install: false) # Contract test for the interactive simulation REPL's `sim_print_decision` # Gate component (scheduler-sim-repl-verbosity spec, task 4.1, Requirements # 2.3, 5.1, 5.4 "retire the redundant per-decision echo during continuous # execution"): under `continue` mode, sim_print_decision()'s (sim_loop.c) # bare per-decision line must no longer appear outside the Round Rollup's # own per-round summary; `step` mode and non-interactive (headless, no -i) # batch runs are completely unaffected and keep printing that bare line # exactly as today. Same white-box #include pattern as # sched_repl_round_rollup_test/sched_repl_event_echo_test above (core.c, # core_clock.c, core_events.c, core_session.c, decision.c, plugin.c, # plugins/builtin_fcfs.c, recording.c, recording_session.c, sim.c, # sim_loop.c, sim_record.c, sim_verify.c, # snapshot.c/snapshot_wire.c/snapshot_load.c, repl.c, repl_rollup.c, # repl_break.c, repl_info.c, repl_params.c). Split into its own file rather # than extended onto either sibling: test_repl_round_rollup.c is already # 1022 lines (222 over this project's 800-line cap) on its own, and # test_repl_event_echo.c (704 lines) deliberately keeps every one of its # own fixtures job-free (bug-1595 jobid-reuse safety discipline), which # this task's decision-producing fixtures cannot follow -- see this file's # own header comment for the full rationale. sched_sim_print_decision_gate_test = executable( 'sched_sim_print_decision_gate_test', ['test_sim_print_decision_gate.c'], include_directories:[incdir], dependencies: [scheduler_test_deps, libedit_dep], install: false) # Contract test for the interactive simulation REPL's breakpoint and # state-inspection slice (scheduler-core spec, task 12.2, Req 5 AC 22 # "Breakpoints"/"State inspection"): setting a breakpoint on a specific # event type and field value pauses the REPL exactly when a matching event # is about to be processed, and each `info` command reports state matching # a snapshot dump of the same moment. Same white-box #include pattern as # sched_repl_execution_control_test above (core.c, core_clock.c, # core_events.c, core_session.c, decision.c, plugin.c, # plugins/builtin_fcfs.c, recording.c, recording_session.c, sim.c, # sim_loop.c, sim_record.c, sim_verify.c, # snapshot.c/snapshot_wire.c/snapshot_load.c, repl.c, repl_break.c, # repl_info.c). Split into its own file rather than appended to # test_repl_execution_control.c -- that file was already 644 lines after # task 12.1, and this task's own fixture/assertion surface (breakpoints on # multiple event kinds plus five separate `info` dumps) does not fit # alongside it under this project's 800-line cap. sched_repl_breakpoints_inspection_test = executable( 'sched_repl_breakpoints_inspection_test', ['test_repl_breakpoints_inspection.c'], include_directories:[incdir], dependencies: [scheduler_test_deps, libedit_dep], install: false) # Contract test for the interactive simulation REPL's Resource Value # Formatter table/grouping layout, units-mode rendering, and the Jobid # Range Compressor's adoption in `info worker`'s assigned-job listing # (scheduler-sim-repl-verbosity spec, task 8.1, Requirements 6.4, 6.5, 6.6, # 4.5). Same white-box #include pattern as # sched_repl_breakpoints_inspection_test above (core.c, core_clock.c, # core_events.c, core_session.c, decision.c, plugin.c, # plugins/builtin_fcfs.c, recording.c, recording_session.c, sim.c, # sim_loop.c, sim_record.c, sim_verify.c, # snapshot.c/snapshot_wire.c/snapshot_load.c, repl.c, repl_fmt.c, # repl_rollup.c, repl_break.c, repl_info.c, repl_params.c). Split into its # own file rather than appended to test_repl_breakpoints_inspection.c -- # landing these ten tests there per design.md's own File Structure Plan # pushed that file from 2095 to 3215 lines, well past the ~1000-line split # trigger this exact file family already established (the same reasoning # that already split test_repl_round_rollup.c/test_repl_event_echo.c out; # see this file's own header comment for the full rationale). sched_repl_resource_table_test = executable( 'sched_repl_resource_table_test', ['test_repl_resource_table.c'], include_directories:[incdir], dependencies: [scheduler_test_deps, libedit_dep], install: false) # Contract test for the interactive simulation REPL's Help & Breakpoint # Discoverability component (scheduler-sim-repl-verbosity spec, task 9.1, # Requirements 7.1-7.4): `help`'s listing groups commands into four labeled # sections in a fixed order, aligns every command's description to one # consistent column position throughout, lists `info config` together with # its `info` siblings in the state-inspection section, lists `set units` # alongside `set speed`/`set output`/`set verify` in the snapshot-and- # parameters section, and enumerates the complete BP_KIND_TABLE event-type # set on the `break` line. Same white-box #include pattern as # sched_repl_resource_table_test above (core.c, core_clock.c, core_events.c, # core_session.c, decision.c, plugin.c, plugins/builtin_fcfs.c, recording.c, # recording_session.c, sim.c, sim_loop.c, sim_record.c, sim_verify.c, # snapshot.c/snapshot_wire.c/snapshot_load.c, repl.c, repl_fmt.c, # repl_rollup.c, repl_break.c, repl_info.c, repl_params.c) even though this # file's own tests call only repl_print_help() directly -- no # xce_sched_sim_driver_t/replay fixture needed. Split into its own file # rather than appended to test_repl_execution_control.c -- that file was # already 949 lines (pre-existing, over this project's 800-line cap) before # this task began; landing this task's own section/column/discoverability # tests there would have pushed it well past the ~1000-line split trigger # this exact file family already established (the same reasoning that split # test_repl_round_rollup.c/test_repl_event_echo.c/test_repl_resource_table.c # out of their own siblings). `break`'s own unrecognized-event-type error # message test (Requirement 7.5) lives in # test_repl_breakpoints_inspection.c instead, per design.md's own file- # placement guidance for this component. sched_repl_help_test = executable( 'sched_repl_help_test', ['test_repl_help.c'], include_directories:[incdir], dependencies: [scheduler_test_deps, libedit_dep], install: false) # Contract test for the interactive simulation REPL's snapshot-capture and # simulation-parameter command slice (scheduler-core spec, task 12.3, Req 5 # AC 22 "Snapshots"/"Simulation parameters"): `snapshot [FILE]` writes a # standalone .replay file a FRESH sched_sim_driver_start() can load, landing # on the exact position the snapshot was taken at (the task's own central # Observable, proved end to end via a forked child + a second, real # sched_sim_driver_start() call in the parent); `set speed`/`set output`/ # `set verify` mutate the parameters `info config` reports. Same white-box # #include pattern as sched_repl_breakpoints_inspection_test above (core.c, # core_clock.c, core_events.c, core_session.c, decision.c, plugin.c, # plugins/builtin_fcfs.c, recording.c, recording_session.c, sim.c, # sim_loop.c, sim_record.c, sim_verify.c, # snapshot.c/snapshot_wire.c/snapshot_load.c, repl.c, repl_break.c, # repl_info.c) PLUS the new ../src/repl_params.c under test. Split into its # own file rather than appended to test_repl_breakpoints_inspection.c -- # that file was already over 1000 lines after task 12.2, and this task's # own fixture/assertion surface (a fork+reload round-trip plus five # further unit-level command tests) does not belong crammed into it. sched_repl_snapshot_params_test = executable( 'sched_repl_snapshot_params_test', ['test_repl_snapshot_params.c'], include_directories:[incdir], dependencies: [scheduler_test_deps, libedit_dep], install: false) # Contract test for REPL step/continue-to-completion vs batch simulation # equivalence (scheduler-core spec, task 12.4, Req 5 AC 22 "Deterministic # replay is preserved"): running a fixture through the REPL via a scripted # `step`/`continue` command sequence to completion must produce the SAME # decision sequence as running the identical fixture through batch # (non-interactive) simulation mode. Unlike task 11.6's # test_sim_equivalence.c (which compares the NORMAL-mode driver against the # SIMULATION driver), this compares the SAME sched_sim_driver_run() against # itself, differing only in `sim->interactive` -- proving the REPL only # controls WHEN events are processed, never WHAT. Same white-box #include # pattern as sched_repl_execution_control_test (core.c, core_clock.c, # core_events.c, core_session.c, decision.c, plugin.c, # plugins/builtin_fcfs.c, recording.c, recording_session.c, sim.c, # sim_loop.c, sim_record.c, sim_verify.c, # snapshot.c/snapshot_wire.c/snapshot_load.c, repl.c, repl_break.c, # repl_info.c, repl_params.c) -- no driver.c: both runs are pure # simulation-driver replays of one hand-built fixture, never a real # normal-mode recording session. sched_repl_equivalence_test = executable( 'sched_repl_equivalence_test', ['test_repl_equivalence.c'], include_directories:[incdir], dependencies: [scheduler_test_deps, libedit_dep], install: false) # Contract test for the REPL's job-identifier range compressor # (scheduler-sim-repl-verbosity spec, task 1.1/1.2, Requirement 4). # repl_fmt_jobid_range() lives in ../src/repl.c (design.md's File Structure # Plan: "implements the new shared jobid-range-compression helper ... in # repl.c"), but repl.c's own dependency surface is too large for the lean # "#include the one file under test" pattern the other lightweight REPL # tests use (test_repl_output_compression.c declares repl_fmt_jobid_range() # as a plain extern rather than #include-ing repl.c -- see that file's own # header comment: repl.c's repl_dispatch() references repl_cmd_break/ # repl_cmd_info/repl_cmd_set/... from sibling files repl_break.c/ # repl_info.c/repl_params.c, and a directly-linked .o -- unlike an archive # member -- requires ALL its undefined symbols resolved regardless of # whether the calling code path is ever exercised). So instead this target # links the real scheduler_srcs object list, the same technique # sched_scheduler_connect_test below established for the identical "real # production dependency surface, avoid textual inclusion" problem. # scheduler_srcs (parent meson.build) minus src/main.c (this test file # supplies its own main()) -- built via a loop, same as # scheduler_connect_test_srcs below, so it can never drift from the # production source list. No `-Wl,--wrap=` or `-DXCE_SCHEDULER_C_PATH` is # needed here: this test never calls sched_init() or reaches networking # code, it only exercises the pure repl_fmt_jobid_range() formatter. repl_output_compression_test_srcs = ['test_repl_output_compression.c'] foreach f : scheduler_srcs if f != 'src/main.c' repl_output_compression_test_srcs += ['../' + f] endif endforeach sched_repl_output_compression_test = executable( 'sched_repl_output_compression_test', repl_output_compression_test_srcs, include_directories:[incdir], dependencies: [scheduler_deps, unity_dep], install: false) # Contract test for the REPL's resource-value byte/megabyte classification # and adaptive human-scaling helpers (scheduler-sim-repl-verbosity spec, task # 7.1, Requirement 6.1/6.2 "Human-Readable Resource Value Formatting"). # repl_is_bytes_valued_resource()/repl_format_bytes_human() are pure, # self-contained formatters (design.md's "Resource Value Formatter" # component) that -- like repl_fmt_jobid_range() above -- do not yet exist # anywhere in this codebase (task 7.2, a separate later task, implements # them); this test file declares them as plain externs rather than # #include-ing repl.c, same rationale as # repl_output_compression_test_srcs above (repl.c's own dependency surface # pulls in undefined cross-references to sibling files this test does not # need). Same "link the real scheduler_srcs object list instead of textually # including one" technique, for the identical reason: task 7.2 has not # landed yet, so this target is expected to fail at LINK time (undefined # reference to both symbols) until it does -- that failure is task 7.1's own # Observable evidence. repl_resource_formatting_test_srcs = ['test_repl_resource_formatting.c'] foreach f : scheduler_srcs if f != 'src/main.c' repl_resource_formatting_test_srcs += ['../' + f] endif endforeach sched_repl_resource_formatting_test = executable( 'sched_repl_resource_formatting_test', repl_resource_formatting_test_srcs, include_directories:[incdir], dependencies: [scheduler_deps, unity_dep], install: false) # Tests for the scheduler's unified candidate-list connect/rejoin pipeline # (component-failover-adoption, task 3.1, boundary: SchedulerControllerClient). # Unlike the white-box #include-the-.c-file tests above, this target links # the REAL scheduler_srcs (everything sched_init() needs -- core.c, # schedobj.c, resource.c, plugin.c, the picker/allocator plugins, etc.) and # calls the real, public sched_init()/sched_fini(): scheduler.c's own # dependency surface is too large for whole-file inclusion (same "too many # externals to stub" reasoning sched_picker_core_loop_boundary_test's own # comment already gives for not #include-ing scheduler.c), so this avoids # that by linking the real objects instead of textually including one. # scheduler_srcs (defined in the parent meson.build) minus src/main.c (this # test file supplies its own main()) -- built via a loop rather than a # hand-duplicated list so it can never drift from the production source list. scheduler_connect_test_srcs = ['test_scheduler_connect.c'] foreach f : scheduler_srcs if f != 'src/main.c' scheduler_connect_test_srcs += ['../' + f] endif endforeach sched_scheduler_connect_test = executable( 'sched_scheduler_connect_test', scheduler_connect_test_srcs, include_directories:[incdir], dependencies: [scheduler_deps, unity_dep], c_args: ['-DXCE_SCHEDULER_C_PATH="' + (meson.current_source_dir() / '..' / 'src' / 'scheduler.c') + '"'], install: false) # Tests for the scheduler's decision-publish retry-until-success-or-shutdown # wrapper, composed with rejoin retry-on-failure (component-failover-adoption, # task 3.2, boundary: SchedulerControllerClient). scheduler.c IS the file # under test here (sched_publish_dispatch()/sched_publish_pend_reason()), so # unlike sched_driver_decision_cb_test this target cannot spy on those two # functions directly. Same real-scheduler_srcs link technique as # sched_scheduler_connect_test above (reused scheduler_connect_test_srcs # list), PLUS `-Wl,--wrap=` linker symbol interposition on the three libxce # client calls this task's retry/rejoin logic makes (xcecli_jobdispatch, # xcecli_set_pend_reason, xcecli_join) and two more needed only to let this # file's one real sched_init() setup call reach xcecli_set_reconnect_handler() # without a live controller (xcecli_start, xcecli_set_reconnect_handler) -- # see the test file's own header comment for why `--wrap` (which redirects # call sites, not archive members) was required instead of the "test double # ahead of the archive" trick: all of these symbols share client.c's single # translation unit inside libxce.a with several OTHER xcecli_* entry points # this test's real scheduler_srcs dependency graph also needs, so simply # excluding client.c from the link was not viable. scheduler_decision_publish_retry_test_srcs = [ 'test_scheduler_decision_publish_retry.c'] foreach f : scheduler_srcs if f != 'src/main.c' scheduler_decision_publish_retry_test_srcs += ['../' + f] endif endforeach sched_scheduler_decision_publish_retry_test = executable( 'sched_scheduler_decision_publish_retry_test', scheduler_decision_publish_retry_test_srcs, include_directories:[incdir], dependencies: [scheduler_deps, unity_dep], c_args: ['-DXCE_MAIN_C_PATH="' + (meson.current_source_dir() / '..' / 'src' / 'main.c') + '"'], link_args: ['-Wl,--wrap=xcecli_jobdispatch', '-Wl,--wrap=xcecli_set_pend_reason', '-Wl,--wrap=xcecli_join', '-Wl,--wrap=xcecli_start', '-Wl,--wrap=xcecli_set_reconnect_handler', '-Wl,--wrap=xcecli_is_connection_broken'], install: false) # Worst-case decision/allocation backpressure test (component-failover- # adoption, task 3.3, boundary: SchedulerControllerClient, Req 3 AC2 / Req # 7). Same real-scheduler_srcs link technique as the two targets above, PLUS # `-Wl,--wrap=` on xcecli_start/xcecli_join (forced to succeed with no I/O, # so this file's one real sched_init() call actually starts the picker/ # allocator threads) and xcecli_set_pend_reason (blocks on a test-controlled # condvar, standing in for a stuck outage retry) -- see the test file's own # header comment for the full design and worst-case derivation. scheduler_backpressure_test_srcs = ['test_scheduler_backpressure.c'] foreach f : scheduler_srcs if f != 'src/main.c' scheduler_backpressure_test_srcs += ['../' + f] endif endforeach sched_scheduler_backpressure_test = executable( 'sched_scheduler_backpressure_test', scheduler_backpressure_test_srcs, include_directories:[incdir], dependencies: [scheduler_deps, unity_dep], link_args: ['-Wl,--wrap=xcecli_start', '-Wl,--wrap=xcecli_join', '-Wl,--wrap=xcecli_set_pend_reason'], install: false) # Queue-level decision-redelivery test coverage (component-failover-adoption, # task 3.4, boundary: SchedulerControllerClient, Req 7). Proves task 3.2's # retry-until-success-or-shutdown wrapper's guarantees hold across MULTIPLE # queued decisions drained through the real xce_sched_driver_on_decision() # (driver.c), not just a single isolated call (already covered by # test_scheduler_decision_publish_retry.c). Same real-scheduler_srcs link # technique as the targets above, but only xcecli_jobdispatch() needs # wrapping here -- these fixtures use xce_sched_core_init() directly (not # sched_init()), so sched_needs_rejoin is never set and # sched_publish_check_rejoin() never reaches xcecli_join(). Also needs # driver.c's absolute path (XCE_DRIVER_C_PATH) alongside scheduler.c's # (XCE_SCHEDULER_C_PATH, same pattern as sched_scheduler_connect_test) for # its Req 7 AC5 source-text scan. scheduler_decision_redelivery_test_srcs = [ 'test_scheduler_decision_redelivery.c'] foreach f : scheduler_srcs if f != 'src/main.c' scheduler_decision_redelivery_test_srcs += ['../' + f] endif endforeach sched_scheduler_decision_redelivery_test = executable( 'sched_scheduler_decision_redelivery_test', scheduler_decision_redelivery_test_srcs, include_directories:[incdir], dependencies: [scheduler_deps, unity_dep], c_args: ['-DXCE_SCHEDULER_C_PATH="' + (meson.current_source_dir() / '..' / 'src' / 'scheduler.c') + '"', '-DXCE_DRIVER_C_PATH="' + (meson.current_source_dir() / '..' / 'src' / 'driver.c') + '"'], link_args: ['-Wl,--wrap=xcecli_jobdispatch'], install: false) # scheduler-dispatch-commit spec, task 2.1 (Req 1.1/1.2/1.3): proves # sched_commit_decision()'s DISPATCH branch transitions job->state to # JOB_STAT_RUN in the same operation that already commits job->allocs/ # job->accounts. Same real-scheduler_srcs link technique as # sched_scheduler_connect_test above, but no `-Wl,--wrap=` is needed: this # file never calls sched_init()/sched_fini(), so none of the xcecli_* calls # those make are ever reached. scheduler_dispatch_commit_test_srcs = ['test_scheduler_dispatch_commit.c'] foreach f : scheduler_srcs if f != 'src/main.c' scheduler_dispatch_commit_test_srcs += ['../' + f] endif endforeach sched_scheduler_dispatch_commit_test = executable( 'sched_scheduler_dispatch_commit_test', scheduler_dispatch_commit_test_srcs, include_directories:[incdir], dependencies: [scheduler_deps, unity_dep], install: false) # scheduler-snapshot-job-allocation spec, task 4.1 (Req 2 AC 2/AC 4): direct # regression test proving a PENDING job restored via the real # xce_sched_core_load_snapshot() (task 1.2's job->schedobj fix) reaches the # scheduler's REAL allocator entry point (sched_make_allocation(), # `static` to scheduler.c) without crashing -- the exact bug-1569-class # failure shape this feature closes. Same real-scheduler_srcs link # technique as sched_scheduler_connect_test/sched_scheduler_backpressure_test # above (see this test file's own header comment for why extending # test_snapshot_save_load.c's existing white-box #include of core.c/ # core_events.c/.../snapshot_load.c with ALSO #include-ing scheduler.c was # ruled out: scheduler.c's dependency surface is exactly the "link-surface # reason" test_scheduler_connect.c's own header comment already documents # for not white-box #include-ing it anywhere in this directory). Only # `-Wl,--wrap=` needed is xcecli_start/xcecli_join (trivial always-succeed # doubles, identical to sched_scheduler_backpressure_test's own), so this # file's one real sched_init() call succeeds with no live controller and # starts the real picker/allocator threads. scheduler_snapshot_load_allocator_regression_test_srcs = [ 'test_snapshot_load_allocator_regression.c'] foreach f : scheduler_srcs if f != 'src/main.c' scheduler_snapshot_load_allocator_regression_test_srcs += ['../' + f] endif endforeach sched_snapshot_load_allocator_regression_test = executable( 'sched_snapshot_load_allocator_regression_test', scheduler_snapshot_load_allocator_regression_test_srcs, include_directories:[incdir], dependencies: [scheduler_deps, unity_dep], link_args: ['-Wl,--wrap=xcecli_start', '-Wl,--wrap=xcecli_join'], install: false) # White-box regression test for bug-1685 (double-free/heap-corruption # SIGABRT in limit_update_config() on a duplicate limit-name config # update). It #includes ../src/plugins/limit.c directly (same white-box # pattern as sched_picker_registration_test) so it exercises the real # limit_update_config()/limit_init()/limit_priv_data_init() -- all # `static`, otherwise unreachable from a test binary -- not a # re-implementation of any of them. Stubs reset_sched_obj()/get_resvals()/ # put_resvals() (scheduler/src, not part of this TU) purely to satisfy the # linker for limit.c code paths this test never exercises -- see the # file's own header comment. sched_limit_plugin_test = executable('sched_limit_plugin_test', ['test_limit_plugin.c'], include_directories:[incdir], dependencies: [scheduler_test_deps], install: false) # White-box regression test for bug-1686 (live SIGSEGV in # fcfs_cursor_enter_queue() <- builtin_fcfs_next_job(), a heap-use-after-free # on priv->cursor/job_cursor -- raw ordq_item_t* values that persist across # separate next_job() calls and can be freed in between by a properly-locked # on_queue_update() re-sort of the same queue). It #includes # ../src/plugins/builtin_fcfs.c directly (same white-box pattern as # sched_picker_fcfs_session_test) so it exercises the real cursor logic and # the real private fcfs_plugin_data_t layout -- including direct field # access to priv->cursor/priv->job_cursor, which only a white-box #include # gives a test -- not a re-implementation of any of it. Supplies its own # always-ready sched_queue_is_ready()/sched_job_is_ready() test doubles and a # plugin_register() stub, same convention as sched_picker_fcfs_session_test. sched_builtin_fcfs_cursor_uaf_test = executable( 'sched_builtin_fcfs_cursor_uaf_test', ['test_builtin_fcfs_cursor_uaf.c'], include_directories:[incdir], dependencies: [scheduler_test_deps], install: false) # Contract test for the lazy allocation-plan and host-candidate iterator # interfaces (scheduler-allocation spec, task 1.1, Req 2 AC 1-6 / Req 3 AC # 1-6). Only #includes the new ../include/sched/alloc_iter.h -- no # allocator is wired onto these interfaces yet (parjob_allocator/ # seqjob_allocator rewrap is later tasks' own work). Proves the contract # shape compiles and is usable via a trivial, no-op reference # implementation of each interface, stack-allocated and initialized in # place per the documented convention, driven through a full # init()/next()/fini() cycle -- including the exact plan -> per-bucket # fresh-host_iter composition shape requirements.md's Composition # Algorithm describes for allocate_primary() (Req 3 AC 4 / Req 4 AC 2). sched_alloc_plan_iter_test = executable( 'sched_alloc_plan_iter_test', ['test_alloc_plan_iter.c'], include_directories:[incdir], dependencies: [scheduler_test_deps], install: false) # Contract + behavioral test for the one shared xce_host_iter_t # implementation (scheduler-allocation spec, task 2.1, Req 3 AC 1-6). Unlike # sched_alloc_plan_iter_test's own trivial no-op stubs, this drives the REAL # ../src/host_iter.c against real fixture state -- select-expression # filtering, availability filtering, exhaustion, the fresh-per-bucket # adversarial case (a host too small for one search remains a valid # candidate for a later, smaller search over a freshly-initialized # instance), and a behavioral proof of the required pthread_testcancel() # cancellation point. Same white-box #include pattern as # test_resource_accounting.c (../src/core.c, ../src/resource.c, # ../src/schedobj.c) PLUS the new ../src/host_iter.c under test. sched_host_iter_test = executable( 'sched_host_iter_test', ['test_host_iter.c'], include_directories:[incdir], dependencies: [scheduler_test_deps], install: false) # Unit test for the session-level unsatisfiable-resreq cache # (scheduler-allocation spec, task 2.2, Req 7.1, 7.3, 7.4, 7.5). White-box # TU (#includes ../src/alloc_cache.c directly, same convention as # sched_host_iter_test above) -- never touches xce_sched_core_init(), since # alloc_cache.c only depends on kv.h + scheduler.h/sched/types.h struct # definitions, not on core.c's collections. Covers: same-key-twice hit # (the cache_key_cmp_() three-way-vs-boolean polarity regression guard), # a miss on every individually-differing fingerprint/identity field, # reason-category round-trip across two distinct categories, and # clear-empties-all-entries. sched_alloc_cache_test = executable( 'sched_alloc_cache_test', ['test_alloc_cache.c'], include_directories:[incdir], dependencies: [scheduler_test_deps], install: false) # Task 3.1 (scheduler-allocation spec, Req 9.1, 4.6): seqjob_allocator.c's # rewrap onto the shared plan_iter/host_iter interfaces, plus the new # maxTasks==1 guard on seqjob_prepare_allocation() (Req 4.6). Same # white-box #include pattern as sched_host_iter_test above (../src/core.c, # ../src/resource.c, ../src/schedobj.c, ../src/host_iter.c) PLUS # ../src/plugins/seqjob_allocator.c itself, the file under test. Smoke- # level coverage only -- the exhaustive pre/post-rewrap equivalence proof # is task 3.2's dedicated sched_seqjob_rewrap_equivalence_test. sched_seqjob_allocator_test = executable( 'sched_seqjob_allocator_test', ['test_seqjob_allocator.c'], include_directories:[incdir], dependencies: [scheduler_test_deps], install: false) # Register as meson tests so `meson test --suite scheduler` runs them all. # detect_leaks=0 matches the suite convention (fixtures are not torn down). test('scheduler test', scheduler_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler job-update test', sched_job_update_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler handlers test', sched_handlers_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler job-array expand test', sched_job_array_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler job-array wire e2e test', sched_job_array_wire_e2e_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler picker iface test', sched_picker_iface_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler picker registration test', sched_picker_registration_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler picker config fields test', sched_picker_config_fields_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler picker fcfs test', sched_picker_fcfs_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler picker fcfs session test', sched_picker_fcfs_session_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler picker wiring test', sched_picker_wiring_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler picker core loop boundary test', sched_picker_core_loop_boundary_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler pendreason factory audit test', sched_pendreason_factory_audit_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler core isolation test', sched_core_isolation_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler no bare printf test', sched_no_bare_printf_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler core jbuf capacity pin test', sched_core_jbuf_capacity_pin_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler core events test', sched_core_events_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler core session test', sched_core_session_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler core clock test', sched_core_clock_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler core full cycle test', sched_core_full_cycle_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler driver translate test', sched_driver_translate_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler resval ownership test', sched_resval_ownership_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler driver decision cb test', sched_driver_decision_cb_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler driver session ordering test', sched_driver_session_ordering_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler resource accounting test', sched_resource_accounting_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler snapshot save load test', sched_snapshot_save_load_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler recording path validation test', sched_recording_path_validation_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler record lifecycle test', sched_record_lifecycle_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler admin request test', sched_admin_request_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler sim startup test', sched_sim_startup_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler sim event loop test', sched_sim_event_loop_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler sim isolation test', sched_sim_isolation_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler sim verify test', sched_sim_verify_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler sim alt events test', sched_sim_alt_events_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler sim record output test', sched_sim_record_output_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler sim equivalence test', sched_sim_equivalence_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler sim session ordering test', sched_sim_session_ordering_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler sim reconcile unaccounted test', sched_sim_reconcile_unaccounted_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler sim resource contention test', sched_sim_resource_contention_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler sim round boundary reconciliation test', sched_sim_round_boundary_reconciliation_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler sim snapshot reconcile gap test', sched_sim_snapshot_reconcile_gap_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler sim contention parity test', sched_sim_contention_parity_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler sim e2e original motivation test', sched_sim_e2e_original_motivation_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler repl execution control test', sched_repl_execution_control_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler repl round rollup test', sched_repl_round_rollup_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler repl event echo test', sched_repl_event_echo_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler repl step verbosity test', sched_repl_step_verbosity_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler repl prompt context test', sched_repl_prompt_context_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler sim print decision gate test', sched_sim_print_decision_gate_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler repl breakpoints inspection test', sched_repl_breakpoints_inspection_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler repl resource table test', sched_repl_resource_table_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler repl help test', sched_repl_help_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler repl snapshot params test', sched_repl_snapshot_params_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler repl equivalence test', sched_repl_equivalence_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler repl output compression test', sched_repl_output_compression_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler repl resource formatting test', sched_repl_resource_formatting_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler connect pipeline test', sched_scheduler_connect_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler decision publish retry test', sched_scheduler_decision_publish_retry_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler backpressure test', sched_scheduler_backpressure_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler decision redelivery test', sched_scheduler_decision_redelivery_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler dispatch commit test', sched_scheduler_dispatch_commit_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler snapshot load allocator regression test', sched_snapshot_load_allocator_regression_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler limit plugin test', sched_limit_plugin_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler builtin fcfs cursor uaf test', sched_builtin_fcfs_cursor_uaf_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler alloc plan iter test', sched_alloc_plan_iter_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler host iter test', sched_host_iter_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler alloc cache test', sched_alloc_cache_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) test('scheduler seqjob allocator test', sched_seqjob_allocator_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0'])