diff --git a/src/scheduler/src/resource.c b/src/scheduler/src/resource.c index 1ebdbf70..c7a814b6 100644 --- a/src/scheduler/src/resource.c +++ b/src/scheduler/src/resource.c @@ -179,8 +179,35 @@ free_host_eval_ctx(host_eval_ctx_t* ctx) int sched_meet_host_selection(xce_scheduler_t* sched, xce_sched_worker_t* w, xce_select_t* s) { - /* FIXME: add real work later */ - return 1; + (void)sched; + + if (s == NULL || s->root == NULL) return 1; + + int num_res = (int)w->resvals.caps; + + /* When num_res == 0, build_host_eval_ctx returns NULL (no resource slots). + * Use an empty stack-allocated context so eval_select_simple can still + * evaluate constant sub-expressions (SEL_TRUE, SEL_FALSE, SEL_ANY). */ + host_eval_ctx_t empty_ctx = { .num_res = 0, .numvals = NULL, .strvals = NULL }; + host_eval_ctx_t* hctx; + + if (num_res <= 0) { + hctx = &empty_ctx; + } else { + hctx = build_host_eval_ctx(w, num_res); + if (hctx == NULL) { + /* OOM: conservatively pass host */ + return 1; + } + } + + int rc = eval_select_simple(s->root, hctx); + if (hctx != &empty_ctx) { + free_host_eval_ctx(hctx); + } + + /* eval_select_simple: 1=match, 0=no-match, <0=error (treat as no-match) */ + return (rc > 0) ? 1 : 0; } static int sched_check_shared_satisfy_(xce_scheduler_t* sched, xvec_t* total, diff --git a/src/scheduler/testsuite/test.c b/src/scheduler/testsuite/test.c index d8b73139..81085ff1 100644 --- a/src/scheduler/testsuite/test.c +++ b/src/scheduler/testsuite/test.c @@ -1,3 +1,4 @@ +#define UNIT_TEST 1 #include #include #include @@ -122,9 +123,77 @@ test_sel_optimize_set_at_scheduler_startup(void) sel_optimize_set(1); TEST_ASSERT_EQUAL_INT(1, sel_get_optimize_level()); /* reset for clean test isolation */ -#ifdef UNIT_TEST sel_optimize_test_reset(); -#endif +} + +static void +test_meet_host_selection_null_select_passes(void) +{ + /* A NULL select pointer means no expression — always pass */ + xce_scheduler_t sched; + memset(&sched, 0, sizeof(sched)); + xce_sched_worker_t w; + memset(&w, 0, sizeof(w)); + zarray_init(&w.resvals, 4, NULL); + + int rc = sched_meet_host_selection(&sched, &w, NULL); + TEST_ASSERT_EQUAL_INT(1, rc); + + zarray_fini(&w.resvals); +} + +static void +test_meet_host_selection_always_true_passes(void) +{ + xce_scheduler_t sched; + memset(&sched, 0, sizeof(sched)); + sel_optimize_set(1); + sel_node_table_init(); + + xce_sched_worker_t w; + memset(&w, 0, sizeof(w)); + zarray_init(&w.resvals, 4, NULL); + + /* SEL_TRUE root — must pass any host */ + xce_select_node_t* root = makeSelectNode(SEL_TRUE, 0, 0); + TEST_ASSERT_NOT_NULL(root); + + xce_select_t sel = { .root = root }; + int rc = sched_meet_host_selection(&sched, &w, &sel); + TEST_ASSERT_EQUAL_INT(1, rc); + + zarray_fini(&w.resvals); + gc_clear_marks(); + gc_sweep_select_nodes(NULL, 0); + sel_node_table_fini(); + sel_optimize_test_reset(); +} + +static void +test_meet_host_selection_always_false_fails(void) +{ + xce_scheduler_t sched; + memset(&sched, 0, sizeof(sched)); + sel_optimize_set(1); + sel_node_table_init(); + + xce_sched_worker_t w; + memset(&w, 0, sizeof(w)); + zarray_init(&w.resvals, 4, NULL); + + /* SEL_FALSE root — must fail every host */ + xce_select_node_t* root = makeSelectNode(SEL_FALSE, 0, 0); + TEST_ASSERT_NOT_NULL(root); + + xce_select_t sel = { .root = root }; + int rc = sched_meet_host_selection(&sched, &w, &sel); + TEST_ASSERT_EQUAL_INT(0, rc); + + zarray_fini(&w.resvals); + gc_clear_marks(); + gc_sweep_select_nodes(NULL, 0); + sel_node_table_fini(); + sel_optimize_test_reset(); } #define TEST(x) \ @@ -143,6 +212,9 @@ int main(int argc, char* argv[]) TEST(test_build_host_eval_ctx_float); TEST(test_scheduler_t_has_atomic_gc_fields); TEST(test_sel_optimize_set_at_scheduler_startup); + TEST(test_meet_host_selection_null_select_passes); + TEST(test_meet_host_selection_always_true_passes); + TEST(test_meet_host_selection_always_false_fails); return UNITY_END(); }