Skip to content

test: add boundary regression tests for storage, oauth poll abort, and prompt refresh dedupe#35

Open
ndycode wants to merge 3 commits intomainfrom
qa/test-dominant-origin-main
Open

test: add boundary regression tests for storage, oauth poll abort, and prompt refresh dedupe#35
ndycode wants to merge 3 commits intomainfrom
qa/test-dominant-origin-main

Conversation

@ndycode
Copy link
Owner

@ndycode ndycode commented Mar 4, 2026

Summary

  • add regression test for resolveProjectStorageIdentityRoot fallback when .git entry exists but is neither file nor directory
  • add regression test for OAuth waitForCode abort path when close() is called during active polling
  • add regression test for Codex instruction stale-cache concurrent refresh deduplication

What Changed

  • updated test/paths.test.ts
  • updated test/server.unit.test.ts
  • updated test/codex-prompts.test.ts

Validation

  • npx vitest run test/paths.test.ts -t "falls back when .git entry exists but is neither file nor directory"
  • npx vitest run test/server.unit.test.ts -t "waitForCode returns null when close aborts active poll loop"
  • npx vitest run test/codex-prompts.test.ts -t "deduplicates background refresh for concurrent stale calls"
  • npx vitest run test/paths.test.ts test/server.unit.test.ts test/codex-prompts.test.ts
  • npm run typecheck

Risk and Rollback

  • Risk level: low (tests only)
  • Rollback plan: revert commit 77d0e0309c30a6cf9635b56c29f34859ae63531f

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

added three regression tests covering edge cases and race conditions: storage path fallback for non-file/non-directory .git entries (sockets/pipes on unix), oauth poll abort during active waitForCode loop, and concurrent stale cache refresh deduplication.

  • test/paths.test.ts: validates resolveProjectStorageIdentityRoot fallback when .git exists but isFile() and isDirectory() both return false
  • test/server.unit.test.ts: validates waitForCode returns null (not timeout) when close() aborts active poll, uses fake timers
  • test/codex-prompts.test.ts: validates concurrent calls to getCodexInstructions with stale cache trigger exactly one background refresh, uses waitFor for async stability

all tests properly mock filesystem and network calls, use appropriate timing controls, and verify expected behavior without side effects.

Confidence Score: 5/5

  • test-only changes, no production code modified, safe to merge
  • all three tests are well-structured regression tests with proper mocking, timing controls, and assertions. no production code changes means zero runtime risk. tests improve coverage for edge cases (unix special files, oauth abort, cache dedupe race).
  • no files require special attention

Important Files Changed

Filename Overview
test/paths.test.ts added boundary test for .git entry that is neither file nor directory (socket/pipe edge case)
test/server.unit.test.ts added abort path test for waitForCode when close() is called during active polling
test/codex-prompts.test.ts added concurrent refresh dedupe test with waitFor for stability, validates single background fetch for multiple stale calls

Last reviewed commit: e06e5e5

- add storage identity fallback test for malformed .git metadata

- add OAuth poll abort test for deterministic close behavior

- add prompt refresh dedupe test for concurrent stale cache reads

Co-authored-by: Codex <noreply@openai.com>
@coderabbitai
Copy link

coderabbitai bot commented Mar 4, 2026

📝 Walkthrough

This is a minor, low-risk, test-only PR that increases coverage for three boundary behaviors (storage root detection, OAuth polling abort, and prompt-cache refresh dedupe). No production code changes, no security or data-loss risks introduced, and regression tests were added and validated locally.

Changes

  • test/paths.test.ts (+16)

    • Adds a regression test for resolveProjectStorageIdentityRoot: when a .git entry exists but is neither a file nor a directory (e.g., broken symlink/socket/pipe), the function falls back to the provided project root and must not call readFileSync.
  • test/server.unit.test.ts (+25)

    • Adds a unit test for OAuth waitForCode abort behavior: if close() is called during active polling, waitForCode resolves to null and the test asserts no premature timeout warning/log is emitted.
  • test/codex-prompts.test.ts (+59)

    • Adds a regression test ensuring getCodexInstructions deduplicates background refreshes for concurrent stale-cache calls: concurrent callers receive stale content immediately, only one background fetch is triggered, the cache is written once when the fetch completes, and subsequent calls return the refreshed content. The test replaces a microtask spin-loop with vi.waitFor polling to improve stability while retaining an assertion that no extra fetches occur post-refresh.

Validation

  • Ran targeted vitest commands for each test file and a combined run for the three new tests.
  • Ran npm run typecheck successfully.

Risk & Rollback

  • Risk: Low — tests only.
  • Rollback: Revert commit 77d0e03

