Skip to content

test: extend mutation testing to pricing.js and default-rates.js (depends on #710) - #714

Merged
lis186 merged 10 commits into
mainfrom
test/stryker-pricing
Oct 20, 2026
Merged

lis186 merged 10 commits into
mainfrom
test/stryker-pricing

Conversation

@lis186

@lis186 lis186 commented Oct 17, 2026

Copy link
Copy Markdown
Owner

Depends on #710. This branch is stacked on test/stryker-wire-parsers (82739a6). Until #710 merges, the diff below also shows #710's commit; this PR's own change is d44bd9a. Merge #710 first.

This extends the Stryker mutation scope to server/pricing.js and server/default-rates.js. The changes are tests, config and docs only, with no change under server/ and no new dependencies.

Setup

  • One stryker.config.mjs covers both scopes; a full run stays under 4 min. It adds the two files to mutate and 11 pricing-related unit test files to testFiles.
  • Isolation:
    • The config points CCXRAY_PRICING_CACHE at a path that doesn't exist.
    • The new preload test/helpers/no-network.js makes any non-loopback http/https/net/tls/fetch connection throw, including in spawned Node children.
    • The fetchPricing() network path is tested through a stubbed https.get.
    • In each mutation run, about 80 LiteLLM fetch attempts come only from mutants that break the cache/TTL checks, and all are blocked. The unmutated test list makes 0 attempts. The repo's pricing-cache.json was never created by a Stryker run.

Scores (Stryker clear-text report, --force run)

File Before After
pricing.js 41.38% (96 killed / 62 survived / 74 no-cov) 83.62% (194 / 25 / 13)
default-rates.js 65.57% (160 / 57 / 27, +4 runtime errors) 88.93% (217 / 7 / 20, 4 runtime errors)
wire-parsers/** 97.19% 97.19%
Total 84.93% 94.12%

Time and memory (8 cores, concurrency 2, nice)

Full run: 220–231 s. Stryker peak RSS was about 0.24 GB and the process tree about 0.65 GB. MemAvailable never went below 11.4 GB.

Triage

  • Tests added: 45, in test/pricing-edges.test.js and test/default-rates-edges.test.js. They cover:
    • LiteLLM per-token → per-million conversion and the fallbacks when cache fields are absent
    • fetchPricing cache hit and miss, the 24 h TTL, the request URL and timeout, the cache write, and falling back on bad status, parse error, request error or timeout
    • context-window loading and longest-prefix matching
    • the xai/ fallback and dated-key prefix matching
    • the 1 h cache-creation rate and sanity checks on every offline default row
  • 65 equivalent or unreachable survivors are left on purpose, grouped with reasons in docs/mutation-testing.md. Of these, 45 are in the lag-override code, which can't run because LITELLM_LAG_OVERRIDES is an empty frozen list.
  • // Stryker disable comments: 0.
  • Two survivors point at possible pricing bugs. They were reported separately and are not fixed here, and no test locks the current behaviour in:
    1. A LiteLLM cache rate listed as exactly 0 is treated as missing and charged at the input rate.
    2. A model priced at $0 is dropped instead of being priced at $0.

Found along the way (pre-existing, not changed here)

test/hub.test.js forks a real hub without CCXRAY_PRICING_CACHE, so npm run test:unit downloads LiteLLM and writes the repo-root pricing-cache.json. The fix is a one-line follow-up.

lis186 and others added 3 commits October 18, 2026 00:41
…unner)

Adds an opt-in `npm run test:mutation` (not in npm test or CI) scoped to
server/wire-parsers/**. The suite is node:test, so the tap runner is used
instead of vitest; each file runs under test/helpers/home-guard.js.

Triage of surviving mutants added two edge-case test files; score
64.43% -> 97.19% (anthropic 69.66 -> 98.60, openai 61.98 -> 96.58).
The 34 remaining survivors are equivalent and listed in
docs/mutation-testing.md. No production code changes.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Adds server/pricing.js and server/default-rates.js to the Stryker scope with
their unit test files. Every test process gets a nonexistent
CCXRAY_PRICING_CACHE and a no-network preload, so a mutant that breaks the
cache/TTL checks cannot download LiteLLM or touch pricing-cache.json.

New edge tests cover ratesFromLiteLLMEntry, fetchPricing's cache and
(stubbed) network paths, the synchronous context-table load, prefix matching,
cache-file validation and the 1h cache-creation rate. pricing.js 41.38% ->
83.62%, default-rates.js 65.57% -> 88.93%; remaining survivors are listed as
equivalent/unreachable in docs/mutation-testing.md.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 17, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-17T18:23:36.702416Z d44bd9a PR opened
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@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: d44bd9a2e8

ℹ️ 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 package.json
"ws": "^8.19.0"
},
"devDependencies": {
"@stryker-mutator/core": "^10.0.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 Align mutation tooling with supported Node versions

On Node 18 or 20—both accepted by engines.node, with Node 20 also exercised in .github/workflows/ci.yml—the new mutation command loads Stryker 10 even though its locked packages declare node >=22.0.0 (and Babel dependencies require Node 22.18+). Thus contributors on an otherwise supported development runtime cannot reliably run the documented npm run test:mutation; pin a compatible Stryker release or explicitly raise/separate the tooling requirement.

Useful? React with 👍 / 👎.

@lis186
lis186 merged commit 8130748 into main Oct 20, 2026
4 checks passed
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.

1 participant