Eight display/text defects in test.c: worker_status_str's "UNKOWN" typo, cmd_runtasks's "sequentail" typo (display-only, verified inert against the real launch_type consumer), cmd_reslist's right-justified columns and unlabeled hex Flags (now matching workerlist/state_raw's conventions), joblist's raw-epoch timestamps (now via a format_job_time helper delegating to the same formatter ctrlstatus already uses) and combined NTasks column split into MinTasks/MaxTasks, job_state_str's missing raw-state fallback for ambiguous RUN+EXIT (mirroring print_jobinfo's existing pattern), and getconf's no-op group/config list stubs (now genuinely implemented from already-fetched data, matching the three sibling print functions' convention). worker_status_str/job_state_str/format_job_time are pure functions with no networking/REPL/global-state dependency, extracted into a new joblist_display.c/.h module with a permanent 20-test standalone suite -- following this codebase's own resval_typeresolve.c/misc.c precedent for testing functions that would otherwise be stranded inside untестable test.c. cmd_reslist/joblist_query/cmd_getconf's table-printing bodies inline fetch+print and remain untestable without a live cluster. 1348/1348 across the full controller suite (+20), 0 regressions. Task 2.5 of .kiro/specs/xce-test-cli-ux/tasks.md. Requirements: 11.1, 11.3, 11.4, 11.5, 11.6, 11.7, 11.8 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019jaMf9QEwpugH2W9KAuc7f
256 lines
9.4 KiB
C
256 lines
9.4 KiB
C
/* test_joblist_display.c -- xce-test-cli-ux task 2.5 remediation
|
|
*
|
|
* Unity unit tests for joblist_display.c's worker_status_str()/
|
|
* job_state_str()/format_job_time(), extracted from test.c (see
|
|
* joblist_display.h for the full extraction rationale). All three fixes
|
|
* these functions carry (bug-1711) were already verified correct by review
|
|
* against the pre-extraction code; this file is the permanent, automated
|
|
* proof that (a) the fixes behave as intended and (b) the extraction did not
|
|
* change any observed behavior -- in particular, that the pre-existing
|
|
* branches these fixes sit alongside do NOT regress into the new fallback
|
|
* branches.
|
|
*
|
|
* Standalone Unity main (this binary is its own test executable -- see
|
|
* meson.build's joblist_display_unit_test), mirroring
|
|
* resval_typeresolve_unit_test's/host_runusage_unit_test's own pattern.
|
|
*/
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#include <unity/unity.h>
|
|
|
|
#include "ctrlstatus_fmt.h" /* ctrlstatus_format_time_ms -- used directly
|
|
* below to prove format_job_time() genuinely
|
|
* delegates to it (byte-identical output),
|
|
* rather than a parallel reimplementation that
|
|
* could silently drift. */
|
|
#include "joblist_display.h"
|
|
#include "xce/types.h" /* XCE_WORKER_*, JOB_STAT_* bit definitions */
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* worker_status_str() */
|
|
/* ------------------------------------------------------------------ */
|
|
|
|
/* Requirement 11.1's non-regression proof: admin-set CLOSED must still take
|
|
* priority over the dynamic UNAVAIL bit when both are set (task 8.6's
|
|
* config-upgrade-snapshot soak relies on this precedence). */
|
|
static void test_worker_status_closed_over_unavail_priority(void)
|
|
{
|
|
char* rc = worker_status_str(XCE_WORKER_CLOSED | XCE_WORKER_UNAVAIL);
|
|
|
|
TEST_ASSERT_EQUAL_STRING_MESSAGE(
|
|
"CLOSED", rc,
|
|
"CLOSED must take priority over UNAVAIL when both bits are set");
|
|
}
|
|
|
|
static void test_worker_status_unavail_alone(void)
|
|
{
|
|
TEST_ASSERT_EQUAL_STRING("UNAVAIL",
|
|
worker_status_str(XCE_WORKER_UNAVAIL));
|
|
}
|
|
|
|
static void test_worker_status_lockedu_alone(void)
|
|
{
|
|
TEST_ASSERT_EQUAL_STRING("LOCKU", worker_status_str(XCE_WORKER_LOCKEDU));
|
|
}
|
|
|
|
static void test_worker_status_lockedw_alone(void)
|
|
{
|
|
TEST_ASSERT_EQUAL_STRING("LOCKW", worker_status_str(XCE_WORKER_LOCKEDW));
|
|
}
|
|
|
|
static void test_worker_status_busy_alone(void)
|
|
{
|
|
TEST_ASSERT_EQUAL_STRING("BUSY", worker_status_str(XCE_WORKER_BUSY));
|
|
}
|
|
|
|
static void test_worker_status_zero_is_ok(void)
|
|
{
|
|
TEST_ASSERT_EQUAL_STRING("OK", worker_status_str(0));
|
|
}
|
|
|
|
/* Requirement 11.1 (bug-1711's actual fix): an unrecognized status bit
|
|
* (XCE_WORKER_CLOSED_BY_ADMIN -- a real bit in xce/types.h, but not one
|
|
* worker_status_str() checks for) must fall through to "UNKNOWN", correctly
|
|
* spelled -- previously misspelled "UNKOWN". */
|
|
static void test_worker_status_unrecognized_bit_is_unknown(void)
|
|
{
|
|
char* rc = worker_status_str(XCE_WORKER_CLOSED_BY_ADMIN);
|
|
|
|
TEST_ASSERT_EQUAL_STRING_MESSAGE(
|
|
"UNKNOWN", rc,
|
|
"an unrecognized status bit must report correctly-spelled UNKNOWN "
|
|
"(Requirement 11.1)");
|
|
}
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* job_state_str() */
|
|
/* ------------------------------------------------------------------ */
|
|
|
|
static void test_job_state_pend(void)
|
|
{
|
|
TEST_ASSERT_EQUAL_STRING("PEND", job_state_str(JOB_STAT_PEND));
|
|
}
|
|
|
|
static void test_job_state_pend_psusp(void)
|
|
{
|
|
TEST_ASSERT_EQUAL_STRING(
|
|
"PSUSP", job_state_str(JOB_STAT_PEND | JOB_STAT_PSUSP));
|
|
}
|
|
|
|
static void test_job_state_run(void)
|
|
{
|
|
TEST_ASSERT_EQUAL_STRING("RUN", job_state_str(JOB_STAT_RUN));
|
|
}
|
|
|
|
/* Non-regression proof (review's specific request): RUN+USUSP must still
|
|
* resolve to "USUSP", not fall through to the new RUN+EXIT fallback. */
|
|
static void test_job_state_run_ususp(void)
|
|
{
|
|
TEST_ASSERT_EQUAL_STRING_MESSAGE(
|
|
"USUSP", job_state_str(JOB_STAT_RUN | JOB_STAT_USUSP),
|
|
"RUN+USUSP must not regress into the new RUN+EXIT fallback");
|
|
}
|
|
|
|
/* Non-regression proof (review's specific request): RUN+SSUSP must still
|
|
* resolve to "SSUSP", not fall through to the new RUN+EXIT fallback. */
|
|
static void test_job_state_run_ssusp(void)
|
|
{
|
|
TEST_ASSERT_EQUAL_STRING_MESSAGE(
|
|
"SSUSP", job_state_str(JOB_STAT_RUN | JOB_STAT_SSUSP),
|
|
"RUN+SSUSP must not regress into the new RUN+EXIT fallback");
|
|
}
|
|
|
|
/* Requirement 11.7 (bug-1711's actual fix): RUN+EXIT (e.g. a worker-reported
|
|
* FAIL received without a prior FINISH) must report the raw-state fallback
|
|
* "RUN(0x%x)", mirroring print_jobinfo's own state_raw guard for the same
|
|
* ambiguity, instead of silently printing plain "RUN". */
|
|
static void test_job_state_run_exit_fallback(void)
|
|
{
|
|
int state = JOB_STAT_RUN | JOB_STAT_EXIT;
|
|
char expected[32];
|
|
char* rc = job_state_str(state);
|
|
|
|
snprintf(expected, sizeof(expected), "RUN(0x%x)", state);
|
|
|
|
TEST_ASSERT_EQUAL_STRING_MESSAGE(
|
|
expected, rc,
|
|
"RUN+EXIT must report the raw-state fallback RUN(0x%x) "
|
|
"(Requirement 11.7)");
|
|
}
|
|
|
|
static void test_job_state_exit(void)
|
|
{
|
|
TEST_ASSERT_EQUAL_STRING("EXIT", job_state_str(JOB_STAT_EXIT));
|
|
}
|
|
|
|
static void test_job_state_done(void)
|
|
{
|
|
TEST_ASSERT_EQUAL_STRING("DONE", job_state_str(JOB_STAT_DONE));
|
|
}
|
|
|
|
static void test_job_state_error(void)
|
|
{
|
|
TEST_ASSERT_EQUAL_STRING("ERROR", job_state_str(JOB_STAT_ERR));
|
|
}
|
|
|
|
/* Default/unknown branch: no recognized bit set at all. */
|
|
static void test_job_state_unknown_default(void)
|
|
{
|
|
TEST_ASSERT_EQUAL_STRING("UNKNOWN", job_state_str(0));
|
|
}
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* format_job_time() */
|
|
/* ------------------------------------------------------------------ */
|
|
|
|
/* Requirement 11.5: a zero job time_t (event has not happened yet) must
|
|
* print "-", not a misleading 1970-01-01 epoch date. */
|
|
static void test_format_job_time_zero_is_dash(void)
|
|
{
|
|
char buf[32];
|
|
const char* rc = format_job_time((time_t)0, buf, sizeof(buf));
|
|
|
|
TEST_ASSERT_EQUAL_STRING("-", rc);
|
|
}
|
|
|
|
/* Requirement 11.5's delegation proof: format_job_time() is supposed to be a
|
|
* thin seconds->milliseconds adapter directly in front of
|
|
* ctrlstatus_format_time_ms() -- this asserts the two are BYTE-IDENTICAL for
|
|
* the equivalent millisecond input, proving genuine delegation rather than a
|
|
* parallel reimplementation that could silently drift from ctrlstatus's own
|
|
* formatting. */
|
|
static void test_format_job_time_matches_ctrlstatus_formatter(void)
|
|
{
|
|
time_t t = (time_t)1700000000; /* arbitrary fixed nonzero epoch */
|
|
char via_format_job_time[32];
|
|
char via_ctrlstatus_direct[32];
|
|
const char* rc1;
|
|
char* rc2;
|
|
|
|
rc1 = format_job_time(t, via_format_job_time, sizeof(via_format_job_time));
|
|
rc2 = ctrlstatus_format_time_ms((uint64_t)t * 1000u,
|
|
via_ctrlstatus_direct,
|
|
sizeof(via_ctrlstatus_direct));
|
|
|
|
TEST_ASSERT_NOT_NULL(rc1);
|
|
TEST_ASSERT_NOT_NULL(rc2);
|
|
TEST_ASSERT_EQUAL_STRING_MESSAGE(
|
|
rc2, rc1,
|
|
"format_job_time() must be byte-identical to a direct "
|
|
"ctrlstatus_format_time_ms() call on the equivalent millisecond "
|
|
"input -- it must delegate, not reimplement");
|
|
}
|
|
|
|
/* Bonus branch coverage: format_job_time()'s own "-" fallback when the
|
|
* underlying formatter declines (buffer too small per
|
|
* ctrlstatus_format_time_ms's documented >= 24-byte contract). */
|
|
static void test_format_job_time_buffer_too_small_is_dash(void)
|
|
{
|
|
char buf[4]; /* below ctrlstatus_format_time_ms's 24-byte floor */
|
|
const char* rc = format_job_time((time_t)1700000000, buf, sizeof(buf));
|
|
|
|
TEST_ASSERT_EQUAL_STRING("-", rc);
|
|
}
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* Standalone Unity main (this binary is its own test executable -- see */
|
|
/* meson.build's joblist_display_unit_test) */
|
|
/* ------------------------------------------------------------------ */
|
|
|
|
void setUp(void) { return; }
|
|
void tearDown(void) { return; }
|
|
|
|
int main(void)
|
|
{
|
|
printf("\n>> xce-test-cli-ux task 2.5 remediation: joblist_display "
|
|
"worker_status_str/job_state_str/format_job_time\n\n");
|
|
|
|
UNITY_BEGIN();
|
|
|
|
RUN_TEST(test_worker_status_closed_over_unavail_priority);
|
|
RUN_TEST(test_worker_status_unavail_alone);
|
|
RUN_TEST(test_worker_status_lockedu_alone);
|
|
RUN_TEST(test_worker_status_lockedw_alone);
|
|
RUN_TEST(test_worker_status_busy_alone);
|
|
RUN_TEST(test_worker_status_zero_is_ok);
|
|
RUN_TEST(test_worker_status_unrecognized_bit_is_unknown);
|
|
|
|
RUN_TEST(test_job_state_pend);
|
|
RUN_TEST(test_job_state_pend_psusp);
|
|
RUN_TEST(test_job_state_run);
|
|
RUN_TEST(test_job_state_run_ususp);
|
|
RUN_TEST(test_job_state_run_ssusp);
|
|
RUN_TEST(test_job_state_run_exit_fallback);
|
|
RUN_TEST(test_job_state_exit);
|
|
RUN_TEST(test_job_state_done);
|
|
RUN_TEST(test_job_state_error);
|
|
RUN_TEST(test_job_state_unknown_default);
|
|
|
|
RUN_TEST(test_format_job_time_zero_is_dash);
|
|
RUN_TEST(test_format_job_time_matches_ctrlstatus_formatter);
|
|
RUN_TEST(test_format_job_time_buffer_too_small_is_dash);
|
|
|
|
return UNITY_END();
|
|
}
|