test(lib): cover the highest-value gaps in four logic modules - #543
Conversation
…me-current-account, usage and models commands Per-file line coverage (same metric as the full-suite baseline run): - lib/storage/snapshot-inspectors.ts: 34.7% -> 100% (66 uncovered lines -> 0); describeAccountsWalSnapshot was fully untested - lib/runtime/runtime-current-account.ts: 77.6% -> 99.0% (43 -> 2) - lib/codex-manager/commands/usage.ts: 86.1% -> 100% (45 -> 0) - lib/codex-manager/commands/models.ts: 72.2% -> 100% (20 -> 0) Behaviors pinned: - WAL snapshot inspection: missing-file short-circuit, malformed/forged journal entries (checksum mismatch never reaches the normalizer), schema-valid fast path, raw-JSON legacy fallback with schemaErrors surfaced and non-numeric storedVersion dropped, EACCES read failures reported as existing-but-invalid. - Runtime current-account resolution: index fallback (truncation, negative/out-of-range/NaN rejection) and contradiction checks where a signal's id/email disagrees with the indexed account; helper status file parsing (1 MB cap, type normalization, malformed JSON). Pinned quirk: isRecord() accepts JSON arrays, so an "[]" status file yields an all-null status object instead of null (downstream kind check still rejects it) - suspected oversight, behavior pinned, not fixed. - usage --since parsing (relative 30m/24h/7d/2W against the clock via fake timers, epoch passthrough as number, date strings as strings) and the default atomic report writer (nested mkdir, .tmp consumed on success, EBUSY rename retry, non-retryable failure cleans the staged temp file that briefly exists next to the destination). - models command: --help short-circuits before account loading, --model value validation (missing/empty/flag-like), text-mode availability lines incl. disabled-account reasons, quota cache load failures swallowed. https://claude.ai/code/session_01XNtnkLbBiXZxfQQYLMpucB
|
Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits. |
📝 WalkthroughWalkthroughThis PR expands test coverage across four test files with no changes to implementation. New tests validate CLI command argument parsing, file I/O atomicity and retry logic, runtime account resolution edge cases, and WAL snapshot inspection failure scenarios. ChangesTest coverage expansion for CLI and runtime commands
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes Possibly related PRs
review notes:
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
✨ Simplify code
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@test/runtime-current-account.test.ts`:
- Around line 537-555: The test documents that isRecord() currently treats
arrays as records causing an all-null status for "[]"; change the implementation
of isRecord in lib/runtime/runtime-current-account.ts so it explicitly returns
false for arrays (use Array.isArray(value) ? false : typeof value === "object"
&& value !== null) to prevent arrays from being treated as records; keep
existing callers such as appRuntimeHelperStatusToSignal unchanged so they now
receive null for array inputs.
In `@test/snapshot-inspectors.test.ts`:
- Line 39: The isRecord mock in the test currently accepts arrays (isRecord:
(value: unknown) => typeof value === "object" && value !== null) which diverges
from production behavior; update the mock to exclude arrays (add
!Array.isArray(value)) and add a test case feeding a journal entry whose content
is a JSON array (e.g., ["item1","item2"]) to snapshot inspector functions
(referencing isRecord and the inspector functions in snapshot-inspectors) to
assert the inspector rejects or handles array content as the real implementation
should.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: a73c276b-9c6a-42cb-96cc-9ebd8a61f6ca
📒 Files selected for processing (4)
test/codex-manager-models-command.test.tstest/codex-manager-usage-command.test.tstest/runtime-current-account.test.tstest/snapshot-inspectors.test.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Greptile Review
🧰 Additional context used
📓 Path-based instructions (6)
test/**/*.test.ts
📄 CodeRabbit inference engine (test/AGENTS.md)
test/**/*.test.ts: Vitest globals (describe,it,expect) are enabled and should be used without explicit imports
Maintain 80% coverage threshold across statements, branches, functions, and lines
UseremoveWithRetryfor Windows filesystem cleanup instead of barefs.rmto handle EBUSY/EPERM/ENOTEMPTY backoff
Use source files in tests, not compileddist/files; test the source directly
Do not skip tests without justification; include rationale if a test must be skipped
Relax ESLint rules for test files as specified ineslint.config.js
Files:
test/codex-manager-models-command.test.tstest/runtime-current-account.test.tstest/snapshot-inspectors.test.tstest/codex-manager-usage-command.test.ts
**/*.ts
📄 CodeRabbit inference engine (AGENTS.md)
Do not use
as any,@ts-ignore, or@ts-expect-errortype assertions
Files:
test/codex-manager-models-command.test.tstest/runtime-current-account.test.tstest/snapshot-inspectors.test.tstest/codex-manager-usage-command.test.ts
**/*.{ts,js}
📄 CodeRabbit inference engine (AGENTS.md)
Use ESM module syntax exclusively; the project is ESM-only with
"type": "module"
Files:
test/codex-manager-models-command.test.tstest/runtime-current-account.test.tstest/snapshot-inspectors.test.tstest/codex-manager-usage-command.test.ts
test/**/*.ts
📄 CodeRabbit inference engine (AGENTS.md)
Windows filesystem operations must include retry handling for transient
EBUSY,EPERM, andENOTEMPTYerrors where tests cover Windows locks
Files:
test/codex-manager-models-command.test.tstest/runtime-current-account.test.tstest/snapshot-inspectors.test.tstest/codex-manager-usage-command.test.ts
test/**
⚙️ CodeRabbit configuration file
tests must stay deterministic and use vitest. demand regression cases that reproduce concurrency bugs, token refresh races, and windows filesystem behavior. reject changes that mock real secrets or skip assertions.
Files:
test/codex-manager-models-command.test.tstest/runtime-current-account.test.tstest/snapshot-inspectors.test.tstest/codex-manager-usage-command.test.ts
**
⚙️ CodeRabbit configuration file
**: # PROJECT KNOWLEDGE BASEGenerated: 2026-04-25
Commit: a87e005
Branch: main
Package version: 2.2.0OVERVIEW
codex-multi-authis a Codex CLI-first OAuth account manager and optional forwarding wrapper for the official Codex CLI. The installedcodex-multi-authentrypoint handles account-management commands locally,codex-multi-auth-codexforwards official Codex commands through this package's wrapper when explicitly used, and runtime rotation can route live Responses traffic through a localhost account-rotation proxy by default. The plugin-host entrypoint remains exported for compatibility, but the primary product surface is the account manager, optional wrapper, storage, runtime proxy, and repair tooling.STRUCTURE
./ ├── scripts/ │ ├── codex.js # codex-multi-auth-codex wrapper, official CLI forwarder, shadow CODEX_HOME/runtime proxy setup │ ├── codex-multi-auth.js # standalone package CLI entrypoint │ ├── codex-routing.js # auth command and compatibility alias routing │ ├── codex-bin-resolver.js # official Codex binary discovery │ ├── codex-app-router.js # persistent localhost router for packaged Codex app bind │ └── codex-app-launcher.js # reversible user-level app launcher routing helper ├── index.ts # optional plugin-host runtime entry ├── lib/ # core runtime logic (see lib/AGENTS.md) │ ├── auth/ # OAuth flow, PKCE, callback server │ ├── runtime/ # Codex CLI/app integration helpers, app bind, live sync, runtime observability │ ├── request/ # request transform, SSE, failover, backoff │ ├── storage/ # path resolution, migrations, backups, restore, import/export │ ├── codex-cli/ # Codex CLI state sync and writer helpers │ ├── codex-manager/ # command modules and settings panels │ ├── prompts/ # model-family prompts, GitHub ETag cache │ ├── recovery/ # conve...
Files:
test/codex-manager-models-command.test.tstest/runtime-current-account.test.tstest/snapshot-inspectors.test.tstest/codex-manager-usage-command.test.ts
🧠 Learnings (2)
📚 Learning: 2026-06-04T06:14:18.093Z
Learnt from: ndycode
Repo: ndycode/codex-multi-auth PR: 510
File: test/scheduling-strategy-config.test.ts:1-1
Timestamp: 2026-06-04T06:14:18.093Z
Learning: In ndycode/codex-multi-auth, do not flag explicit imports from "vitest" (e.g., describe, it, expect, beforeEach/afterEach, etc.) in test files as issues—even if the Vitest config sets `globals: true`. The repo’s established convention is to keep these imports for consistency with neighboring tests; removing them would make files outliers.
Applied to files:
test/codex-manager-models-command.test.tstest/runtime-current-account.test.tstest/snapshot-inspectors.test.tstest/codex-manager-usage-command.test.ts
📚 Learning: 2026-06-04T06:14:24.975Z
Learnt from: ndycode
Repo: ndycode/codex-multi-auth PR: 510
File: test/runtime-rotation-proxy.test.ts:2478-2491
Timestamp: 2026-06-04T06:14:24.975Z
Learning: In ndycode/codex-multi-auth test files (e.g. `test/*.test.ts`), when creating V3 storage fixtures for accounts, it’s an intentional convention to use `as never` for deliberately minimal stored-account objects that only include `refreshToken`, `addedAt`, and `lastUsed`. Do not treat `as never` here as a type-safety problem: optional/other fields are expected to be populated by the runtime during execution, and the cast is used solely to keep the fixture minimal and consistent across existing tests.
Applied to files:
test/codex-manager-models-command.test.tstest/runtime-current-account.test.tstest/snapshot-inspectors.test.tstest/codex-manager-usage-command.test.ts
🔇 Additional comments (9)
test/codex-manager-models-command.test.ts (1)
56-141: LGTM!test/codex-manager-usage-command.test.ts (1)
1-7: LGTM!Also applies to: 235-365
test/snapshot-inspectors.test.ts (3)
1-11: LGTM!
50-128: LGTM!
130-202: LGTM!test/runtime-current-account.test.ts (4)
1-12: LGTM!
460-483: LGTM!
484-555: LGTM!
379-398: fractional index truncation is already implemented and matches the test expectations
- lib/runtime/runtime-current-account.ts:79-83 normalizes lastAccountIndex via
Math.trunc(...)and returns null for non-finite values (soNaNis rejected) and negatives.- lib/runtime/runtime-current-account.ts:257-258 rejects any normalized index
>= storage.accounts.length, so2correctly null for a 2-account storage.- test/runtime-current-account.test.ts:379-398 aligns with this behavior (
1.9→1,-1/2/NaN→ null).
…g it Use APP_RUNTIME_HELPER_STATUS_FILE from lib/runtime-constants.js so a rename of the status file cannot silently turn the readAppRuntimeHelperStatus tests into file-not-found nulls. https://claude.ai/code/session_01XNtnkLbBiXZxfQQYLMpucB
Adds the follow-up table (#543-#546 plus the per-branch unit suites) and updates the remaining-deferred note now that proxy phase 2 and login phase 4 are in progress. https://claude.ai/code/session_01XNtnkLbBiXZxfQQYLMpucB
The local isRecord copy in runtime-current-account.ts had drifted from the canonical lib/utils.ts guard and accepted JSON arrays, so an [] helper-status file produced an all-null status object instead of null (harmless today only because the downstream kind check rejected it). Deletes the drifted duplicate in favor of the canonical import and flips the behavior-pinning test from PR ndycode#543 to the corrected contract. https://claude.ai/code/session_01XNtnkLbBiXZxfQQYLMpucB
Summary
Test-only PR closing the highest-value coverage gaps in
lib/, found by ranking the full-suite coverage report by absolute uncovered lines and picking the modules whose gaps are real logic (parsers, validators, decision functions) rather than OS integration or env-failing suites' residue. Zero production-code changes; 632 new test lines across 1 new + 3 extended suites (47 tests).Per-file coverage (line metric, before → after)
lib/storage/snapshot-inspectors.tsdescribeAccountsWalSnapshothad zero coverage)lib/runtime/runtime-current-account.tslib/codex-manager/commands/usage.tslib/codex-manager/commands/models.tsDeliberately skipped despite ranking high:
storage.ts(gap inflated by the environment-failing EACCES suites),repair-commands.ts(4% residue of a huge interactive module),bridge.ts(network/OS integration),event-handler.ts(thin facade).Behaviors now pinned (contracts derived from the implementations)
schemaErrorssurfaced; non-numericstoredVersiondropped; EACCES reads classified existing-but-invalid with stat metadata preserved.usage:--sincerelative durations (30m/24h/7d/2W, case-insensitive) resolved against fake-timer clocks; epoch and date-string passthrough; the atomic writer creates nested dirs, consumes.tmpon success, retries rename on EBUSY, and removes the staged temp on non-retryable ENOSPC.models:--helpshort-circuits before account loading; missing/empty/flag-like--modelvalues error;unavailable (account disabled)availability lines; quota-cache load failures swallowed.Suspected bug (pinned, not fixed)
runtime-current-account.ts'sisRecord()accepts JSON arrays, so an[]helper-status file yields an all-null status object instead ofnull. Harmless today (the downstreamkindcheck rejects it) but likely an oversight — the test pins current behavior with a comment so a deliberate fix shows up as an explicit diff.Validation
npm run typecheck; eslint--max-warnings=0on all 4 filesstorage-flagged,backup-metadata-builder,codex-manager-status-command) passRisk / Rollback
Pure test addition; revert the single commit.
https://claude.ai/code/session_01XNtnkLbBiXZxfQQYLMpucB
Generated by Claude Code
note: greptile review for oc-chatgpt-multi-auth. cite files like
lib/foo.ts:123. confirm regression tests + windows concurrency/token redaction coverage.Greptile Summary
test-only PR closing the top coverage gaps in four logic modules \u2014 WAL snapshot inspection, usage-command
--sinceparsing + atomic writer retry, and runtime current-account resolution. zero production-code changes; 632 new test lines across one new suite and three extended ones.snapshot-inspectors.test.ts(new, 202 lines): pins all eight branches ofdescribeAccountsWalSnapshot\u2014 non-existing snapshot, outer/inner JSON parse failures, forged checksum, schema-unknown legacy path, EACCES read error, and the happy path.runtime-current-account.test.ts: adds index-fallback resolution, fractional/negative/NaN rejection, id/email contradiction guard, whitespace-only field handling, and a fullreadAppRuntimeHelperStatusblock (size cap, field normalization, the documentedisRecord-accepts-arrays quirk).codex-manager-usage-command.test.ts/codex-manager-models-command.test.ts: cover--sincerelative/epoch/date-string parsing (fake-timer clock),--helpshort-circuit,--modelflag-like-value rejection, disabled-account unavailability text, and the atomic writer\u2019s nested-dir creation, EBUSY retry, and ENOSPC fast-fail + temp-file cleanup paths.Confidence Score: 5/5
pure test addition — no production code changes, all new tests isolated in temp dirs with correct env-var and spy cleanup
every new test exercises a clearly-defined branch of the implementation; assertions match the source logic; env mutations are saved/restored in beforeEach/afterEach; removeWithRetry is used throughout for windows-safe temp dir cleanup; no test shares mutable state across describe blocks
no files require special attention; the ebusy retry test in codex-manager-usage-command.test.ts uses a real 10 ms sleep that could be made deterministic with fake timers, but it is not a correctness issue
Important Files Changed
Sequence Diagram
sequenceDiagram participant Test participant runUsageCommand participant parseSinceValue participant defaultWriteFile participant fs_rename Note over Test,fs_rename: --since parsing (fake timers) Test->>+runUsageCommand: --since 30m runUsageCommand->>parseSinceValue: 30m parseSinceValue-->>runUsageCommand: NOW-30x60000 runUsageCommand-->>-Test: captured since value Note over Test,fs_rename: atomic writer EBUSY retry Test->>+runUsageCommand: --out usage.txt runUsageCommand->>+defaultWriteFile: path, contents defaultWriteFile->>fs_rename: rename attempt 0 fs_rename-->>defaultWriteFile: EBUSY defaultWriteFile->>defaultWriteFile: sleep 10ms defaultWriteFile->>fs_rename: rename attempt 1 fs_rename-->>defaultWriteFile: ok defaultWriteFile-->>-runUsageCommand: resolved runUsageCommand-->>-Test: exitCode 0 Note over Test,fs_rename: atomic writer ENOSPC fast-fail Test->>+runUsageCommand: --out usage.txt runUsageCommand->>+defaultWriteFile: path, contents defaultWriteFile->>fs_rename: rename fs_rename-->>defaultWriteFile: ENOSPC defaultWriteFile->>defaultWriteFile: unlink tmp defaultWriteFile-->>-runUsageCommand: throw runUsageCommand-->>-Test: exitCode 1 tmp removedPrompt To Fix All With AI
Reviews (2): Last reviewed commit: "test: import the helper status filename ..." | Re-trigger Greptile