feat(resource-value-verification): extract resupdate type-resolution logic (task 1.1)
Move set_resval()'s resource-name lookup table into a new, dependency-light resval_typeresolve.c/.h module so it's independently unit-testable (test.c can't be white-box included into Unity). Adds RED tests for the not-yet- implemented numeric-fallback/type-override behavior (task 2.1). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
54ea3bc5b5
commit
98b8c34bec
5 changed files with 357 additions and 1 deletions
120
.kiro/specs/resource-value-verification/tasks.md
Normal file
120
.kiro/specs/resource-value-verification/tasks.md
Normal file
|
|
@ -0,0 +1,120 @@
|
||||||
|
# Implementation Plan
|
||||||
|
|
||||||
|
- [ ] 1. Foundation: test scaffolding and skill directory setup
|
||||||
|
- [x] 1.1 Extract resupdate's type-resolution logic and write failing unit tests for its fallback behavior
|
||||||
|
- Move `set_resval()`'s resource-name → `Value_u_which` table lookup into a new, small, dependency-light `resval_typeresolve.c`/`.h` module with no networking/REPL/global-state dependency — `test.c` (4298 lines, its own `main()`, heavy `libedit`/network dependencies) cannot itself be white-box included into a unit test, so this extraction is a hard prerequisite for testing this logic in isolation at all
|
||||||
|
- Create `test_resval_typeresolve.c` (Unity) and wire both new files into `src/controller/meson.build`: add `testsuite/resval_typeresolve.c` to `xce_test_src` (line 57) so `xce_test` still links, and add a new `test()` target for `test_resval_typeresolve.c` following the existing `controller_unit_test`/`sched_push_unit_test` pattern (lines 86, 215, 222) — these are hand-maintained explicit lists, not globs, so the module and test will not build without this step
|
||||||
|
- Write tests covering: a currently-known name (e.g. `mem`) still resolves numeric exactly as today; a currently-known string name (`type`) still resolves string exactly as today; an unrecognized name (e.g. `r15m`) defaults to numeric; an unrecognized name with an explicit type-override flag resolves to the requested type
|
||||||
|
- Observable completion: the new module and test target both compile and link via `meson`, and the new test target fails (RED) because the fallback-to-numeric and type-override behavior don't exist yet
|
||||||
|
- _Requirements: 1.1, 1.4_
|
||||||
|
|
||||||
|
- [ ] 1.2 (P) Scaffold the xce-test-resources skill directory
|
||||||
|
- Create the skill directory with a `SKILL.md` stub describing the intended usage (`/xce-test-resources [resource=value ...]`) and the VERDICT line format, following the `xce-test-ha`/`xce-deploy-ha` SKILL.md convention
|
||||||
|
- Observable completion: the skill is discoverable/invocable (even though its underlying script is not yet functional) and its documented contract matches design.md's Batch/Job Contract for the skill
|
||||||
|
- _Requirements: 6.1_
|
||||||
|
- _Boundary: xce-test-resources skill_
|
||||||
|
|
||||||
|
- [ ] 2. Core: resupdate resource-name coverage fix
|
||||||
|
- [ ] 2.1 Wire the extracted resolver into resupdate and add the type-override flag
|
||||||
|
- Extend `resval_typeresolve.c`'s fallback path so any resource name not in the existing table defaults to numeric (`Value_u_fvalue`), while `type`/`model` and all currently-supported names keep their exact existing behavior
|
||||||
|
- Make `test.c`'s `set_resval()` a thin wrapper delegating to `resval_typeresolve.c` (for type resolution) plus its own existing `.host` tagging (unchanged, still needs REPL state)
|
||||||
|
- Add an optional `-t <numeric|string>` flag to `cmd_resupdate()`, applied per `-n`/`-v` pair
|
||||||
|
- Observable completion: the unit tests from 1.1 pass (GREEN); running `resupdate -n r15m -v 1.5` in the worker context (against a live controller) now succeeds where it previously silently failed
|
||||||
|
- _Requirements: 1.1, 1.4_
|
||||||
|
- _Depends: 1.1_
|
||||||
|
|
||||||
|
- [ ] 2.2 Implement per-name accept/reject verification in resupdate
|
||||||
|
- After `cmd_resupdate()` sends the update RPC, issue one follow-up `xcecli_resval()` query per submitted `(resource, worker)` pair (the same client-library call `resval`/`cmd_resval` already uses) and compare the returned value against what was just sent
|
||||||
|
- Report "accepted" for a matching value, "rejected: unknown resource" for a not-found result, with a short bounded retry before concluding rejection (guards against a genuinely-registered resource whose value hasn't propagated to the query path yet)
|
||||||
|
- Report every submitted name's individual accept/reject outcome when a single invocation carries multiple `-n`/`-v` pairs
|
||||||
|
- Observable completion: against a live controller, `resupdate -n mem -v 5 -n not-a-real-resource -v 1` reports `mem` as accepted and `not-a-real-resource` as rejected, in the same invocation
|
||||||
|
- _Requirements: 1.2, 1.3_
|
||||||
|
- _Depends: 2.1_
|
||||||
|
|
||||||
|
- [ ] 3. Core: apiserver local deployment capability
|
||||||
|
- [ ] 3.1 (P) Extend `xce-deploy-ha`'s `deploy-ha.sh` with a conditional apiserver step and a combined `start-all.sh`
|
||||||
|
- In `deploy-ha.sh` Step 3, add a new conditional branch in the same *opt-in-by-presence* spirit as the existing worker/scheduler branch: check for a pre-built apiserver binary at its own Go-build output path (e.g. `/tmp/apiserver`, `make build-server`'s default) — NOT alongside `$BINARY`, since apiserver is a separate build system, not the same meson build dir worker/scheduler share; `deploy-ha.sh` does not invoke `make build-server` itself, building it remains a caller prerequisite (document in SKILL.md's Prerequisites section, same pattern as the existing `/xce-build controller` note). If present, generate `$TOP/scripts/start-apiserver.sh` plus a minimal `logger.yaml` (modeled on `make test-integration`'s `XCE_BIN`/`SRV_URL` convention) — functional auth/RBAC is NOT required (verification is trace-log-based, task 6.4; no REST query is ever issued against this instance), but `logger.yaml` MUST set `logging.level: debug` or task 4.2's trace line is silently never written; absent the binary, generate nothing, so existing callers are unaffected
|
||||||
|
- Also in Step 3, always generate `$TOP/scripts/start-all.sh`: runs `start.sh` for the controller node(s), waits on Step 5's existing health-check, then runs whichever of `start-worker.sh`/`start-scheduler.sh`/`start-apiserver.sh` were actually generated for this deploy (skipping any that weren't) — start the scheduler with `-vvv` specifically (verbosity 3, matching `tlog_debug3`/`TRACE`), overriding SKILL.md's existing `-v`-only example for this feature's needs, or task 4.1's trace line is silently never written
|
||||||
|
- Update `.claude/skills/xce-deploy-ha/SKILL.md` with a new "Step 4d" documenting the apiserver step (following the existing Step 4b pattern) and documenting `start-all.sh` as a combined shortcut for Steps 4/4b/4c
|
||||||
|
- Write apiserver/scheduler logs under the caller's scratch directory, matching the existing `logs/` convention — these are the logs tasks 6.3/6.4 grep
|
||||||
|
- Observable completion: running `deploy-ha.sh` against a build that includes an apiserver binary, then `start-all.sh`, leaves a running controller, scheduler (at `-vvv`), and apiserver (with debug-level logging) with no further manual steps; running `deploy-ha.sh` against a build without an apiserver binary (e.g. `xce-test-ha`'s existing usage) is unaffected — no `start-apiserver.sh` is generated, and `start-all.sh` skips that step
|
||||||
|
- _Requirements: 5.3, 6.1_
|
||||||
|
- _Boundary: xce-deploy-ha (deploy-ha.sh, SKILL.md)_
|
||||||
|
|
||||||
|
- [ ] 4. Core: scheduler and apiserver trace-log instrumentation
|
||||||
|
- [ ] 4.1 (P) Add a trace log line to the scheduler's live resource-update handling
|
||||||
|
- In `xce_core_push_events()`'s `XCE_CORE_EVENT_RESVALS_DELTA` case (`src/scheduler/src/core_events.c`), add one `TRACE`-level log line (this component's existing `tinylog` convention) immediately after the resolved worker's value is written, logging the resolved host, resource name, and applied value in a fixed, greppable format
|
||||||
|
- Confirm the existing scheduler testsuite (`test_core_events.c` and friends) still passes unchanged — this is a pure log addition with no control-flow change, so no new unit test is required (consistent with this codebase's existing precedent: other `TRACE`/`WARN` calls in this area, e.g. `apiserver_worker_change`, have no dedicated unit test coverage either); the log line's actual content/format is confirmed live in task 8.1
|
||||||
|
- Observable completion: a live scheduler daemon's log file contains one line per applied resource update, in the format task 6.3 will grep for; existing scheduler tests are unaffected
|
||||||
|
- _Requirements: 4.1, 4.2, 4.3_
|
||||||
|
|
||||||
|
- [ ] 4.2 (P) Add a trace log line to the apiserver's resource-update storage handling
|
||||||
|
- In `OnResourceLocationUpdated` (`src/frontend/apiserver/backend/handler.go:92-95`), add one `logger.Debug(...)` call (zap, per this component's existing convention) immediately after `store.ResourceLocations.Put(key, *res)`, logging the resource name, location/host, and stored value
|
||||||
|
- Confirm existing apiserver backend tests still pass unchanged — same rationale as 4.1, no new unit test required for a pure log addition; content/format confirmed live in task 8.1
|
||||||
|
- Observable completion: a live apiserver's log file contains one line per stored resource-location update, in the format task 6.4 will grep for; existing backend tests are unaffected
|
||||||
|
- _Requirements: 5.1, 5.2, 5.4_
|
||||||
|
|
||||||
|
- [ ] 5. Integration: full-stack deployment orchestration
|
||||||
|
- [ ] 5.1 Wire controller, scheduler, and apiserver deployment into the skill via `start-all.sh`
|
||||||
|
- Invoke `xce-deploy-ha`'s `deploy-ha.sh` (task 3.1) into a fresh scratch directory, then its generated `start-all.sh` — no manual per-component sequencing lives in this skill; `start-all.sh` already gates scheduler/apiserver startup on the controller health-check and handles the `-vvv`/debug-level logging needed for tasks 4.1/4.2's trace lines
|
||||||
|
- Register a `trap`-based cleanup (or equivalent) before invoking `start-all.sh`, not just at the end of the script — this must cover a mid-deployment abort (e.g. apiserver fails to start after controller+scheduler are already up), not only a completed PASS/FAIL run; deliberately stronger than `xce-deploy-ha`'s own convention (a separate, manually-invoked `cleanup.sh`) because Requirement 6.5 requires cleanup-by-default on every path unless the operator passed the "keep running" flag
|
||||||
|
- Observable completion: a single invocation of the orchestration script leaves a running controller, live scheduler daemon (built with task 4.1's trace log, started at `-vvv`), and apiserver (built with task 4.2's trace log, debug-level logging enabled), all logging under the same scratch directory, with no manual steps; killing the script mid-deployment (e.g. before the apiserver step completes) still removes every process it had already started, unless "keep running" was passed
|
||||||
|
- _Requirements: 5.3, 6.1, 6.5_
|
||||||
|
- _Depends: 1.2, 3.1, 4.1, 4.2_
|
||||||
|
|
||||||
|
- [ ] 6. Core: resource injection and per-layer verification checks
|
||||||
|
- [ ] 6.1 Implement worker join and resource injection
|
||||||
|
- Join a synthetic worker through the `xce_test` worker context (no real worker daemon process), then run `resupdate` for one or more resource names/values
|
||||||
|
- Observable completion: after this step runs, `resupdate` has been accepted for every requested resource name with zero real worker daemon processes running
|
||||||
|
- _Requirements: 2.1, 2.2, 6.1, 6.4_
|
||||||
|
- _Depends: 2.1, 2.2, 5.1_
|
||||||
|
|
||||||
|
- [ ] 6.2 Implement the controller-side verification check
|
||||||
|
- Query the controller via `resval` for each injected resource/worker pair and compare against the injected value
|
||||||
|
- Observable completion: the check reports, per resource, whether the controller's observed value matches the injected value, including both values when it does not
|
||||||
|
- _Requirements: 3.1, 3.2_
|
||||||
|
- _Depends: 6.1_
|
||||||
|
- _Boundary: xce-test-resources skill (controller check) — same file as 6.3/6.4 (`run-resource-verify.sh`), sequential, not parallel-safe_
|
||||||
|
|
||||||
|
- [ ] 6.3 Implement the scheduler-side verification check via trace-log tail
|
||||||
|
- Tail/grep the live scheduler daemon's log file (task 4.1's trace line) for each injected resource/worker pair, polling with a short interval up to a generous, explicit bounded wait — no record, no replay, no REPL
|
||||||
|
- Compare the scheduler's observed value against the injected value, reported distinctly from the controller-side result; a timeout with no matching line is reported as "unreachable," distinct from a value mismatch
|
||||||
|
- Observable completion: the check reports, per resource, whether the scheduler's observed value matches the injected value within the bounded wait, attributable specifically to the scheduler layer
|
||||||
|
- _Requirements: 4.1, 4.2, 4.3_
|
||||||
|
- _Depends: 6.1, 6.2_
|
||||||
|
- _Boundary: xce-test-resources skill (scheduler check) — same file as 6.2/6.4, sequential_
|
||||||
|
|
||||||
|
- [ ] 6.4 Implement the apiserver-side verification check via trace-log tail
|
||||||
|
- Tail/grep the live apiserver's log file (task 4.2's trace line) for each injected resource/worker pair, polling with a short interval up to a generous, explicit bounded wait — no `xcecli` query, no REST call
|
||||||
|
- Compare the apiserver's observed value against the injected value, reported distinctly from the controller-side and scheduler-side results; a timeout with no matching line is reported as "unreachable," distinct from a value mismatch
|
||||||
|
- Observable completion: the check reports, per resource, whether the apiserver's observed value matches the injected value within the bounded wait, attributable specifically to the apiserver layer
|
||||||
|
- _Requirements: 5.1, 5.2, 5.4_
|
||||||
|
- _Depends: 6.1, 6.3_
|
||||||
|
- _Boundary: xce-test-resources skill (apiserver check) — same file as 6.2/6.3, sequential_
|
||||||
|
|
||||||
|
- [ ] 7. Integration: verdict aggregation, reporting, and cleanup
|
||||||
|
- [ ] 7.1 Aggregate layer results, emit the verdict, and clean up
|
||||||
|
- Combine the controller/scheduler/apiserver check results into a single per-resource, per-layer comparison, implemented as a self-contained comparison step that accepts a set of (resource, injected value, per-layer observed value) records — so it can be invoked directly with synthetic records for testing (task 8.2), not only reachable from a live run
|
||||||
|
- Emit a machine-parseable VERDICT line (following `xce-test-ha`'s convention) plus the standard terminal PASS/FAIL oracle line, naming every layer that mismatched or was unreachable (timed out)
|
||||||
|
- Support checking multiple resource names in one run, defaulting to the resource names added in task 2.1 when none are supplied
|
||||||
|
- Clean up every process and runtime/data-directory artifact this run created, unless the operator passed a flag requesting the deployment be left running — this is the normal-completion firing of the same trap-based cleanup task 5.1 registered for the abort path, not a separate mechanism. **Log files under the scratch directory are always preserved**, regardless of the keep-running flag, so a FAIL verdict's underlying scheduler/apiserver trace-log evidence remains inspectable after the run
|
||||||
|
- Observable completion: a full run against the default resource set produces exactly one VERDICT line and a matching process exit code, no controller/scheduler/apiserver processes remain afterward (unless the keep-running flag was used), and the run's log files are still present on disk regardless
|
||||||
|
- _Requirements: 6.2, 6.3, 6.4, 6.5_
|
||||||
|
- _Depends: 6.2, 6.3, 6.4_
|
||||||
|
|
||||||
|
- [ ] 8. Validation: end-to-end live verification runs
|
||||||
|
- [ ] 8.1 Run the full flow live, including one deliberately-unregistered resource name
|
||||||
|
- Execute the skill end-to-end against a freshly deployed controller/scheduler/apiserver, using the default resource set (task 2.1's previously-missing names) plus one resource name that does not exist in the cluster's registered set
|
||||||
|
- Observable completion: every genuinely-registered resource individually reports matching values at all three layers (confirming tasks 4.1/4.2's trace-log lines are correctly formatted and greppable, not just present), AND the unregistered name is reported as a clear, specifically-identified rejection (not a silent omission) with correct per-name accept/reject accounting across the whole batch; per design.md's Error Handling (an unrecognized name is a run-level failure), the run's single overall VERDICT is FAIL, attributable specifically to the unregistered name — not a false overall PASS
|
||||||
|
- _Requirements: 1.1, 1.2, 1.3, 1.4, 2.1, 2.2, 3.1, 3.2, 4.1, 4.2, 4.3, 5.1, 5.2, 5.3, 5.4, 6.1, 6.2, 6.4_
|
||||||
|
- _Depends: 7.1_
|
||||||
|
|
||||||
|
- [ ] 8.2 Verify the verdict logic correctly reports FAIL on a genuine mismatch
|
||||||
|
- Invoke task 7.1's comparison step directly with a synthetic set of per-layer observed-value records where one layer's value deliberately does not match the corresponding injected value (no live deployment required for this check, since the comparison step is self-contained per task 7.1)
|
||||||
|
- Observable completion: the comparison step reports an overall FAIL verdict that correctly names the specific layer whose synthetic record was mismatched, and reports PASS for every other, matching layer/resource in the same input set — proving the verdict logic distinguishes pass from fail rather than always reporting PASS
|
||||||
|
- _Requirements: 6.3_
|
||||||
|
- _Depends: 7.1_
|
||||||
|
|
||||||
|
## Implementation Notes
|
||||||
|
- Task 1.1: `resval_typeresolve.c`'s new function is `int resval_resolve_type(const char* name, int type_override)`, returning a `Value_u_which` tag or `RESVAL_TYPE_UNKNOWN` (-1, doesn't collide with the real 0-6 enum range). Task 2.1 should build on this exact signature rather than inventing a new one. `test.c`'s `set_resval()`/`cmd_resupdate()` were deliberately left untouched by task 1.1 — task 2.1 is the one that makes `set_resval()` a thin wrapper.
|
||||||
|
- `controller_unit_test` (the big legacy Unity binary) has a pre-existing, unrelated flaky failure in `test_config_repl.c` (bug-1561, overlayfs `fdatasync errno=5` sandbox artifact) that shows up on every `/xce-build controller` run in this environment. It is NOT caused by this feature's changes — do not chase it in later tasks; cross-check `.wolf/buglog.json`'s bug-1561 entry before treating a `controller_unit_test` failure as real, and confirm via `git status` that `test_config_repl.c`/`config_repl.c` are untouched by the current task's diff.
|
||||||
|
|
@ -54,7 +54,7 @@ controller = executable('xce_controller',
|
||||||
link_args: wrap_link_args,
|
link_args: wrap_link_args,
|
||||||
install: true)
|
install: true)
|
||||||
|
|
||||||
xce_test_src = [ 'testsuite/test.c', 'testsuite/waldump.c', 'testsuite/walcompare.c', 'testsuite/snapverify.c', 'testsuite/snapdiff.c', 'testsuite/configcompare.c']
|
xce_test_src = [ 'testsuite/test.c', 'testsuite/waldump.c', 'testsuite/walcompare.c', 'testsuite/snapverify.c', 'testsuite/snapdiff.c', 'testsuite/configcompare.c', 'testsuite/resval_typeresolve.c']
|
||||||
|
|
||||||
# BSD-licensed readline replacement (scheduler-core spec, task 12.1 review
|
# BSD-licensed readline replacement (scheduler-core spec, task 12.1 review
|
||||||
# finding): GNU readline is GPL; xce_test's REPL only needs readline()/
|
# finding): GNU readline is GPL; xce_test's REPL only needs readline()/
|
||||||
|
|
@ -283,3 +283,29 @@ test('apiserver push test', apiserver_push_unit_test,
|
||||||
timeout: 60,
|
timeout: 60,
|
||||||
env: ['ASAN_OPTIONS=detect_leaks=0'])
|
env: ['ASAN_OPTIONS=detect_leaks=0'])
|
||||||
|
|
||||||
|
# resource-value-verification task 1.1: resval_typeresolve.c is a small,
|
||||||
|
# dependency-light module (no networking/REPL/global state) extracted from
|
||||||
|
# test.c's set_resval() specifically so its name -> Value_u_which resolution
|
||||||
|
# logic can be unit-tested in isolation -- test.c itself (4298 lines, its own
|
||||||
|
# main(), heavy libedit/network dependencies) cannot be white-box included
|
||||||
|
# into a Unity test. Standalone binary (not folded into controller_unit_test_
|
||||||
|
# src) since it has zero dependency on controller.c/cluster.c internals,
|
||||||
|
# mirroring sched_push_unit_test's/apiserver_push_unit_test's own standalone-
|
||||||
|
# binary rationale above.
|
||||||
|
resval_typeresolve_unit_test_src = [
|
||||||
|
'testsuite/test_resval_typeresolve.c',
|
||||||
|
'testsuite/resval_typeresolve.c',
|
||||||
|
]
|
||||||
|
|
||||||
|
resval_typeresolve_unit_test = executable('resval_typeresolve_unit_test',
|
||||||
|
resval_typeresolve_unit_test_src,
|
||||||
|
include_directories: [incdir],
|
||||||
|
dependencies: controller_unit_test_deps,
|
||||||
|
c_args: ['-DXCE_TESTING'],
|
||||||
|
install: false)
|
||||||
|
|
||||||
|
test('resval typeresolve test', resval_typeresolve_unit_test,
|
||||||
|
suite: 'controller',
|
||||||
|
timeout: 60,
|
||||||
|
env: ['ASAN_OPTIONS=detect_leaks=0'])
|
||||||
|
|
||||||
|
|
|
||||||
53
src/controller/testsuite/resval_typeresolve.c
Normal file
53
src/controller/testsuite/resval_typeresolve.c
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
/* resval_typeresolve.c -- resource-value-verification task 1.1
|
||||||
|
*
|
||||||
|
* See resval_typeresolve.h for the full rationale and TASK 1.1 STATUS note.
|
||||||
|
*/
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "resval_typeresolve.h"
|
||||||
|
|
||||||
|
int resval_resolve_type(const char* name, int type_override)
|
||||||
|
{
|
||||||
|
/* Verbatim extraction of set_resval()'s resinfo[] table (test.c),
|
||||||
|
* unchanged: type/model are Value_u_svalue; everything else here is
|
||||||
|
* Value_u_fvalue. */
|
||||||
|
static const struct {
|
||||||
|
const char* name;
|
||||||
|
int valtype;
|
||||||
|
} resinfo[] = {
|
||||||
|
{ "r15s", Value_u_fvalue },
|
||||||
|
{ "r1m", Value_u_fvalue },
|
||||||
|
{ "slots", Value_u_fvalue },
|
||||||
|
{ "ut", Value_u_fvalue },
|
||||||
|
{ "mem", Value_u_fvalue },
|
||||||
|
{ "maxcpus", Value_u_fvalue },
|
||||||
|
{ "ndisks", Value_u_fvalue },
|
||||||
|
{ "cpuf", Value_u_fvalue },
|
||||||
|
{ "maxswap", Value_u_fvalue },
|
||||||
|
{ "maxtmp", Value_u_fvalue },
|
||||||
|
{ "type", Value_u_svalue },
|
||||||
|
{ "model", Value_u_svalue },
|
||||||
|
{ "verilog", Value_u_fvalue },
|
||||||
|
{ "dyna", Value_u_fvalue },
|
||||||
|
{ NULL, 0 }
|
||||||
|
};
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* task 2.1 wires this in for the unrecognized-name numeric-default
|
||||||
|
* fallback / explicit-override path (Requirement 1.1/1.4); until then
|
||||||
|
* it has no effect -- an unrecognized name always returns
|
||||||
|
* RESVAL_TYPE_UNKNOWN below, regardless of what was passed here. */
|
||||||
|
(void)type_override;
|
||||||
|
|
||||||
|
if (name == NULL) {
|
||||||
|
return RESVAL_TYPE_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; resinfo[i].name != NULL; i++) {
|
||||||
|
if (strcmp(resinfo[i].name, name) == 0) {
|
||||||
|
return resinfo[i].valtype;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return RESVAL_TYPE_UNKNOWN;
|
||||||
|
}
|
||||||
52
src/controller/testsuite/resval_typeresolve.h
Normal file
52
src/controller/testsuite/resval_typeresolve.h
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
#ifndef RESVAL_TYPERESOLVE_H
|
||||||
|
#define RESVAL_TYPERESOLVE_H
|
||||||
|
|
||||||
|
/* resval_typeresolve.h -- resource-value-verification task 1.1
|
||||||
|
*
|
||||||
|
* Extracted from test.c's set_resval(): pure resource-name -> wire-type
|
||||||
|
* resolution logic, with NO networking, REPL, or global-state dependency
|
||||||
|
* (unlike set_resval() itself, which also allocates xce_val_t and tags
|
||||||
|
* .host via get_setting("myname") -- that stays in test.c since it needs
|
||||||
|
* REPL state). This isolation is what makes the logic unit-testable outside
|
||||||
|
* of test.c, which cannot be white-box #include'd into a Unity test (4298
|
||||||
|
* lines, its own main(), heavy libedit/network dependencies).
|
||||||
|
*
|
||||||
|
* The resolved type is a Value_u_which tag (controller.capnp.h) -- e.g.
|
||||||
|
* Value_u_fvalue for a numeric resource, Value_u_svalue for a string one.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "controller.capnp.h" /* enum Value_u_which */
|
||||||
|
|
||||||
|
/* Sentinel: not a valid Value_u_which value. Used both as:
|
||||||
|
* - the RETURN value when `name` is not present in the known-resource
|
||||||
|
* table and no override applies;
|
||||||
|
* - the `type_override` INPUT value meaning "no override requested".
|
||||||
|
*/
|
||||||
|
#define RESVAL_TYPE_UNKNOWN (-1)
|
||||||
|
|
||||||
|
/* Resolve `name` to its Value_u_which wire type.
|
||||||
|
*
|
||||||
|
* `type_override`: pass a valid Value_u_which value (Value_u_fvalue,
|
||||||
|
* Value_u_svalue, ...) to request that type for a name not in the known-
|
||||||
|
* resource table, or RESVAL_TYPE_UNKNOWN for no override.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* - the table's type, for any of the 14 currently-known resource names
|
||||||
|
* (r15s, r1m, slots, ut, mem, maxcpus, ndisks, cpuf, maxswap, maxtmp,
|
||||||
|
* type, model, verilog, dyna) -- `type_override` is ignored for a known
|
||||||
|
* name, exactly as set_resval() behaves today.
|
||||||
|
* - RESVAL_TYPE_UNKNOWN, for `name` == NULL or a name not in the table.
|
||||||
|
*
|
||||||
|
* *** TASK 1.1 STATUS (non-behavioral extraction) ***
|
||||||
|
* This is a byte-for-byte extraction of set_resval()'s existing resinfo[]
|
||||||
|
* table lookup -- current behavior for every one of the 14 known names is
|
||||||
|
* UNCHANGED. The numeric-by-default fallback for an unrecognized name, and
|
||||||
|
* honoring `type_override` for one, are Requirement 1.1/1.4 behavior that
|
||||||
|
* task 2.1 implements on top of this same signature -- until then,
|
||||||
|
* `type_override` is accepted but ignored, and an unrecognized name always
|
||||||
|
* returns RESVAL_TYPE_UNKNOWN regardless of `type_override`. See
|
||||||
|
* test_resval_typeresolve.c for the RED tests documenting this gap.
|
||||||
|
*/
|
||||||
|
int resval_resolve_type(const char* name, int type_override);
|
||||||
|
|
||||||
|
#endif /* RESVAL_TYPERESOLVE_H */
|
||||||
105
src/controller/testsuite/test_resval_typeresolve.c
Normal file
105
src/controller/testsuite/test_resval_typeresolve.c
Normal file
|
|
@ -0,0 +1,105 @@
|
||||||
|
/* test_resval_typeresolve.c -- resource-value-verification task 1.1
|
||||||
|
*
|
||||||
|
* Unity unit tests for resval_typeresolve.c's resource-name -> Value_u_which
|
||||||
|
* resolution, extracted from test.c's set_resval() (design.md "Testing
|
||||||
|
* Strategy"). Four cases, matching tasks.md task 1.1 exactly:
|
||||||
|
*
|
||||||
|
* 1. A currently-known numeric name (mem) resolves Value_u_fvalue, exactly
|
||||||
|
* as today (Requirement 1.4) -- GREEN.
|
||||||
|
* 2. A currently-known string name (type) resolves Value_u_svalue, exactly
|
||||||
|
* as today (Requirement 1.4) -- GREEN.
|
||||||
|
* 3. An unrecognized name (r15m) defaults to numeric (Requirement 1.1) --
|
||||||
|
* RED: task 2.1 has not yet implemented the fallback.
|
||||||
|
* 4. An unrecognized name with an explicit type-override resolves to the
|
||||||
|
* requested type (Requirement 1.1) -- RED: task 2.1 has not yet wired
|
||||||
|
* `type_override` in.
|
||||||
|
*
|
||||||
|
* Cases 3 and 4 are INTENTIONALLY FAILING (RED) evidence for this task --
|
||||||
|
* see resval_typeresolve.h's "TASK 1.1 STATUS" note and tasks.md task 2.1,
|
||||||
|
* which implements the behavior these two cases assert.
|
||||||
|
*/
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <unity/unity.h>
|
||||||
|
|
||||||
|
#include "resval_typeresolve.h"
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* Tests */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
/* 1. Currently-known numeric name -- unchanged behavior (GREEN). */
|
||||||
|
static void test_known_numeric_name_resolves_fvalue(void)
|
||||||
|
{
|
||||||
|
int rc = resval_resolve_type("mem", RESVAL_TYPE_UNKNOWN);
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_INT_MESSAGE(
|
||||||
|
Value_u_fvalue, rc,
|
||||||
|
"a currently-known numeric resource name (mem) must still resolve "
|
||||||
|
"Value_u_fvalue exactly as set_resval() does today");
|
||||||
|
printf("test_known_numeric_name_resolves_fvalue: PASS\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 2. Currently-known string name -- unchanged behavior (GREEN). */
|
||||||
|
static void test_known_string_name_resolves_svalue(void)
|
||||||
|
{
|
||||||
|
int rc = resval_resolve_type("type", RESVAL_TYPE_UNKNOWN);
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_INT_MESSAGE(
|
||||||
|
Value_u_svalue, rc,
|
||||||
|
"a currently-known string resource name (type) must still resolve "
|
||||||
|
"Value_u_svalue exactly as set_resval() does today");
|
||||||
|
printf("test_known_string_name_resolves_svalue: PASS\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 3. Unrecognized name defaults to numeric -- RED (task 2.1 implements). */
|
||||||
|
static void test_unrecognized_name_defaults_to_numeric(void)
|
||||||
|
{
|
||||||
|
int rc = resval_resolve_type("r15m", RESVAL_TYPE_UNKNOWN);
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_INT_MESSAGE(
|
||||||
|
Value_u_fvalue, rc,
|
||||||
|
"an unrecognized resource name (r15m) with no type override must "
|
||||||
|
"default to Value_u_fvalue (Requirement 1.1) -- NOT YET "
|
||||||
|
"IMPLEMENTED, expected RED until task 2.1");
|
||||||
|
printf("test_unrecognized_name_defaults_to_numeric: PASS\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 4. Unrecognized name + explicit override -- RED (task 2.1 implements). */
|
||||||
|
static void test_unrecognized_name_with_override_resolves_requested_type(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
int rc = resval_resolve_type("r15m", Value_u_svalue);
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_INT_MESSAGE(
|
||||||
|
Value_u_svalue, rc,
|
||||||
|
"an unrecognized resource name (r15m) with an explicit type "
|
||||||
|
"override must resolve to the requested type (Requirement 1.1) -- "
|
||||||
|
"NOT YET IMPLEMENTED, expected RED until task 2.1");
|
||||||
|
printf(
|
||||||
|
"test_unrecognized_name_with_override_resolves_requested_type: "
|
||||||
|
"PASS\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* Standalone Unity main (this binary is its own test executable -- see */
|
||||||
|
/* meson.build's resval_typeresolve_unit_test) */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
void setUp(void) { return; }
|
||||||
|
void tearDown(void) { return; }
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
printf("\n>> resource-value-verification task 1.1: resval_typeresolve "
|
||||||
|
"type resolution\n\n");
|
||||||
|
|
||||||
|
UNITY_BEGIN();
|
||||||
|
|
||||||
|
RUN_TEST(test_known_numeric_name_resolves_fvalue);
|
||||||
|
RUN_TEST(test_known_string_name_resolves_svalue);
|
||||||
|
RUN_TEST(test_unrecognized_name_defaults_to_numeric);
|
||||||
|
RUN_TEST(test_unrecognized_name_with_override_resolves_requested_type);
|
||||||
|
|
||||||
|
return UNITY_END();
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue