Skip to content

Add a CLI regression test target - #330

Open
1a1a11a wants to merge 1 commit into
claude/polish-4-registry-hashpowerfrom
claude/polish-5-cli-tests
Open

Add a CLI regression test target#330
1a1a11a wants to merge 1 commit into
claude/polish-4-registry-hashpowerfrom
claude/polish-5-cli-tests

Conversation

@1a1a11a

@1a1a11a 1a1a11a commented Aug 13, 2026

Copy link
Copy Markdown
Owner

Part 5 of 5, split out of #324. Stacked on #329 — the diff shown here is against that branch; merge #328 and #329 first.

Two files: test/test_cli.sh and its test/CMakeLists.txt wiring, as a new testCLI ctest target. 174 checks over ground nothing covered before.

Why a shell target rather than more C unit tests

The existing C tests build caches in-process. Every bug fixed in #328 and #329 lives in the path between the command line and that point — argp callbacks, parameter parsing, the -e print early exit — or only becomes visible when a binary runs to completion. So this drives the actual binaries.

Two design choices carried most of the value:

  • It sweeps all 45 registered algorithms rather than a hand-picked list. That is how the s3fifov0 and flashProb crashes were found; both were absent from every list I would have written by hand.
  • It replays a trace with each algorithm rather than only parsing parameters. That is what surfaces the missing frees: -e print calls exit(0) before teardown, and LeakSanitizer still counts that memory as reachable, so a parse-only test sees nothing.

Invalid input is asserted to fail cleanly — non-zero with a message, but not SIGSEGV, SIGFPE or SIGBUS. The project's ERROR() aborts, so a deliberate rejection has to stay distinguishable from a crash, and several of these bugs presented as exactly that difference.

Coverage

  • the option forms that were crashing: space-separated -o, --verbose, -e print for every algorithm
  • SLRU n-seg at 0/-1/4/16/20 and seg-size empty / 0:0 / 24 entries
  • SHARDS at sample rates 1, 0.999, 0.5 and 0.0001, plus FIX_SIZE — rate 1 is the undefined-behavior case, where UINT64_MAX * sample_rate rounds to 2^64 and overflows the cast
  • MINISIM asserted equal to cachesim on unsampled runs, not merely exiting 0, so the size-scaling bug cannot come back quietly
  • belady and beladySize accepted on oracle traces and rejected on others
  • --hashpower at 4, 5, 6 and 8 across the composite policies
  • wtinyLFU --consider-obj-metadata=true, which used to segfault
  • a string-id csv asserting the miss ratio that four distinct objects in six requests produce, so a regression to obj_id = 0 fails the test rather than returning a believable number

Are the tests load-bearing?

Green tests prove nothing on their own, so I checked the other direction: reverting the six originally-fixed sources to their previous state and rebuilding gives 16 failures, and 0 with them restored.

Testing

ctest --output-on-failure10/10, both plain Release and under -fsanitize=leak with CI's ASAN_OPTIONS.


Generated by Claude Code

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3c8b06a379

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread test/test_cli.sh Outdated
Comment on lines +175 to +179
ALL_ALGOS="2q 3LCache CAR GLCache RandomLRU arc arcv0 cacheus clock clock2qplus
clockpro fifo fifo-merge fifo-reinsertion fifomerge flashProb gdsf gl-cache
lecar lecarv0 lfu lfucpp lfuda lhd lirs lrb lru lru-k lru-prob nop
pluginCache qdlp random randomTwo s3-fifo s3-fifov0 s3fifo s3fifod s3fifov0
sieve size slru slruv0 tinyLFU twoq wtinyLFU"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Add the omitted registered algorithms to the sweeps

ALL_ALGOS omits hyperbolic, belady, and beladySize, although all three are registered in libCacheSim/cache/cacheAlgoRegistry.c and the selected oracle trace makes the Belady policies valid. Consequently, neither the -e print sweep nor the replay sweep exercises their cachesim initialization and teardown paths, so regressions in these built-in algorithms can pass this target despite the stated all-algorithm coverage; the later Belady MINISIM checks exercise a different executable path and do not close this gap.

