feat: implement sched_meet_host_selection using eval_select_simple (6-5)

Replace the always-return-1 stub with a real implementation that:
- Returns 1 immediately when s == NULL or s->root == NULL (no constraint)
- Builds a host_eval_ctx_t from w->resvals and calls eval_select_simple
- Uses a zero-resource stack context when resvals.caps == 0 so constant
  sub-expressions (SEL_TRUE, SEL_FALSE, SEL_ANY) still evaluate correctly
- On OOM (build_host_eval_ctx returns NULL), conservatively passes the host
- Maps eval_select_simple result: >0 → 1 (match), <=0 → 0 (no-match)

Add #define UNIT_TEST 1 to test.c, remove redundant #ifdef guard, and
add three new TDD tests covering NULL select, SEL_TRUE, and SEL_FALSE.
All 6 tests pass.
This commit is contained in:
Rongsong Shen 2026-04-30 05:04:47 +00:00
parent 2e3469c3c5
commit 40261b7e96
2 changed files with 103 additions and 4 deletions

View file

@ -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,

View file

@ -1,3 +1,4 @@
#define UNIT_TEST 1
#include <argp.h>
#include <stdio.h>
#include <stdlib.h>
@ -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();
}