Reviewer focus / architectural notes

  • Confirm the deduplication semantics in codex-prompts align with intended shared in-flight-refresh behavior (single shared promise vs. per-call fetch) and that the test's post-refresh assertions are stable.
  • Verify resolveProjectStorageIdentityRoot’s fallback behavior matches expectations for callers that may assume .git is a file or directory.
  • Ensure waitForCode’s abort behavior (resolving to null and suppressing timeout warnings) is the desired contract for consumers that close the server during polling.

walkthrough

three new unit tests added validating concurrent cache refresh deduplication, .git edge-case path resolution, and oauth server cleanup when closing during active polling.

changes

Cohort / File(s) Summary
codex prompts test
test/codex-prompts.test.ts:1
adds "deduplicates background refresh for concurrent stale calls" test that simulates two concurrent getCodexInstructions calls, asserts both return stale content, verifies a single background fetch (deduped in-flight), persists refreshed content, and confirms subsequent call returns updated content.
paths test
test/paths.test.ts:1
adds test for resolveProjectStorageIdentityRoot where .git exists but is neither file nor directory; expects fallback to provided project root and no readFileSync invocation.
oauth server unit test
test/server.unit.test.ts:1
adds "waitForCode returns null when close aborts active poll loop" test using fake timers to ensure waitForCode('test-state') resolves to null when server is closed during polling and no premature timeout log occurs.

sequence diagram(s)

(silently skipped)

estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

notes

  • concurrency risk: review in-flight deduplication logic exercised by test/codex-prompts.test.ts:1. add regression tests for burst concurrent requests and failing background fetch to verify atomic updates and cache consistency.
  • windows edge cases: test/paths.test.ts:1 covers .git non-file/non-dir. add explicit windows-targeted tests for symlinks and special file semantics.
  • missing regression tests: add a stress/regression test for repeated rapid concurrent refreshes and error paths when background fetch fails (test/codex-prompts.test.ts:1).
  • dangling timers / leaks: verify waitForCode cleanup across platforms as exercised by test/server.unit.test.ts:1; confirm no dangling timers, unhandled promise rejections, or resource leaks when polling is aborted.
🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Title check ⚠️ Warning The title exceeds the 72-character limit (92 characters) and violates the conventional commits format requirement. Shorten to 72 characters or fewer while maintaining the test(scope): summary format, e.g., 'test: add regression tests for storage, oauth, and prompt dedupe'.
✅ Passed checks (2 passed)
Check name Status Explanation
Description check ✅ Passed The description covers required sections (summary, what changed, validation) but omits the Docs and Governance Checklist and incomplete Risk and Rollback details.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch qa/test-dominant-origin-main

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@test/codex-prompts.test.ts`:
- Around line 258-265: The test currently only checks mockFetch hit count at a
single instant which allows a late second refresh to slip through; update the
test around resolvePromptText and mockedWriteFile to assert stability by first
waiting for mockFetch to reach 2 (using mockFetch and resolvePromptText), then
ensure no further calls occur by advancing or waiting a deterministic short
window (use vi.useFakeTimers/vi.advanceTimersByTime or an awaited stable wait)
and re-assert mockFetch remains at 2 and mockedWriteFile was called; reference
the test symbols mockFetch, resolvePromptText, mockedWriteFile and tighten
verification to cover the dedupe logic in lib/prompts/codex.ts (the
refresh/dedupe block around lines 236-246) so the test deterministically fails
on late double-refreshes.

ℹ️ Review info

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

Run ID: 28b5a36a-5be6-4f50-8964-03360e78244e

📥 Commits

Reviewing files that changed from the base of the PR and between d36b04f and 77d0e03.

📒 Files selected for processing (3)
  • test/codex-prompts.test.ts
  • test/paths.test.ts
  • test/server.unit.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 (1)
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/server.unit.test.ts
  • test/paths.test.ts
  • test/codex-prompts.test.ts
🧬 Code graph analysis (2)
test/paths.test.ts (1)
lib/storage/paths.ts (1)
  • resolveProjectStorageIdentityRoot (256-298)
test/codex-prompts.test.ts (1)
lib/prompts/codex.ts (1)
  • getCodexInstructions (204-293)
🔇 Additional comments (2)
test/paths.test.ts (1)

657-671: good regression for the non-file .git edge case.

this is deterministic and directly validates the early-return guard in lib/storage/paths.ts:263-267, including the no-read safety check at test/paths.test.ts:670. windows filesystem coverage remains intact via test/paths.test.ts:293-579.

test/server.unit.test.ts (1)

303-326: good regression for poll-loop abort concurrency.

test/server.unit.test.ts:303-326 cleanly reproduces close-during-poll and verifies waitForCode resolves null without timeout-noise behavior.

- replace instantaneous fetch-count check with stable post-refresh assertion window

- verify fetch count remains fixed after refresh persistence completes

Co-authored-by: Codex <noreply@openai.com>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@test/codex-prompts.test.ts`:
- Around line 258-271: Replace the Promise.resolve() spin-loops in the test (the
loops that wait for background ops around mockFetch, mockedWriteFile and
resolvePromptText) with vitest's vi.waitFor so the test doesn't rely on
microtask scheduling; specifically, change the blocks that assert mockFetch has
been called twice, that mockedWriteFile has been called after
resolvePromptText("fresh deduped content"), and the final microtask drain into
vi.waitFor callbacks that poll the respective expectations
(expect(mockFetch).toHaveBeenCalledTimes(2),
expect(mockedWriteFile).toHaveBeenCalled(), and any final settles) using
vi.waitFor's default timeout/interval (or an explicit small timeout if needed)
to make the test deterministic instead of the current spin-loop approach.

