From 4f653d8fbebbd6b66a66041da1408c8e909ca0f1 Mon Sep 17 00:00:00 2001 From: Rongsong Shen Date: Tue, 29 Sep 2026 04:23:46 +0000 Subject: [PATCH] feat(scheduler-sim-discrete-clock): --sim-speed deprecation-warning helper and discrete-clock test binary (task 1.1) Co-Authored-By: Claude Opus 5.5 (1M context) --- .../scheduler-sim-discrete-clock/tasks.md | 7 +- src/scheduler/include/cli_compat.h | 21 +++ src/scheduler/meson.build | 1 + src/scheduler/src/cli_compat.c | 24 +++ src/scheduler/testsuite/meson.build | 20 +++ .../testsuite/test_sim_discrete_clock.c | 161 ++++++++++++++++++ 6 files changed, 232 insertions(+), 2 deletions(-) create mode 100644 src/scheduler/include/cli_compat.h create mode 100644 src/scheduler/src/cli_compat.c create mode 100644 src/scheduler/testsuite/test_sim_discrete_clock.c diff --git a/.kiro/specs/scheduler-sim-discrete-clock/tasks.md b/.kiro/specs/scheduler-sim-discrete-clock/tasks.md index 8cfbf925..2c6cc23d 100644 --- a/.kiro/specs/scheduler-sim-discrete-clock/tasks.md +++ b/.kiro/specs/scheduler-sim-discrete-clock/tasks.md @@ -2,8 +2,8 @@ Test-first throughout (red → green → refactor). Every sub-task leaves the build and the scheduler suite green. The simulator's speed field and its shadow copy stay in place, unused, until the last core task removes them together with every test that sets them (design.md, File Structure Plan: build-order constraint). -- [ ] 1. Foundation: deprecation-warning helper and the new test binary -- [ ] 1.1 Add the `--sim-speed` deprecation-warning helper and register the new discrete-clock test binary +- [x] 1. Foundation: deprecation-warning helper and the new test binary +- [x] 1.1 Add the `--sim-speed` deprecation-warning helper and register the new discrete-clock test binary - Write the tests first, with a test-local stdout-capture helper and without initialising the logger (so warnings reach stdout): the values `0`, `abc`, `-1` and the empty string each produce exactly one line naming the value in quotes and containing `--sim-speed`, "deprecated", "no effect" and "will be removed"; no value produces no output. - Add the helper as its own small source (design.md, Components: CliCompat) and add it to the scheduler's source list only, not to the simulator-isolation library. - Register the new test binary in the scheduler suite with the same leak-detection setting as the other scheduler tests, a compile-time path to the built scheduler binary, and a build dependency on that binary. Its build sources are the new test file and the helper only, with the usual scheduler test dependencies; the white-box simulator `#include`s and the stand-in picker/allocator go into the test file itself in 2.1, as the other simulator tests do, not into the build file (listing the simulator sources there as well would define every symbol twice). @@ -65,3 +65,6 @@ Test-first throughout (red → green → refactor). Every sub-task leaves the bu - Run the HA soak skill, whose replay-verification step still passes `--sim-speed=0`, without modifying it. - Done when that step passes with zero mismatches and its log contains exactly one deprecation warning. - _Requirements: 5.3_ + +## Implementation Notes +- Build dir: `bash src/tools/xce-build.sh scheduler asan xce.build.discrete` builds into `src/xce.build.discrete`; iterate with `meson test -C src/xce.build.discrete --suite scheduler` and grep its testlog for `:FAIL`. diff --git a/src/scheduler/include/cli_compat.h b/src/scheduler/include/cli_compat.h new file mode 100644 index 00000000..c1de0a84 --- /dev/null +++ b/src/scheduler/include/cli_compat.h @@ -0,0 +1,21 @@ +#if !defined(_CLI_COMPAT_H_) + +#define _CLI_COMPAT_H_ 1 + +/* + * cli_compat.h - command-line compatibility shims for retired xce_scheduler + * options (scheduler-sim-discrete-clock spec, design.md, Components: + * CliCompat). + */ + +/* + * sched_cli_warn_deprecated_options - logs one WARN per deprecated option + * that was given. sim_speed is the raw --sim-speed value as argp stored it + * (the last occurrence), or NULL when the option was not given. + * + * Call once, after mylog_init(), before any mode-specific startup. Never + * fails, never exits, never parses the value (Req 2.3, 2.4, 2.5). + */ +void sched_cli_warn_deprecated_options(const char* sim_speed); + +#endif diff --git a/src/scheduler/meson.build b/src/scheduler/meson.build index b81d2028..ea115c0b 100644 --- a/src/scheduler/meson.build +++ b/src/scheduler/meson.build @@ -1,5 +1,6 @@ scheduler_srcs = [ 'src/main.c', + 'src/cli_compat.c', 'src/handler.c', 'src/scheduler.c', 'src/sched_election.c', diff --git a/src/scheduler/src/cli_compat.c b/src/scheduler/src/cli_compat.c new file mode 100644 index 00000000..29c241c3 --- /dev/null +++ b/src/scheduler/src/cli_compat.c @@ -0,0 +1,24 @@ +/* + * cli_compat.c - command-line compatibility shims for retired xce_scheduler + * options (scheduler-sim-discrete-clock spec, design.md, Components: + * CliCompat). One place to remove once the deprecated options are dropped. + */ + +#include "cli_compat.h" + +#include "utils.h" + +void sched_cli_warn_deprecated_options(const char* sim_speed) +{ + /* Req 2.5: option not given -> no warning. */ + if (sim_speed == NULL) { + return; + } + + /* Req 2.3/2.4: one warning for any value, never parsed; quoted so an + * empty value is visible as "". */ + WARN("xce_scheduler: --sim-speed \"%s\" is deprecated and has no effect " + "(the simulator clock moves only at recorded timestamps); it will " + "be removed in a future release", + sim_speed); +} diff --git a/src/scheduler/testsuite/meson.build b/src/scheduler/testsuite/meson.build index d4c112dd..42ed03c8 100644 --- a/src/scheduler/testsuite/meson.build +++ b/src/scheduler/testsuite/meson.build @@ -2333,3 +2333,23 @@ sched_alloc_from_stamp_test = executable( test('scheduler alloc from stamp test', sched_alloc_from_stamp_test, suite: 'scheduler', env: ['ASAN_OPTIONS=detect_leaks=0']) + +# scheduler-sim-discrete-clock spec (task 1.1, Req 2.3-2.5): unit tests for +# the --sim-speed deprecation warning (../src/cli_compat.c), and -- in later +# tasks -- the discrete-clock and end-to-end command-line tests. Sources are +# the test file and cli_compat.c ONLY: the white-box sim #includes live in +# the test file itself (listing sim sources here too would define every +# symbol twice). XCE_SCHEDULER_BIN points the end-to-end tests at the built +# xce_scheduler, which `depends: scheduler` guarantees is built first. +sched_sim_discrete_clock_test = executable( + 'sched_sim_discrete_clock_test', + ['test_sim_discrete_clock.c', '../src/cli_compat.c'], + include_directories:[incdir], + dependencies: [scheduler_test_deps, libedit_dep], + c_args: ['-DXCE_SCHEDULER_BIN="' + scheduler.full_path() + '"'], + install: false) + +test('scheduler sim discrete clock test', + sched_sim_discrete_clock_test, suite: 'scheduler', + env: ['ASAN_OPTIONS=detect_leaks=0'], + depends: scheduler) diff --git a/src/scheduler/testsuite/test_sim_discrete_clock.c b/src/scheduler/testsuite/test_sim_discrete_clock.c new file mode 100644 index 00000000..7e55dbcd --- /dev/null +++ b/src/scheduler/testsuite/test_sim_discrete_clock.c @@ -0,0 +1,161 @@ +/* + * test_sim_discrete_clock.c - tests for the scheduler-sim-discrete-clock + * spec. + * + * Task 1.1 (Requirements 2.3, 2.4, 2.5; design.md, Components: CliCompat, + * Testing Strategy: Unit (CliCompat)): sched_cli_warn_deprecated_options() + * logs exactly one warning naming the quoted --sim-speed value, stating it + * is deprecated, has no effect and will be removed, for ANY value (numeric, + * non-numeric, negative, empty), and logs nothing when the option was not + * given (NULL). + * + * This binary deliberately never calls mylog_init(): without it, tlog's + * early-print path writes WARN lines to stdout, which the test-local + * capture_stdout_around() below captures. + * + * XCE_SCHEDULER_BIN (compile-time, from the scheduler executable's + * full_path() in testsuite/meson.build) is used by the end-to-end tests + * later tasks add to this file. + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "cli_compat.h" + +#if !defined(XCE_SCHEDULER_BIN) +#error "XCE_SCHEDULER_BIN must be defined by testsuite/meson.build" +#endif + +void setUp(void) { return; } +void tearDown(void) { return; } + +/* ---------------------------------------------------------------------- */ +/* Fixture helpers -- test-local copy of the dup()/dup2() stdout capture */ +/* used by test_repl_help.c (each test file carries its own copy). */ +/* ---------------------------------------------------------------------- */ + +static const char* g_warn_value; + +static void call_warn_helper(void) +{ + sched_cli_warn_deprecated_options(g_warn_value); +} + +static char* capture_stdout_around(void (*fn)(void)) +{ + char tmp[] = "/tmp/xce_simclock_stdoutcap_XXXXXX"; + int fd = mkstemp(tmp); + int saved_stdout; + off_t len; + char* buf; + + TEST_ASSERT_TRUE_MESSAGE(fd >= 0, "mkstemp for stdout capture must " + "succeed"); + + fflush(stdout); + saved_stdout = dup(STDOUT_FILENO); + TEST_ASSERT_TRUE_MESSAGE(saved_stdout >= 0, "dup(STDOUT_FILENO) must " + "succeed"); + TEST_ASSERT_TRUE_MESSAGE(dup2(fd, STDOUT_FILENO) >= 0, + "dup2 redirect of STDOUT_FILENO must succeed"); + + fn(); + + fflush(stdout); + dup2(saved_stdout, STDOUT_FILENO); + close(saved_stdout); + + len = lseek(fd, 0, SEEK_CUR); + TEST_ASSERT_TRUE(len >= 0); + + buf = (char*)calloc(1, (size_t)len + 1); + TEST_ASSERT_NOT_NULL(buf); + if (len > 0) { + TEST_ASSERT_EQUAL_INT64((int64_t)len, (int64_t)pread(fd, buf, + (size_t)len, 0)); + } + close(fd); + unlink(tmp); + return buf; +} + +static int count_lines(const char* s) +{ + int n = 0; + + for (; *s != '\0'; s++) { + if (*s == '\n') { + n++; + } + } + return n; +} + +/* Asserts the captured output is exactly one line naming the quoted value + * and carrying every required phrase. */ +static void assert_one_warning_for(const char* value) +{ + char* out; + char quoted[64]; + + g_warn_value = value; + out = capture_stdout_around(call_warn_helper); + + snprintf(quoted, sizeof(quoted), "\"%s\"", value); + + TEST_ASSERT_EQUAL_INT_MESSAGE(1, count_lines(out), + "exactly one warning line expected"); + TEST_ASSERT_NOT_NULL_MESSAGE(strstr(out, quoted), + "warning must name the quoted value"); + TEST_ASSERT_NOT_NULL_MESSAGE(strstr(out, "--sim-speed"), + "warning must name --sim-speed"); + TEST_ASSERT_NOT_NULL_MESSAGE(strstr(out, "deprecated"), + "warning must say deprecated"); + TEST_ASSERT_NOT_NULL_MESSAGE(strstr(out, "no effect"), + "warning must say no effect"); + TEST_ASSERT_NOT_NULL_MESSAGE(strstr(out, "will be removed"), + "warning must say will be removed"); + free(out); +} + +/* ---------------------------------------------------------------------- */ +/* CliCompat (Requirements 2.3, 2.4, 2.5) */ +/* ---------------------------------------------------------------------- */ + +static void test_warn_numeric_zero_value(void) { assert_one_warning_for("0"); } + +static void test_warn_non_numeric_value(void) { assert_one_warning_for("abc"); } + +static void test_warn_negative_value(void) { assert_one_warning_for("-1"); } + +static void test_warn_empty_value(void) { assert_one_warning_for(""); } + +static void test_no_warning_when_option_absent(void) +{ + char* out; + + g_warn_value = NULL; + out = capture_stdout_around(call_warn_helper); + TEST_ASSERT_EQUAL_STRING_MESSAGE("", out, + "NULL (option not given) must log " + "nothing"); + free(out); +} + +int main(void) +{ + UNITY_BEGIN(); + RUN_TEST(test_warn_numeric_zero_value); + RUN_TEST(test_warn_non_numeric_value); + RUN_TEST(test_warn_negative_value); + RUN_TEST(test_warn_empty_value); + RUN_TEST(test_no_warning_when_option_absent); + return UNITY_END(); +}