myxce/src/scheduler/testsuite/test_decision_trace.c
Rongsong Shen 29b6734649
feat(scheduler-sim-decision-trace): trace attachment and trace-only op on decisions
Task 1.7: xce_decision_t gains a trace pointer (NULL from every existing
constructor) and XCE_DECISION_TRACE with make_trace_decision(); the live
driver skips trace-only decisions and frees any attached trace.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-08 08:40:37 +00:00

130 lines
3.8 KiB
C

/*
* test_decision_trace.c - the decision transport's trace attachment and
* trace-only op (scheduler-sim-decision-trace spec, task 1.7; design.md
* "DecisionTransport"; Requirements 2.4, 10.1, 11.4).
*
* - every existing constructor (pend, dispatch, preempt) leaves the trace
* attachment NULL;
* - the existing op values are unchanged and the trace-only op is
* appended after XCE_DECISION_PREEMPT;
* - make_trace_decision() builds a trace-only decision: op TRACE, zeroed
* union, the record attached.
*
* The live driver's handling of both is covered in
* test_driver_session_ordering.c.
*
* White-box #include of src/decision.c; links src/sched_trace.c for the
* record constructor and free.
*/
#include <stdlib.h>
#include <string.h>
#include <unity/unity.h>
#include "sched/trace.h"
#include "../src/decision.c"
void setUp(void) { return; }
void tearDown(void) { return; }
static xce_sched_trace_ctl_t make_ctl(void)
{
xce_sched_trace_ctl_t ctl;
memset(&ctl, 0, sizeof(ctl));
ctl.all = true;
ctl.level = XCE_TRACE_LEVEL_SUMMARY;
ctl.line_bound = XCE_TRACE_LINE_BOUND_DEFAULT;
ctl.session_no = 1;
ctl.policy_name = "fcfs";
return ctl;
}
static void test_existing_op_values_unchanged(void)
{
TEST_ASSERT_EQUAL_INT(0, XCE_DECISION_NONE);
TEST_ASSERT_EQUAL_INT(1, XCE_DECISION_DISPATCH);
TEST_ASSERT_EQUAL_INT(2, XCE_DECISION_PEND);
TEST_ASSERT_EQUAL_INT(3, XCE_DECISION_NEW_SESSION);
TEST_ASSERT_EQUAL_INT(4, XCE_DECISION_PREEMPT);
TEST_ASSERT_EQUAL_INT(5, XCE_DECISION_TRACE);
}
static void test_existing_constructors_leave_trace_null(void)
{
xce_pendreason_t reason;
xce_job_alloc_t alloc;
xce_preempt_t preempt;
xce_decision_t* d;
memset(&reason, 0, sizeof(reason));
memset(&alloc, 0, sizeof(alloc));
memset(&preempt, 0, sizeof(preempt));
d = make_pend_decision(&reason);
TEST_ASSERT_NOT_NULL(d);
TEST_ASSERT_EQUAL_INT(XCE_DECISION_PEND, d->op);
TEST_ASSERT_EQUAL_PTR(&reason, d->u.reason);
TEST_ASSERT_NULL(d->trace);
free(d);
d = make_dispatch_decision(&alloc);
TEST_ASSERT_NOT_NULL(d);
TEST_ASSERT_EQUAL_INT(XCE_DECISION_DISPATCH, d->op);
TEST_ASSERT_EQUAL_PTR(&alloc, d->u.alloc);
TEST_ASSERT_NULL(d->trace);
free(d);
d = make_preempt_decision(&preempt);
TEST_ASSERT_NOT_NULL(d);
TEST_ASSERT_EQUAL_INT(XCE_DECISION_PREEMPT, d->op);
TEST_ASSERT_EQUAL_PTR(&preempt, d->u.preempt);
TEST_ASSERT_NULL(d->trace);
free(d);
}
static void test_make_trace_decision_attaches_record(void)
{
xce_sched_trace_ctl_t ctl = make_ctl();
xce_sched_trace_rec_t* rec;
xce_decision_t* d;
rec = sched_trace_rec_new(&ctl, 42, XCE_TRACE_REC_DECISION);
TEST_ASSERT_NOT_NULL(rec);
sched_trace_rec_finish(rec, XCE_TRACE_REC_NO_SCHEDOBJ, 0);
d = make_trace_decision(rec);
TEST_ASSERT_NOT_NULL(d);
TEST_ASSERT_EQUAL_INT(XCE_DECISION_TRACE, d->op);
TEST_ASSERT_NULL(d->u.alloc);
TEST_ASSERT_NULL(d->u.reason);
TEST_ASSERT_NULL(d->u.preempt);
TEST_ASSERT_EQUAL_PTR(rec, d->trace);
TEST_ASSERT_EQUAL_INT(XCE_TRACE_REC_NO_SCHEDOBJ, d->trace->kind);
TEST_ASSERT_EQUAL_UINT64(42, d->trace->jobid);
/* the receiver owns d->trace: free it, then the decision */
sched_trace_rec_free(d->trace);
free(d);
}
static void test_make_trace_decision_accepts_null_record(void)
{
xce_decision_t* d = make_trace_decision(NULL);
TEST_ASSERT_NOT_NULL(d);
TEST_ASSERT_EQUAL_INT(XCE_DECISION_TRACE, d->op);
TEST_ASSERT_NULL(d->trace);
free(d);
}
int main(void)
{
UNITY_BEGIN();
RUN_TEST(test_existing_op_values_unchanged);
RUN_TEST(test_existing_constructors_leave_trace_null);
RUN_TEST(test_make_trace_decision_attaches_record);
RUN_TEST(test_make_trace_decision_accepts_null_record);
return UNITY_END();
}