Define xce_dispatch_fail_site_t/xce_dispatch_fail_class_t and xce_classify_dispatch_fail() in job.c, mapping each of dispatch_a_job_()'s six post-lookup failure points to retryable or terminal per Requirement 4.1/4.2. Standalone, not yet wired into dispatch_a_job_() (deferred to tasks 3.2/3.3). Also adds this spec's requirements/design/research/tasks docs (first commit touching this spec). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
114 lines
4.4 KiB
C
114 lines
4.4 KiB
C
/* test_job_dispatch.c -- scheduler-dispatch-commit task 1.1
|
|
*
|
|
* Unit tests for the Controller Dispatch-Failure Classification component
|
|
* (design.md, "Controller Dispatch-Failure Classification"): a pure, static,
|
|
* file-local function in job.c that maps each of dispatch_a_job_()'s six
|
|
* post-lookup failure points (xce_dispatch_fail_site_t) to a retryable-vs-
|
|
* terminal classification (xce_dispatch_fail_class_t), per Requirements
|
|
* 4.1/4.2.
|
|
*
|
|
* xce_classify_dispatch_fail() and its enum types are deliberately NOT
|
|
* declared in any header (design.md's own placement-correction note: nothing
|
|
* outside job.c consumes them). This test file reaches the static function
|
|
* through a thin, int-typed, XCE_TESTING-only wrapper exported from job.c
|
|
* (xce_classify_dispatch_fail_test), the same pattern job.c already uses for
|
|
* job_array_apply_test_set_force_fail_at()/friends -- and, like test_job_
|
|
* array_fence.c's ha_arm_promotion_fence_timer_for_test, the extern
|
|
* declaration lives directly in this test file rather than in a shared
|
|
* header.
|
|
*
|
|
* No cluster_t/persist/worker fixture is needed: the classification is a
|
|
* pure decision with no side effects, independently testable against every
|
|
* known failure case without a live dispatch attempt (task 1.1's own
|
|
* Observable-completion clause).
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <unity/unity.h>
|
|
|
|
/* Mirrors design.md's Service Interface enum values exactly (job.c's own
|
|
* xce_dispatch_fail_site_t/xce_dispatch_fail_class_t are file-local and not
|
|
* shared via a header -- this test drives the wrapper by the same plain-int
|
|
* values documented there, not by including a private type). */
|
|
#define SITE_WORKER_LOOKUP 0
|
|
#define SITE_WORKER_NULL 1
|
|
#define SITE_WORKER_NOT_READY 2
|
|
#define SITE_INVALID_ALLOC 3
|
|
#define SITE_QUEUE_EXEC 4
|
|
#define SITE_RPC_FAILURE 5
|
|
|
|
#define CLASS_RETRYABLE 0
|
|
#define CLASS_TERMINAL 1
|
|
|
|
extern int xce_classify_dispatch_fail_test(int site);
|
|
|
|
static void test_worker_lookup_is_retryable(void)
|
|
{
|
|
TEST_ASSERT_EQUAL_INT(CLASS_RETRYABLE,
|
|
xce_classify_dispatch_fail_test(SITE_WORKER_LOOKUP));
|
|
printf("test_worker_lookup_is_retryable: PASS\n");
|
|
}
|
|
|
|
static void test_worker_null_is_retryable(void)
|
|
{
|
|
TEST_ASSERT_EQUAL_INT(CLASS_RETRYABLE,
|
|
xce_classify_dispatch_fail_test(SITE_WORKER_NULL));
|
|
printf("test_worker_null_is_retryable: PASS\n");
|
|
}
|
|
|
|
static void test_worker_not_ready_is_retryable(void)
|
|
{
|
|
TEST_ASSERT_EQUAL_INT(CLASS_RETRYABLE, xce_classify_dispatch_fail_test(
|
|
SITE_WORKER_NOT_READY));
|
|
printf("test_worker_not_ready_is_retryable: PASS\n");
|
|
}
|
|
|
|
static void test_rpc_failure_is_retryable(void)
|
|
{
|
|
TEST_ASSERT_EQUAL_INT(CLASS_RETRYABLE,
|
|
xce_classify_dispatch_fail_test(SITE_RPC_FAILURE));
|
|
printf("test_rpc_failure_is_retryable: PASS\n");
|
|
}
|
|
|
|
static void test_invalid_alloc_is_terminal(void)
|
|
{
|
|
TEST_ASSERT_EQUAL_INT(CLASS_TERMINAL,
|
|
xce_classify_dispatch_fail_test(SITE_INVALID_ALLOC));
|
|
printf("test_invalid_alloc_is_terminal: PASS\n");
|
|
}
|
|
|
|
static void test_queue_exec_is_terminal(void)
|
|
{
|
|
TEST_ASSERT_EQUAL_INT(CLASS_TERMINAL,
|
|
xce_classify_dispatch_fail_test(SITE_QUEUE_EXEC));
|
|
printf("test_queue_exec_is_terminal: PASS\n");
|
|
}
|
|
|
|
/* Invariant (design.md Service Interface Postconditions): the same site
|
|
* always classifies the same way -- no hidden state, no time-dependence. */
|
|
static void test_classification_is_stable_across_repeated_calls(void)
|
|
{
|
|
int first = xce_classify_dispatch_fail_test(SITE_WORKER_NOT_READY);
|
|
int second = xce_classify_dispatch_fail_test(SITE_WORKER_NOT_READY);
|
|
int third = xce_classify_dispatch_fail_test(SITE_QUEUE_EXEC);
|
|
int fourth = xce_classify_dispatch_fail_test(SITE_QUEUE_EXEC);
|
|
|
|
TEST_ASSERT_EQUAL_INT(first, second);
|
|
TEST_ASSERT_EQUAL_INT(third, fourth);
|
|
printf("test_classification_is_stable_across_repeated_calls: PASS\n");
|
|
}
|
|
|
|
void test_job_dispatch(void)
|
|
{
|
|
UnitySetTestFile(__FILE__);
|
|
printf("\n>> dispatch-failure classification tests (Req 4.1, 4.2)\n\n");
|
|
|
|
RUN_TEST(test_worker_lookup_is_retryable);
|
|
RUN_TEST(test_worker_null_is_retryable);
|
|
RUN_TEST(test_worker_not_ready_is_retryable);
|
|
RUN_TEST(test_rpc_failure_is_retryable);
|
|
RUN_TEST(test_invalid_alloc_is_terminal);
|
|
RUN_TEST(test_queue_exec_is_terminal);
|
|
RUN_TEST(test_classification_is_stable_across_repeated_calls);
|
|
}
|