Useful? React with 👍 / 👎.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new CLI-focused regression test to the test/ suite to exercise end-to-end argument parsing and “run to completion” behavior that isn’t covered by in-process C unit tests. This fits into the codebase’s CTest-driven testing by introducing a testCLI target that runs a shell script from the build directory.

Changes:

  • Add test/test_cli.sh, a bash-based regression suite that drives cachesim, traceAnalyzer, and mrcProfiler across many option/parameter combinations.
  • Wire the script into CTest as a new testCLI test via test/CMakeLists.txt.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
test/test_cli.sh New bash regression suite that runs CLI binaries and asserts clean failures vs crashes across many parameter/option cases.
test/CMakeLists.txt Registers the new testCLI CTest target to run the shell regression suite from the build directory.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread test/test_cli.sh Outdated
Comment on lines +175 to +179
ALL_ALGOS="2q 3LCache CAR GLCache RandomLRU arc arcv0 cacheus clock clock2qplus
clockpro fifo fifo-merge fifo-reinsertion fifomerge flashProb gdsf gl-cache
lecar lecarv0 lfu lfucpp lfuda lhd lirs lrb lru lru-k lru-prob nop
pluginCache qdlp random randomTwo s3-fifo s3-fifov0 s3fifo s3fifod s3fifov0
sieve size slru slruv0 tinyLFU twoq wtinyLFU"
Comment thread test/CMakeLists.txt
Comment on lines +66 to +68
add_test(NAME testCLI
COMMAND ${CMAKE_COMMAND} -E env bash ${CMAKE_CURRENT_SOURCE_DIR}/test_cli.sh
WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
Comment thread test/test_cli.sh Outdated
TRACE_CSV="${DATA_DIR}/cloudPhysicsIO.csv"
TRACE_TXT="${DATA_DIR}/cloudPhysicsIO.txt"

WORK_DIR=$(mktemp -d)
@1a1a11a
1a1a11a force-pushed the claude/polish-4-registry-hashpower branch from 720f1d5 to aa99429 Compare August 13, 2026 17:50
@1a1a11a
1a1a11a force-pushed the claude/polish-5-cli-tests branch from 3c8b06a to 803fa29 Compare August 13, 2026 17:50

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 803fa298de

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread test/test_cli.sh
Comment on lines +112 to +115
elif ! grep -qi "error" <<<"${out}"; then
_report 1 "${desc} failed without an error message (exit ${rc})"
else
_report 0 ""

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject sanitizer diagnostics before accepting clean errors

When this suite is run against an AddressSanitizer build, a segfault is typically converted into exit code 1 with output containing ERROR: AddressSanitizer; this branch therefore counts the crash as a clean rejection solely because the output contains “error.” That allows the invalid-input crash regressions this helper is intended to detect to pass under a common diagnostic configuration, so sanitizer error signatures should be checked before the generic message check.

Useful? React with 👍 / 👎.

Comment thread test/CMakeLists.txt Outdated
# The script prints SKIP: and exits 0 when the binaries or sample traces are
# absent. Without this, ctest reports that as a pass, so a run that tested
# nothing looks the same as a run that tested everything.
set_tests_properties(testCLI PROPERTIES SKIP_REGULAR_EXPRESSION "^SKIP:")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve compatibility with the declared CMake minimum

On CMake 3.12–3.15, which the root cmake_minimum_required(VERSION 3.12) explicitly supports, SKIP_REGULAR_EXPRESSION is unavailable because CMake introduced this test property in 3.16. Consequently, a missing-binary or missing-data run exits zero and is reported as passed rather than skipped on those supported versions; either raise the minimum to 3.16 or use a skip mechanism available in 3.12.

Useful? React with 👍 / 👎.

@1a1a11a
1a1a11a force-pushed the claude/polish-4-registry-hashpower branch from aa99429 to cddf41e Compare August 13, 2026 18:07
@1a1a11a
1a1a11a force-pushed the claude/polish-5-cli-tests branch from 803fa29 to dbe53fc Compare August 13, 2026 18:07

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: dbe53fcc0d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread test/test_cli.sh

n_skipped=0
for algo in ${ALL_ALGOS}; do
out=$("${BIN_DIR}/cachesim" "${TRACE_ORACLE}" oracleGeneral "${algo}" 1gb -e print 2>&1)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Handle optional algorithms before sweeping -e print

When built with ENABLE_LRB or ENABLE_3L_CACHE, this sweep includes the now-registered lrb and 3LCache entries, but their parsers reject bare print before reaching their print branches because value is NULL (LRB_Interface.cpp:333-338 and ThreeLCache_Interface.cpp:343-348). These configurations therefore record a failure here on every ctest run; either fix those parsers as part of this change or exclude/handle algorithms that cannot accept -e print.

Useful? React with 👍 / 👎.

Comment thread test/test_cli.sh
"${BIN_DIR}/traceAnalyzer" --num-req=10000 -o out-nreq "${TRACE}" vscsi
fi

if [[ -x "${BIN_DIR}/mrcProfiler" ]]; then

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Require every CLI binary before reporting success

If mrcProfiler is absent or moved from bin/—for example after building only the cachesim target—this condition silently skips all SHARDS and MINISIM checks, yet the script can still exit successfully and CTest reports testCLI as passed. mrcProfiler and traceAnalyzer are unconditional project executables rather than optional features, so the preflight should require them (or skip/fail the whole test) instead of treating their missing coverage as success.

Useful? React with 👍 / 👎.

@1a1a11a
1a1a11a force-pushed the claude/polish-4-registry-hashpower branch from cddf41e to 74d0d5e Compare August 13, 2026 18:12
@1a1a11a
1a1a11a force-pushed the claude/polish-5-cli-tests branch from dbe53fc to f3a18a6 Compare August 13, 2026 18:12

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f3a18a6d68

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread test/test_cli.sh
local out
out=$("$@" 2>&1)
local rc=$?
if [[ ${rc} -eq 0 ]]; then

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject sanitizer diagnostics from successful commands

When this target runs against a recovering sanitizer such as UBSan, a command can print runtime error: and still exit 0; this branch therefore records the invocation as passing. The same exit-code-only behavior appears in expect_output and the manual algorithm sweeps, so undefined behavior in most valid-input paths can evade the regression target even though expect_clean_error already recognizes these diagnostics. Check sanitizer signatures before accepting successful commands as well.

Useful? React with 👍 / 👎.

1a1a11a commented Aug 13, 2026

Copy link
Copy Markdown
Owner Author

Consolidated response to the review comments on this PR.

Sanitizer diagnostics counted as clean rejections — fixed, and it was the best catch here. _expect_clean_failure accepted any non-zero exit whose output contained the word "error". A sanitizer turns a crash into exit 1 with ERROR: AddressSanitizer, so in exactly the builds this suite exists to protect, a crash regression would have been recorded as a clean rejection. Sanitizer signatures are now tested first.

The follow-up — that a successful command can also print runtime error: under a recovering UBSan and still exit 0 — is correct and not yet addressed; expect_output and the sweeps check exit status only. Worth doing, and I have left it rather than adding it unverified at this point.

mktemp -d — fixed. BSD/macOS rejects the bare form, and the macOS job runs this target. It now passes an explicit "${TMPDIR:-/tmp}/libcachesim_cli_test.XXXXXX".

SKIP_REGULAR_EXPRESSION — fixed, then fixed again. Added so a self-skipped run stops reporting as a pass; the follow-up correctly noted the property arrived in CMake 3.16 while this project declares 3.12, where setting it is an error. It is guarded by a version check now.

Missing algorithms — fixed. hyperbolic, belady and beladySize were absent from ALL_ALGOS; the trace is oracleGeneral, so the Belady policies are valid on it. 174 checks became 180.

s3fifov0 is not a duplicate. s3-fifov0 and s3fifov0 are two distinct registry names for one constructor, as are 2q/twoq, s3-fifo/s3fifo, fifo-merge/fifomerge and gl-cache/GLCache. Sweeping both is deliberate: the point is that every registered name resolves, and an alias that stops resolving is exactly the regression the registry refactor could introduce.

Not addressed, both real: lrb and 3LCache reject bare print before reaching their print branches, so the sweep would fail in those optional build configurations; and a missing mrcProfiler binary silently skips the SHARDS and MINISIM checks while the target still passes. Both deserve fixing — flagging rather than rushing them.


Generated by Claude Code

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 70efb28ccb

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread test/test_cli.sh Outdated
Comment on lines +192 to +194
if [[ ${rc} -ne 0 ]] && grep -qi "do not support algorithm" <<<"${out}"; then
n_skipped=$((n_skipped + 1))
continue

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Fail when mandatory algorithms become unsupported

If an always-built entry such as lru is accidentally removed from g_cache_algos, create_cache_by_name() returns NULL and cache_init.h emits this exact “do not support algorithm” message, so this branch skips the failure; the replay sweep repeats the same logic. Only 3LCache, GLCache/gl-cache, and lrb are feature-gated, so restrict skipping to those optional names or pass the enabled feature set into the test, otherwise the target can pass after a mandatory CLI algorithm disappears.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, and fixed — this one undermined the sweep's whole purpose, so it was worth taking even though I had otherwise stopped adding to this PR.

The skip keyed off the do not support algorithm message alone, but cache_init.h emits that whenever a name is missing from the registry for any reason, not just an uncompiled feature. So a mandatory algorithm dropping out of g_cache_algos — precisely the regression the registry refactor could introduce — would have been skipped rather than reported.

Your list is exactly right: 3LCache, GLCache, gl-cache and lrb are the only feature-gated entries. The skip is restricted to those now.

Verified by deleting an entry and rebuilding, using gdsf rather than lrulru is asserted directly elsewhere in the suite, so its removal would have been caught regardless, whereas gdsf is covered by the sweeps and nothing else, which is the case that was genuinely silent:

FAIL: gdsf -e print (exit 134)   do not support algorithm gdsf
FAIL: gdsf replay (exit 134)     do not support algorithm gdsf
(4 algorithms not compiled in, skipped)

The four genuinely optional ones still skip, and the suite is 180/180 with the registry restored.


Generated by Claude Code

@1a1a11a
1a1a11a force-pushed the claude/polish-5-cli-tests branch from 70efb28 to 482d28d Compare August 13, 2026 18:28
@1a1a11a
1a1a11a force-pushed the claude/polish-4-registry-hashpower branch from 7393ce8 to 7d8f16e Compare August 14, 2026 20:04
@1a1a11a
1a1a11a force-pushed the claude/polish-5-cli-tests branch from 482d28d to 8c87ad4 Compare August 14, 2026 20:04

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8c87ad4142

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread test/test_cli.sh Outdated
--size=100MB,500MB,3 2>/dev/null | grep '^104857600B' | awk '{printf "%.4f", $2}')
_cachesim_exact=$("${BIN_DIR}/cachesim" "${TRACE_ORACLE}" oracleGeneral lru 100mb \
2>/dev/null | tail -1 | grep -oE 'miss ratio [0-9.]+' | head -1 | awk '{printf "%.4f", $3}')
if [[ "${_minisim_unsampled}" == "${_cachesim_exact}" ]]; then

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject empty outputs before comparing miss ratios

If both extraction pipelines fail to find their expected rows—for example after both tools' output formats change—each command substitution produces an empty string, and this equality check records the regression assertion as passed because "" == ""; the pipeline statuses are discarded because the script does not use set -e. Require both extracted values to be nonempty before comparing them so this test cannot succeed without actually observing either miss ratio.

Useful? React with 👍 / 👎.

@1a1a11a
1a1a11a force-pushed the claude/polish-4-registry-hashpower branch from 7d8f16e to 52d2e27 Compare August 14, 2026 20:16
@1a1a11a
1a1a11a force-pushed the claude/polish-5-cli-tests branch from 8c87ad4 to 73893f3 Compare August 14, 2026 20:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants