Add xce_job_picker_iface_t to plugin.h with all 13 hooks across lifecycle/state-change/session/post-allocation/optional categories, matching design.md's literal struct. Documents per-category thread assignment, next_job() cancel-safety, and begin_session() session-reset requirements. Forward-declares xce_sched_core_t (built in a later task). Requirements: 1.2, 1.5, 2.6
227 lines
7.6 KiB
C
227 lines
7.6 KiB
C
/*
|
|
* test_picker_iface.c - standalone compile-check test for the job picker
|
|
* plugin contract, xce_job_picker_iface_t (scheduler-core spec, task 1.1).
|
|
*
|
|
* This task only adds a header (plugin.h) -- there is no picker
|
|
* implementation yet (that lands in task 2.x, builtin_fcfs). So the
|
|
* red/green evidence for this task is a *compile-time* contract check, not
|
|
* a runtime behavior check:
|
|
*
|
|
* RED: before xce_job_picker_iface_t existed in plugin.h, this file
|
|
* failed to compile (unknown type xce_job_picker_iface_t).
|
|
* GREEN: with the header in place, every hook category from Req 1 AC 2
|
|
* (lifecycle, state-change, session, post-allocation, optional)
|
|
* is present with the exact signature design.md specifies, and a
|
|
* correctly-typed function pointer can be assigned to every
|
|
* field without an incompatible-pointer-type diagnostic. This
|
|
* test target builds with -Werror=incompatible-pointer-types
|
|
* (see testsuite/meson.build) specifically so a signature drift
|
|
* in plugin.h fails the build, not just this assertion file.
|
|
*
|
|
* Each stub below is intentionally typed via an explicit named function
|
|
* pointer variable of the exact field type (copied from plugin.h) before
|
|
* being stored into the struct literal -- that forces the compiler to
|
|
* check the stub's signature against the interface's declared signature
|
|
* at the point of assignment, which is the property this test exists to
|
|
* verify.
|
|
*/
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
|
|
#include <unity/unity.h>
|
|
|
|
#include "plugin.h"
|
|
|
|
/* ---- lifecycle hooks ---- */
|
|
static int stub_init(void* picker, xce_sched_core_t* core)
|
|
{
|
|
(void)picker;
|
|
(void)core;
|
|
return 0;
|
|
}
|
|
|
|
static void stub_fini(void* picker) { (void)picker; }
|
|
|
|
/* ---- session hooks ---- */
|
|
static int stub_begin_session(void* picker)
|
|
{
|
|
(void)picker;
|
|
return 0;
|
|
}
|
|
|
|
static xce_sched_job_t* stub_next_job(void* picker)
|
|
{
|
|
(void)picker;
|
|
return NULL;
|
|
}
|
|
|
|
static int stub_end_session(void* picker)
|
|
{
|
|
(void)picker;
|
|
return 0;
|
|
}
|
|
|
|
/* ---- post-allocation hooks ---- */
|
|
static int stub_on_dispatch(void* picker, uint64_t jobid)
|
|
{
|
|
(void)picker;
|
|
(void)jobid;
|
|
return 0;
|
|
}
|
|
|
|
static int stub_on_pend(void* picker, uint64_t jobid)
|
|
{
|
|
(void)picker;
|
|
(void)jobid;
|
|
return 0;
|
|
}
|
|
|
|
/* ---- state-change hooks ---- */
|
|
static int stub_on_queue_update(void* picker, xce_sched_queue_t* queue)
|
|
{
|
|
(void)picker;
|
|
(void)queue;
|
|
return 0;
|
|
}
|
|
|
|
static int stub_on_job_push(void* picker, xce_sched_job_t* job)
|
|
{
|
|
(void)picker;
|
|
(void)job;
|
|
return 0;
|
|
}
|
|
|
|
static int stub_on_job_state_change(void* picker, xce_sched_job_t* job,
|
|
uint32_t state)
|
|
{
|
|
(void)picker;
|
|
(void)job;
|
|
(void)state;
|
|
return 0;
|
|
}
|
|
|
|
static int stub_on_job_update(void* picker, xce_sched_job_t* job)
|
|
{
|
|
(void)picker;
|
|
(void)job;
|
|
return 0;
|
|
}
|
|
|
|
/* ---- optional hooks (MAY be NULL) ---- */
|
|
static int stub_on_config(void* picker, xce_conf4sched_t* config)
|
|
{
|
|
(void)picker;
|
|
(void)config;
|
|
return 0;
|
|
}
|
|
|
|
static int stub_on_job_rusage(void* picker, xce_sched_job_t* job,
|
|
xce_job_rusages_t* rusages)
|
|
{
|
|
(void)picker;
|
|
(void)job;
|
|
(void)rusages;
|
|
return 0;
|
|
}
|
|
|
|
void setUp(void) { return; }
|
|
void tearDown(void) { return; }
|
|
|
|
/* Assigns every hook through an explicitly-typed intermediate function
|
|
* pointer -- see file header comment. If any field's declared signature in
|
|
* plugin.h drifted from the stub below, this would fail to compile
|
|
* (incompatible-pointer-types, -Werror'd for this target). */
|
|
static void test_picker_iface_has_every_hook_with_correct_signature(void)
|
|
{
|
|
int (*init_fn)(void*, xce_sched_core_t*) = stub_init;
|
|
void (*fini_fn)(void*) = stub_fini;
|
|
int (*begin_session_fn)(void*) = stub_begin_session;
|
|
xce_sched_job_t* (*next_job_fn)(void*) = stub_next_job;
|
|
int (*end_session_fn)(void*) = stub_end_session;
|
|
int (*on_dispatch_fn)(void*, uint64_t) = stub_on_dispatch;
|
|
int (*on_pend_fn)(void*, uint64_t) = stub_on_pend;
|
|
int (*on_queue_update_fn)(void*, xce_sched_queue_t*) = stub_on_queue_update;
|
|
int (*on_job_push_fn)(void*, xce_sched_job_t*) = stub_on_job_push;
|
|
int (*on_job_state_change_fn)(void*, xce_sched_job_t*, uint32_t)
|
|
= stub_on_job_state_change;
|
|
int (*on_job_update_fn)(void*, xce_sched_job_t*) = stub_on_job_update;
|
|
int (*on_config_fn)(void*, xce_conf4sched_t*) = stub_on_config;
|
|
int (*on_job_rusage_fn)(void*, xce_sched_job_t*, xce_job_rusages_t*)
|
|
= stub_on_job_rusage;
|
|
|
|
xce_job_picker_iface_t iface = {
|
|
.init = init_fn,
|
|
.fini = fini_fn,
|
|
.begin_session = begin_session_fn,
|
|
.next_job = next_job_fn,
|
|
.end_session = end_session_fn,
|
|
.on_dispatch = on_dispatch_fn,
|
|
.on_pend = on_pend_fn,
|
|
.on_queue_update = on_queue_update_fn,
|
|
.on_job_push = on_job_push_fn,
|
|
.on_job_state_change = on_job_state_change_fn,
|
|
.on_job_update = on_job_update_fn,
|
|
.on_config = on_config_fn,
|
|
.on_job_rusage = on_job_rusage_fn,
|
|
};
|
|
|
|
/* MUST hooks are all non-NULL when populated. */
|
|
TEST_ASSERT_NOT_NULL(iface.init);
|
|
TEST_ASSERT_NOT_NULL(iface.fini);
|
|
TEST_ASSERT_NOT_NULL(iface.begin_session);
|
|
TEST_ASSERT_NOT_NULL(iface.next_job);
|
|
TEST_ASSERT_NOT_NULL(iface.end_session);
|
|
TEST_ASSERT_NOT_NULL(iface.on_dispatch);
|
|
TEST_ASSERT_NOT_NULL(iface.on_pend);
|
|
TEST_ASSERT_NOT_NULL(iface.on_queue_update);
|
|
TEST_ASSERT_NOT_NULL(iface.on_job_push);
|
|
TEST_ASSERT_NOT_NULL(iface.on_job_state_change);
|
|
TEST_ASSERT_NOT_NULL(iface.on_job_update);
|
|
|
|
/* Optional hooks are populated here (proving the signature compiles),
|
|
* but the contract (Req 1 AC 2) is that they MAY be NULL -- exercised
|
|
* by the next test. */
|
|
TEST_ASSERT_NOT_NULL(iface.on_config);
|
|
TEST_ASSERT_NOT_NULL(iface.on_job_rusage);
|
|
|
|
/* Confirm the assignment actually stored the intended function, not
|
|
* merely "a" function -- pins the test to the real symbols above. */
|
|
TEST_ASSERT_EQUAL_PTR(stub_init, iface.init);
|
|
TEST_ASSERT_EQUAL_PTR(stub_next_job, iface.next_job);
|
|
TEST_ASSERT_EQUAL_PTR(stub_on_job_state_change, iface.on_job_state_change);
|
|
}
|
|
|
|
/* Req 1 AC 2: on_config and on_job_rusage are the two hooks explicitly
|
|
* documented "MAY be NULL". A picker that doesn't need them (e.g. FCFS)
|
|
* must be able to leave them unset. */
|
|
static void test_picker_iface_optional_hooks_may_be_null(void)
|
|
{
|
|
xce_job_picker_iface_t iface = {
|
|
.init = stub_init,
|
|
.fini = stub_fini,
|
|
.begin_session = stub_begin_session,
|
|
.next_job = stub_next_job,
|
|
.end_session = stub_end_session,
|
|
.on_dispatch = stub_on_dispatch,
|
|
.on_pend = stub_on_pend,
|
|
.on_queue_update = stub_on_queue_update,
|
|
.on_job_push = stub_on_job_push,
|
|
.on_job_state_change = stub_on_job_state_change,
|
|
.on_job_update = stub_on_job_update,
|
|
.on_config = NULL,
|
|
.on_job_rusage = NULL,
|
|
};
|
|
|
|
TEST_ASSERT_NULL(iface.on_config);
|
|
TEST_ASSERT_NULL(iface.on_job_rusage);
|
|
/* MUST hooks stay required even when the optional ones are absent. */
|
|
TEST_ASSERT_NOT_NULL(iface.next_job);
|
|
}
|
|
|
|
int main(void)
|
|
{
|
|
UNITY_BEGIN();
|
|
RUN_TEST(test_picker_iface_has_every_hook_with_correct_signature);
|
|
RUN_TEST(test_picker_iface_optional_hooks_may_be_null);
|
|
return UNITY_END();
|
|
}
|