Task 2.4: outcome capture moves to sched_trace_outcome.c and the position/host/summary/rollback half of the model to sched_trace_scan.c; shared helpers go behind sched_trace_internal.h (sti_ prefix). Code is moved unchanged; every target that compiles the trace sources gets all four, and the core isolation scan covers the new files. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
561 lines
18 KiB
C
561 lines
18 KiB
C
/*
|
|
* test_alloc_runner.c - scheduler-allocator-runner task 3.1: the framework
|
|
* allocation routine's guards and shared-resource precheck (Req 1.3, 1.4,
|
|
* 2.1-2.4, 5.1), driven only through sched_allocator_run() with an in-test
|
|
* fake allocator contract on a hand-built plugin.
|
|
*
|
|
* The fake contract counts every call: the acceptance guard returns a
|
|
* configurable verdict; plan_init returns a configurable result and
|
|
* plan_next yields no plan, so an attempt that gets past the shared
|
|
* precheck always ends pending. The job-level shared request is staged by
|
|
* the plugin_prepare_allocation() stub below from g_shared_want.
|
|
*/
|
|
#include <errno.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include <unity/unity.h>
|
|
|
|
#include "preason.h"
|
|
#include "resobj.h"
|
|
#include "resreq.h"
|
|
#include "sched/alloc_iter.h"
|
|
#include "scheduler.h"
|
|
#include "xcealloc.h"
|
|
#include "xstring.h"
|
|
|
|
/* White-box sources under test */
|
|
#include "../src/alloc_runner.c"
|
|
#include "../src/core.c"
|
|
#include "../src/host_iter.c"
|
|
#include "../src/resource.c"
|
|
/* Hooked sources compile SCHED_TRACE bodies (scheduler-sim-decision-trace). */
|
|
#include "../src/sched_trace.c"
|
|
#include "../src/sched_trace_scan.c"
|
|
#include "../src/sched_trace_capture.c"
|
|
#include "../src/sched_trace_outcome.c"
|
|
#include "../src/schedobj.c"
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
/* Link-satisfying stubs (same convention as test_alloc_equivalence_*.c) */
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
int plugin_register(void* sched, void* plugin)
|
|
{
|
|
return (void)sched, (void)plugin, 0;
|
|
}
|
|
|
|
void plugin_unregister(void* arg) { (void)arg; }
|
|
|
|
int plugin_job_update(void* s, xce_sched_job_t* j)
|
|
{
|
|
return (void)s, (void)j, 0;
|
|
}
|
|
|
|
int plugin_queue_update(void* s, xce_sched_queue_t* q)
|
|
{
|
|
return (void)s, (void)q, 0;
|
|
}
|
|
|
|
int plugin_job_rusage_update(void* s, xce_sched_job_t* j, xce_job_rusages_t* r)
|
|
{
|
|
return (void)s, (void)j, (void)r, 0;
|
|
}
|
|
|
|
/* Never reached by these tests (no plan is ever satisfied); present only
|
|
* because the white-box sources reference it. */
|
|
xce_alloc_t** sched_make_allocs(xce_scheduler_t* sched, char* reserve, int nres,
|
|
int* idxs, float* vals, int* duration)
|
|
{
|
|
(void)sched, (void)reserve, (void)nres, (void)idxs, (void)vals;
|
|
(void)duration;
|
|
errno = ENOSYS;
|
|
return NULL;
|
|
}
|
|
|
|
/* Shared request staged by the job-level prepare pass: resource index and
|
|
* amount per entry, g_shared_nwant entries. */
|
|
#define MAX_WANT 4
|
|
static int g_shared_nwant = 0;
|
|
static int g_shared_idx[MAX_WANT];
|
|
static float g_shared_val[MAX_WANT];
|
|
|
|
/* Resets the request vectors as plugin.c does, then stages g_shared_want
|
|
* on the job-level pass (ctx->worker NULL). */
|
|
int plugin_prepare_allocation(xce_sched_core_t* sched, xce_sched_ctx_t* ctx)
|
|
{
|
|
int i;
|
|
|
|
(void)sched;
|
|
xvec_idval_fini(&(ctx->alloc_req.host));
|
|
xvec_idval_init(&(ctx->alloc_req.host), 8);
|
|
if (ctx->worker != NULL) {
|
|
return 0;
|
|
}
|
|
|
|
xvec_idval_fini(&(ctx->alloc_req.shared));
|
|
xvec_idval_init(&(ctx->alloc_req.shared), 8);
|
|
for (i = 0; i < g_shared_nwant; i++) {
|
|
TEST_ASSERT_TRUE(xvec_idval_store(&(ctx->alloc_req.shared),
|
|
g_shared_idx[i], g_shared_val[i])
|
|
> 0);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
/* Fake allocator contract */
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
static int g_accepts_calls = 0;
|
|
static int g_accepts_result = 1;
|
|
static int g_init_calls = 0;
|
|
static int g_init_result = 0;
|
|
static int g_next_calls = 0;
|
|
static int g_fini_calls = 0;
|
|
|
|
static int fake_accepts(const xce_primary_resreq_t* primary)
|
|
{
|
|
(void)primary;
|
|
g_accepts_calls++;
|
|
return g_accepts_result;
|
|
}
|
|
|
|
static int fake_plan_init(xce_alloc_plan_iter_t* iter,
|
|
xce_primary_resreq_t* resreq, xce_sched_core_t* core)
|
|
{
|
|
(void)resreq, (void)core;
|
|
g_init_calls++;
|
|
iter->private = NULL;
|
|
return g_init_result;
|
|
}
|
|
|
|
static xce_alloc_plan_t* fake_plan_next(xce_alloc_plan_iter_t* iter)
|
|
{
|
|
(void)iter;
|
|
g_next_calls++;
|
|
return NULL;
|
|
}
|
|
|
|
static void fake_plan_fini(xce_alloc_plan_iter_t* iter)
|
|
{
|
|
(void)iter;
|
|
g_fini_calls++;
|
|
}
|
|
|
|
/* Mutable so a test can drop one member; reset by setUp() */
|
|
static xce_sched_allocator_iface_t g_iface;
|
|
|
|
/* make_pendreason() failure injection (-Wl,--wrap=make_pendreason in
|
|
* meson.build): when armed, the next call fails with ENOMEM and disarms. */
|
|
static int g_pendreason_fail = 0;
|
|
|
|
xce_pendreason_t* __real_make_pendreason(uint64_t jobid);
|
|
|
|
xce_pendreason_t* __wrap_make_pendreason(uint64_t jobid)
|
|
{
|
|
if (g_pendreason_fail) {
|
|
g_pendreason_fail = 0;
|
|
errno = ENOMEM;
|
|
return NULL;
|
|
}
|
|
return __real_make_pendreason(jobid);
|
|
}
|
|
|
|
/* Restores the full fake contract and clears its call counters */
|
|
static void fake_contract_reset(void)
|
|
{
|
|
g_accepts_calls = 0;
|
|
g_accepts_result = 1;
|
|
g_init_calls = 0;
|
|
g_init_result = 0;
|
|
g_next_calls = 0;
|
|
g_fini_calls = 0;
|
|
|
|
g_iface.accepts = fake_accepts;
|
|
g_iface.plan_init = fake_plan_init;
|
|
g_iface.plan_next = fake_plan_next;
|
|
g_iface.plan_fini = fake_plan_fini;
|
|
}
|
|
|
|
void setUp(void)
|
|
{
|
|
g_shared_nwant = 0;
|
|
g_pendreason_fail = 0;
|
|
fake_contract_reset();
|
|
}
|
|
|
|
void tearDown(void) { }
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
/* Fixture */
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
typedef struct {
|
|
xce_scheduler_t sched;
|
|
xce_resource_t* lic_a; /* shared, 10 in total */
|
|
xce_resource_t* lic_b; /* shared, 2 in total */
|
|
xce_sched_plugin_t plugin;
|
|
xce_primary_resreq_t req;
|
|
xce_sched_obj_t obj;
|
|
xce_primary_schedobj_t primary_obj;
|
|
xce_sched_ctx_t ctx;
|
|
} rt_fixture_t;
|
|
|
|
static xce_resource_t* rt_register_shared(var resmgr, const char* name)
|
|
{
|
|
xce_resource_t res;
|
|
|
|
memset(&res, 0, sizeof(res));
|
|
res.name = (char*)name;
|
|
res.flags = XCE_RESF_GLOBAL;
|
|
|
|
return makeResource(resmgr, &res);
|
|
}
|
|
|
|
/* Core with two shared pools, the hand-built plugin over the fake contract,
|
|
* and a ctx over one single-task primary with its job-level prepare pass
|
|
* run (the shared request staged from g_shared_want). */
|
|
static void rt_fixture_init(rt_fixture_t* f)
|
|
{
|
|
int i;
|
|
int idx[2];
|
|
float total[2] = { 10.0f, 2.0f };
|
|
|
|
memset(f, 0, sizeof(*f));
|
|
TEST_ASSERT_EQUAL_INT(0, xce_sched_core_init(&(f->sched.core)));
|
|
/* xce_sched_core_fini() finalizes these; both drivers calloc them */
|
|
for (i = 0; i < 2; i++) {
|
|
f->sched.core.pend_updates[i] = (dataq_t*)calloc(1, sizeof(dataq_t));
|
|
TEST_ASSERT_NOT_NULL(f->sched.core.pend_updates[i]);
|
|
dataq_init(f->sched.core.pend_updates[i], NULL);
|
|
}
|
|
|
|
f->lic_a = rt_register_shared(f->sched.core.resmgr, "lic_a");
|
|
f->lic_b = rt_register_shared(f->sched.core.resmgr, "lic_b");
|
|
TEST_ASSERT_NOT_NULL(f->lic_a);
|
|
TEST_ASSERT_NOT_NULL(f->lic_b);
|
|
idx[0] = f->lic_a->idx;
|
|
idx[1] = f->lic_b->idx;
|
|
put_resvals(&(f->sched.core.sharedInst), 2, idx, total);
|
|
|
|
f->plugin.name = (char*)"fake_allocator";
|
|
f->plugin.sched = &(f->sched);
|
|
f->plugin.core = &(f->sched.core);
|
|
f->plugin.allocator_iface = &g_iface;
|
|
|
|
f->req.minTasks = 1;
|
|
f->req.maxTasks = 1;
|
|
f->primary_obj.resreq = &(f->req);
|
|
f->obj.tag = XCE_RESREQ_PRIMARY;
|
|
f->obj.u.primary = &(f->primary_obj);
|
|
TEST_ASSERT_EQUAL_INT(
|
|
0, sched_ctx_init(&(f->ctx), &(f->sched.core), &(f->obj)));
|
|
sched_ctx_set_primary(&(f->ctx), &(f->req));
|
|
}
|
|
|
|
static void rt_fixture_fini(rt_fixture_t* f)
|
|
{
|
|
free_JobAlloc_ptr(&(f->ctx.alloc));
|
|
free_PendReason_ptr(&(f->ctx.reason));
|
|
sched_ctx_fini(&(f->ctx));
|
|
xce_sched_core_fini(&(f->sched.core));
|
|
/* xce_sched_core_init() creates the process-wide string table on every
|
|
* call and xce_sched_core_fini() leaves it; release it per fixture */
|
|
xstring_table_fini();
|
|
}
|
|
|
|
/* Stages a shared request of `a` lic_a and `b` lic_b (0 = not requested)
|
|
* and reruns the job-level prepare pass. */
|
|
static void rt_want_shared(rt_fixture_t* f, float a, float b)
|
|
{
|
|
g_shared_nwant = 0;
|
|
if (a > 0.0f) {
|
|
g_shared_idx[g_shared_nwant] = f->lic_a->idx;
|
|
g_shared_val[g_shared_nwant++] = a;
|
|
}
|
|
if (b > 0.0f) {
|
|
g_shared_idx[g_shared_nwant] = f->lic_b->idx;
|
|
g_shared_val[g_shared_nwant++] = b;
|
|
}
|
|
sched_ctx_set_primary(&(f->ctx), &(f->req));
|
|
}
|
|
|
|
static int rt_run(rt_fixture_t* f)
|
|
{
|
|
return sched_allocator_run(&(f->plugin), &(f->ctx));
|
|
}
|
|
|
|
static float rt_shared_uncomit(rt_fixture_t* f, xce_resource_t* r)
|
|
{
|
|
return ((float*)f->ctx.uncomitted.shared->data)[r->idx];
|
|
}
|
|
|
|
static void rt_assert_no_shared_uncomit(rt_fixture_t* f)
|
|
{
|
|
TEST_ASSERT_EQUAL_FLOAT(0.0f, rt_shared_uncomit(f, f->lic_a));
|
|
TEST_ASSERT_EQUAL_FLOAT(0.0f, rt_shared_uncomit(f, f->lic_b));
|
|
}
|
|
|
|
static void rt_assert_calls(int accepts, int init, int fini)
|
|
{
|
|
TEST_ASSERT_EQUAL_INT(accepts, g_accepts_calls);
|
|
TEST_ASSERT_EQUAL_INT(init, g_init_calls);
|
|
TEST_ASSERT_EQUAL_INT(fini, g_fini_calls);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
/* Guards (Req 5.1, 1.3, 1.4, 2.1) */
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
/* Missing plugin or ctx: -EINVAL, the ctx untouched, no contract call. */
|
|
static void test_missing_plugin_or_ctx_is_einval(void)
|
|
{
|
|
rt_fixture_t f;
|
|
|
|
rt_fixture_init(&f);
|
|
TEST_ASSERT_EQUAL_INT(-EINVAL, sched_allocator_run(NULL, &(f.ctx)));
|
|
TEST_ASSERT_EQUAL_INT(-EINVAL, sched_allocator_run(&(f.plugin), NULL));
|
|
TEST_ASSERT_NULL(f.ctx.reason);
|
|
rt_assert_calls(0, 0, 0);
|
|
rt_fixture_fini(&f);
|
|
}
|
|
|
|
/* Each missing field (core, sched, primary, iface) in turn: -EINVAL,
|
|
* ctx->reason still NULL, no contract call. */
|
|
static void test_missing_field_is_einval_without_reason(void)
|
|
{
|
|
rt_fixture_t f;
|
|
int i;
|
|
|
|
rt_fixture_init(&f);
|
|
rt_want_shared(&f, 3.0f, 0.0f);
|
|
for (i = 0; i < 4; i++) {
|
|
xce_sched_core_t* core = f.plugin.core;
|
|
void* sched = f.plugin.sched;
|
|
xce_primary_resreq_t* primary = f.ctx.primary;
|
|
const xce_sched_allocator_iface_t* iface = f.plugin.allocator_iface;
|
|
|
|
f.plugin.core = (i == 0) ? NULL : core;
|
|
f.plugin.sched = (i == 1) ? NULL : sched;
|
|
f.ctx.primary = (i == 2) ? NULL : primary;
|
|
f.plugin.allocator_iface = (i == 3) ? NULL : iface;
|
|
|
|
TEST_ASSERT_EQUAL_INT_MESSAGE(-EINVAL, rt_run(&f), "missing field");
|
|
TEST_ASSERT_NULL(f.ctx.reason);
|
|
|
|
f.plugin.core = core;
|
|
f.plugin.sched = sched;
|
|
f.ctx.primary = primary;
|
|
f.plugin.allocator_iface = iface;
|
|
}
|
|
rt_assert_calls(0, 0, 0);
|
|
rt_assert_no_shared_uncomit(&f);
|
|
rt_fixture_fini(&f);
|
|
}
|
|
|
|
/* Each missing plan_* member in turn: -EINVAL, no reason, no call. */
|
|
static void test_missing_plan_member_is_einval_without_reason(void)
|
|
{
|
|
rt_fixture_t f;
|
|
int i;
|
|
|
|
rt_fixture_init(&f);
|
|
for (i = 0; i < 3; i++) {
|
|
fake_contract_reset();
|
|
g_iface.plan_init = (i == 0) ? NULL : fake_plan_init;
|
|
g_iface.plan_next = (i == 1) ? NULL : fake_plan_next;
|
|
g_iface.plan_fini = (i == 2) ? NULL : fake_plan_fini;
|
|
|
|
TEST_ASSERT_EQUAL_INT_MESSAGE(-EINVAL, rt_run(&f), "missing plan_*");
|
|
TEST_ASSERT_NULL(f.ctx.reason);
|
|
rt_assert_calls(0, 0, 0);
|
|
}
|
|
rt_fixture_fini(&f);
|
|
}
|
|
|
|
/* A rejecting guard: pending, no reason record, no shared check or count,
|
|
* no plan generator (Req 1.4). */
|
|
static void test_rejecting_accepts_pends_without_checks(void)
|
|
{
|
|
rt_fixture_t f;
|
|
|
|
rt_fixture_init(&f);
|
|
rt_want_shared(&f, 3.0f, 1.0f);
|
|
g_accepts_result = 0;
|
|
|
|
TEST_ASSERT_EQUAL_INT(0, rt_run(&f));
|
|
TEST_ASSERT_NULL(f.ctx.reason);
|
|
TEST_ASSERT_NULL(f.ctx.alloc);
|
|
rt_assert_calls(1, 0, 0);
|
|
rt_assert_no_shared_uncomit(&f);
|
|
rt_fixture_fini(&f);
|
|
}
|
|
|
|
/* No guard accepts every request and reaches plan_init (Req 1.3). */
|
|
static void test_null_accepts_reaches_plan_init(void)
|
|
{
|
|
rt_fixture_t f;
|
|
|
|
rt_fixture_init(&f);
|
|
g_iface.accepts = NULL;
|
|
|
|
TEST_ASSERT_EQUAL_INT(0, rt_run(&f));
|
|
TEST_ASSERT_NOT_NULL(f.ctx.reason);
|
|
rt_assert_calls(0, 1, 1);
|
|
rt_fixture_fini(&f);
|
|
}
|
|
|
|
/* An accepting guard: the reason record is created after it (Req 2.1). */
|
|
static void test_reason_created_after_accepting_guard(void)
|
|
{
|
|
rt_fixture_t f;
|
|
|
|
rt_fixture_init(&f);
|
|
|
|
TEST_ASSERT_EQUAL_INT(0, rt_run(&f));
|
|
TEST_ASSERT_NOT_NULL(f.ctx.reason);
|
|
TEST_ASSERT_NOT_NULL(f.ctx.reason->reasons);
|
|
TEST_ASSERT_EQUAL_INT(0, f.ctx.reason->reasons->main_reason);
|
|
TEST_ASSERT_EQUAL_INT(0, f.ctx.reason->reasons->nres_reasons);
|
|
rt_assert_calls(1, 1, 1);
|
|
rt_fixture_fini(&f);
|
|
}
|
|
|
|
/* An existing reason record (e.g. from an earlier primary of the same
|
|
* COMPOUND job) is reused, not replaced. */
|
|
static void test_existing_reason_is_reused(void)
|
|
{
|
|
rt_fixture_t f;
|
|
xce_pendreason_t* before;
|
|
|
|
rt_fixture_init(&f);
|
|
before = make_pendreason(0);
|
|
TEST_ASSERT_NOT_NULL(before);
|
|
f.ctx.reason = before;
|
|
|
|
TEST_ASSERT_EQUAL_INT(0, rt_run(&f));
|
|
TEST_ASSERT_EQUAL_PTR(before, f.ctx.reason);
|
|
rt_fixture_fini(&f);
|
|
}
|
|
|
|
/* The reason record cannot be created: -ENOMEM with ctx->reason still
|
|
* NULL, no shared count and no plan generator (Req 2.4). */
|
|
static void test_reason_oom_returns_enomem_without_checks(void)
|
|
{
|
|
rt_fixture_t f;
|
|
|
|
rt_fixture_init(&f);
|
|
rt_want_shared(&f, 3.0f, 1.0f);
|
|
g_pendreason_fail = 1;
|
|
|
|
TEST_ASSERT_EQUAL_INT(-ENOMEM, rt_run(&f));
|
|
TEST_ASSERT_NULL(f.ctx.reason);
|
|
TEST_ASSERT_NULL(f.ctx.alloc);
|
|
rt_assert_calls(1, 0, 0);
|
|
rt_assert_no_shared_uncomit(&f);
|
|
rt_fixture_fini(&f);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
/* Shared precheck (Req 2.2, 2.3, 3.4) */
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
/* bug-1893: two shared resources requested, only lic_b short (3 of 2):
|
|
* exactly one host-less NO_RESOURCE reason naming lic_b, nothing counted,
|
|
* no plan generator. */
|
|
static void test_shared_short_one_reason_per_unmet_entry(void)
|
|
{
|
|
rt_fixture_t f;
|
|
xce_res_reason_t* rr;
|
|
|
|
rt_fixture_init(&f);
|
|
rt_want_shared(&f, 3.0f, 3.0f);
|
|
|
|
TEST_ASSERT_EQUAL_INT(0, rt_run(&f));
|
|
TEST_ASSERT_NULL(f.ctx.alloc);
|
|
TEST_ASSERT_NOT_NULL(f.ctx.reason);
|
|
TEST_ASSERT_EQUAL_INT(0, f.ctx.reason->reasons->main_reason);
|
|
TEST_ASSERT_EQUAL_INT(0, f.ctx.reason->reasons->nhost_reasons);
|
|
TEST_ASSERT_EQUAL_INT(1, f.ctx.reason->reasons->nres_reasons);
|
|
rr = f.ctx.reason->reasons->res_based_reasons[0];
|
|
TEST_ASSERT_NOT_NULL(rr);
|
|
TEST_ASSERT_EQUAL_STRING("", rr->host);
|
|
TEST_ASSERT_EQUAL_STRING("lic_b", rr->resource);
|
|
TEST_ASSERT_EQUAL_INT(PREASON_NO_RESOURCE, rr->reason);
|
|
|
|
rt_assert_calls(1, 0, 0);
|
|
rt_assert_no_shared_uncomit(&f);
|
|
rt_fixture_fini(&f);
|
|
}
|
|
|
|
/* Shared met, plan_init fails: pending, plan_fini not called, and the
|
|
* requested amounts stay counted at their resource indices. */
|
|
static void test_shared_met_counted_and_kept_when_plan_init_fails(void)
|
|
{
|
|
rt_fixture_t f;
|
|
|
|
rt_fixture_init(&f);
|
|
rt_want_shared(&f, 3.0f, 1.0f);
|
|
g_init_result = -ENOMEM;
|
|
|
|
TEST_ASSERT_EQUAL_INT(0, rt_run(&f));
|
|
TEST_ASSERT_NULL(f.ctx.alloc);
|
|
TEST_ASSERT_EQUAL_INT(0, f.ctx.reason->reasons->nres_reasons);
|
|
rt_assert_calls(1, 1, 0);
|
|
TEST_ASSERT_EQUAL_INT(0, g_next_calls);
|
|
TEST_ASSERT_EQUAL_FLOAT(3.0f, rt_shared_uncomit(&f, f.lic_a));
|
|
TEST_ASSERT_EQUAL_FLOAT(1.0f, rt_shared_uncomit(&f, f.lic_b));
|
|
rt_fixture_fini(&f);
|
|
}
|
|
|
|
/* Shared met, plan_init succeeds with no plan: pending, plan_fini called
|
|
* exactly once, and the requested amounts stay counted. */
|
|
static void test_shared_met_counted_and_kept_when_no_plan(void)
|
|
{
|
|
rt_fixture_t f;
|
|
|
|
rt_fixture_init(&f);
|
|
rt_want_shared(&f, 3.0f, 1.0f);
|
|
|
|
TEST_ASSERT_EQUAL_INT(0, rt_run(&f));
|
|
TEST_ASSERT_NULL(f.ctx.alloc);
|
|
rt_assert_calls(1, 1, 1);
|
|
TEST_ASSERT_EQUAL_FLOAT(3.0f, rt_shared_uncomit(&f, f.lic_a));
|
|
TEST_ASSERT_EQUAL_FLOAT(1.0f, rt_shared_uncomit(&f, f.lic_b));
|
|
rt_fixture_fini(&f);
|
|
}
|
|
|
|
/* The helpers directly: a shared request of nothing is met and counts
|
|
* nothing; the reason helper keeps an existing record. */
|
|
static void test_helpers_empty_shared_is_met(void)
|
|
{
|
|
rt_fixture_t f;
|
|
|
|
rt_fixture_init(&f);
|
|
TEST_ASSERT_EQUAL_INT(0, sched_alloc_ensure_reason_(&(f.ctx)));
|
|
TEST_ASSERT_NOT_NULL(f.ctx.reason);
|
|
TEST_ASSERT_EQUAL_INT(
|
|
1, sched_alloc_prepare_shared_(&(f.sched.core), &(f.ctx)));
|
|
rt_assert_no_shared_uncomit(&f);
|
|
rt_fixture_fini(&f);
|
|
}
|
|
|
|
int main(void)
|
|
{
|
|
UNITY_BEGIN();
|
|
RUN_TEST(test_missing_plugin_or_ctx_is_einval);
|
|
RUN_TEST(test_missing_field_is_einval_without_reason);
|
|
RUN_TEST(test_missing_plan_member_is_einval_without_reason);
|
|
RUN_TEST(test_rejecting_accepts_pends_without_checks);
|
|
RUN_TEST(test_null_accepts_reaches_plan_init);
|
|
RUN_TEST(test_reason_created_after_accepting_guard);
|
|
RUN_TEST(test_existing_reason_is_reused);
|
|
RUN_TEST(test_reason_oom_returns_enomem_without_checks);
|
|
RUN_TEST(test_shared_short_one_reason_per_unmet_entry);
|
|
RUN_TEST(test_shared_met_counted_and_kept_when_plan_init_fails);
|
|
RUN_TEST(test_shared_met_counted_and_kept_when_no_plan);
|
|
RUN_TEST(test_helpers_empty_shared_is_met);
|
|
return UNITY_END();
|
|
}
|