ℹ️ Review info

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

Run ID: 31a84a7e-6565-408e-8a23-de30aa67a25f

📥 Commits

Reviewing files that changed from the base of the PR and between 77d0e03 and 898d708.

📒 Files selected for processing (1)
  • test/codex-prompts.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 (1)
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-prompts.test.ts
🧬 Code graph analysis (1)
test/codex-prompts.test.ts (1)
lib/prompts/codex.ts (1)
  • getCodexInstructions (204-293)

- replace microtask spin-loops with vi.waitFor polling

- keep final no-extra-fetch stability assertion after refresh

Co-authored-by: Codex <noreply@openai.com>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
test/codex-prompts.test.ts (1)

271-273: ⚠️ Potential issue | 🟠 Major

tighten the final no-extra-fetch check to hold over a stable window.

Line 271 in test/codex-prompts.test.ts validates fetch count at one instant; a delayed extra refresh from lib/prompts/codex.ts:236-246 can still slip past. keep the assertion true across a short deterministic window.

proposed fix
-				await vi.waitFor(() => {
-					expect(mockFetch).toHaveBeenCalledTimes(settledFetchCalls);
-				});
+				const stableWindowMs = 150;
+				const stableWindowStart = Date.now();
+				await vi.waitFor(
+					() => {
+						expect(mockFetch).toHaveBeenCalledTimes(settledFetchCalls);
+						expect(Date.now() - stableWindowStart).toBeGreaterThanOrEqual(
+							stableWindowMs,
+						);
+					},
+					{ interval: 20, timeout: 1000 },
+				);

As per coding guidelines, test/**: tests must stay deterministic and use vitest. demand regression cases that reproduce concurrency bugs, token refresh races, and windows filesystem behavior.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/codex-prompts.test.ts` around lines 271 - 273, The final check that
mockFetch was called exactly settledFetchCalls needs to be held stable across a
short deterministic window to catch delayed refreshes from the codex
token-refresh path; replace the single instant assertion with a stability check
that repeatedly verifies mockFetch.callCount === settledFetchCalls for a short
fixed duration (e.g., 50–200ms) using vitest utilities
(vi.waitFor/vi.advanceTimers or a small loop with await new Promise) so the
assertion must remain true across the window; target the existing mockFetch and
settledFetchCalls variables and ensure the test waits for stability rather than
a one-time snapshot.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@test/codex-prompts.test.ts`:
- Around line 271-273: The final check that mockFetch was called exactly
settledFetchCalls needs to be held stable across a short deterministic window to
catch delayed refreshes from the codex token-refresh path; replace the single
instant assertion with a stability check that repeatedly verifies
mockFetch.callCount === settledFetchCalls for a short fixed duration (e.g.,
50–200ms) using vitest utilities (vi.waitFor/vi.advanceTimers or a small loop
with await new Promise) so the assertion must remain true across the window;
target the existing mockFetch and settledFetchCalls variables and ensure the
test waits for stability rather than a one-time snapshot.

ℹ️ Review info

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

Run ID: fc9ec878-97fc-4202-bb0b-e62f0bf9d1d0

📥 Commits

Reviewing files that changed from the base of the PR and between 898d708 and e06e5e5.

📒 Files selected for processing (1)
  • test/codex-prompts.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 (1)
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-prompts.test.ts
🧬 Code graph analysis (1)
test/codex-prompts.test.ts (1)
lib/prompts/codex.ts (1)
  • getCodexInstructions (204-293)
🔇 Additional comments (1)
test/codex-prompts.test.ts (1)

217-270: strong concurrency regression coverage for stale calls.

test/codex-prompts.test.ts:217-270 now deterministically exercises the stale-while-revalidate concurrency path against lib/prompts/codex.ts:236-246 with vitest polling. this explicitly covers the concurrency risk. windows filesystem behavior and token refresh races are out of scope for this segment.

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