scheduler_test_src = [ 'test.c', ] scheduler_test_deps = [libxce_deps, librtti_dep, unity_dep, libxce_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_LIB_PATH="' + sched_core_isolation_lib.full_path() + '"'], 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) # 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, # xce_scheduler_t*-coupled, 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 xce_scheduler_t*-coupled collaborator" rationale # test_driver_decision_cb.c/test_driver_translate.c already established for # 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) # 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) # 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 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 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 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'])