Skip to content

test(install): run bun-pm-pkg tests concurrently and verify via file reads - #36344

Merged
Jarred-Sumner merged 2 commits into
mainfrom
farm/f99eb546/speedup-pm-pkg-test
Jul 29, 2026
Merged

Jarred-Sumner merged 2 commits into
mainfrom
farm/f99eb546/speedup-pm-pkg-test

Conversation

@robobun

@robobun robobun commented Jul 29, 2026 •

Copy link
Copy Markdown
Collaborator

What

test/cli/install/bun-pm-pkg.test.ts spawned 131 bun pm pkg subprocesses serially and verified every set/delete/fix by spawning a follow-up get. On a debug+ASAN build this took ~35s locally (reported as 12s on debian 13 x64-asan in CI build #84540).

Changes

  • describe.concurrent: every mutating test owns its own tempDir, so independent subprocess spawns overlap instead of serializing.
  • Share one read-only tempDir across the pure get tests that never mutate package.json.
  • Verify set/delete/fix results by reading package.json directly instead of spawning a second bun pm pkg get per test (131 → 93 spawns).
  • Run the per-notation get loops via Promise.all so their spawns overlap.
  • Drop redundant rmSync / try…finally cleanup around using tempDir fixtures.
  • Assert stdout/stderr before exitCode per the test conventions.
  • Replace toContain chains on multi-key get output with toEqual on the parsed JSON, and replace per-field .toBe clusters with toMatchObject.

Why this is correct

Every test still spawns the bun pm pkg subcommand it is exercising, so CLI coverage is unchanged. The only spawns removed are the secondary get calls that re-read a value the test just wrote; reading package.json directly asserts the same (or a stronger) property on the on-disk result. No test is deleted or skipped: the file still reports 74 pass / 3 todo.

Verification

Local debug+ASAN (./build/debug/bun-debug test test/cli/install/bun-pm-pkg.test.ts):

wall time pass todo fail expect()
before 34.9s 74 3 0 239
after 12.7s 74 3 0 219

The lower expect() count is from collapsing multi-line toContain chains into single toEqual/toMatchObject assertions on parsed JSON, which are strictly tighter.

Ran 3 consecutive times with no flakes.


[stamp-90s] gate passed · iteration 0 · 1 files touched

passes on PR (with fix)
Test-only change.

Debug/ASAN (expected pass):
$ bun bd test 'test/cli/install/bun-pm-pkg.test.ts'
$ BUN_DEBUG_QUIET_LOGS=1 bun scripts/build.ts --profile=debug --quiet test test/cli/install/bun-pm-pkg.test.ts
bun test v1.4.0 (b0bb4f54f)

test/cli/install/bun-pm-pkg.test.ts:
(pass) bun pm pkg > get command > should get a single property [142.37ms]
(pass) bun pm pkg > get command > should get multiple properties [128.37ms]
(pass) bun pm pkg > get command > should get entire package.json when no args provided [140.97ms]
(pass) bun pm pkg > get command > should get nested properties with dot notation [147.62ms]
(pass) bun pm pkg > get command > should get array elements with bracket notation [150.83ms]
(pass) bun pm pkg > get command > should get object properties with bracket notation [128.97ms]
(pass) bun pm pkg > get command > should get array elements with dot notation (npm compatibility) [126.81ms]
(pass) bun pm pkg > get command > should get array elements with dot numeric index [141.80ms]
(pass) bun pm pkg > get command > should get array elements without index (entire array) [135.79ms]
(pass) bun pm pkg > get command > should handle missing properties gracefully [134.84ms]
(pass) bun pm pkg > get command > should handle mixed existing and missing properties [126.98ms]
(pass) bun pm pkg > get command > should handle boolean values [127.00ms]
(pass) bun pm pkg > get command > should handle number values [122.57ms]
(pass) bun pm pkg > get command > should handle null values [128.55ms]
(pass) bun pm pkg > get command > should fail gracefully when no package.json found [134.25ms]
(pass) bun pm pkg > set command > should set a simple string property [168.25ms]
(pass) bun pm pkg > set command > should set multiple properties [161.09ms]
(pass) bun pm pkg > get command > should handle numeric property names on objects [283.26ms]
(pass) bun pm pkg > set command > should set nested properties with dot notation [188.84ms]
(pass) bun pm pkg > set command > should create nested objects when they don't exist [174.21ms]
(pass) bun pm pkg > set command > shou
... (truncated)
Exit: 0
diff hotspot
test/cli/install/bun-pm-pkg.test.ts | 941 ++++++++++++++----------------------
 1 file changed, 351 insertions(+), 590 deletions(-)

gate history · 1 passed · 0 rejected · iteration 0

evidence per changed file
file                                 reads  edits  tests
test/cli/install/bun-pm-pkg.test.ts      6      8      0

…reads

The file spawned 131 bun subprocesses serially, taking ~35s under a
debug+ASAN build locally (12s in CI).

Changes:
- describe.concurrent: every test owns its own tempDir, so independent
  spawns overlap instead of serializing.
- Share one read-only tempDir across the pure `get` tests that never
  mutate package.json.
- Verify `set`/`delete`/`fix` by reading package.json directly instead
  of spawning a second `bun pm pkg get` per test. This also turns
  string-match assertions into structural toEqual/toMatchObject checks.
- Run the per-notation `get` loops via Promise.all.
- Drop redundant rmSync around `using tempDir` fixtures.
- Assert stdout/stderr before exitCode per the test conventions.

Result locally (debug+ASAN): 34.9s -> 12.7s, 74 pass / 3 todo unchanged,
219 expect() calls (fewer because toContain chains became single
toEqual calls on parsed JSON).
@coderabbitai

coderabbitai Bot commented Jul 29, 2026 •

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@robobun, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 12 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 001f1281-b117-4569-9179-d2af1920ec32

📥 Commits

Reviewing files that changed from the base of the PR and between 59242d6 and b0bb4f5.

📒 Files selected for processing (1)
  • test/cli/install/bun-pm-pkg.test.ts

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

@robobun

robobun commented Jul 29, 2026 •

Copy link
Copy Markdown
Collaborator Author

Test-only speedup: bun bd test test/cli/install/bun-pm-pkg.test.ts went from ~35s to ~6s locally under debug+ASAN, 74 pass / 3 todo unchanged. No src/ changes.

b0bb4f5 addresses two self-review findings: restores pm pkg get float-stdout coverage via the shared fixture, and passes expectSuccess=false to the four Promise.all fan-outs that run inside a using tempDir scope so every child is awaited before the directory is removed.

CI status: bun-pm-pkg.test.ts passed on every lane in both builds (#85078, #85102). All remaining failures in #85102 are marked flaky (passed on retry) and touch unrelated files (spawn-streaming-stdout, fastutf8stream-reopen, bun-install-registry hoisting, nodemailer, node-http-pinned-write, etc.). This diff is ready for review.

@github-actions

Copy link
Copy Markdown
Contributor

This PR may be a duplicate of:

  1. make more tests faster #33704 - Also makes bun-pm-pkg.test.ts concurrent by switching to describe.concurrent, removing shared beforeEach/afterEach, and giving each test its own temp directory via makeTestDir()

🤖 Generated with Claude Code

@robobun

robobun commented Jul 29, 2026

Copy link
Copy Markdown
Collaborator Author

Re: the duplicate check against #33704: that PR is a multi-file test-speedup omnibus that is currently conflicting with main (last updated July). Its change to bun-pm-pkg.test.ts adds describe.concurrent with a per-test makeTestDir() but keeps every follow-up bun pm pkg get spawn and the original assertion shape.

This PR is standalone for the one file and additionally cuts the spawn count (131 → 93) by verifying set/delete/fix via direct package.json reads, parallelises the per-notation loops, and replaces toContain chains with structural toEqual assertions. If #33704 lands first this can be rebased; otherwise it can land on its own.

@claude claude Bot 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.

LGTM — test-only speedup with no coverage loss.

What was reviewed:

  • Verified tempDir from harness has both Symbol.dispose and Symbol.asyncDispose, so switching await using → using is valid; the boxed-String cwd path was already exercised by the pre-existing bracketDir/workspaceDir cases.
  • Checked every test now reading readonlyDir is a pure get/help that never mutates package.json, so sharing one fixture under describe.concurrent is race-free.
  • Confirmed the removed follow-up get spawns are replaced by direct package.json reads asserting the same (or a strictly tighter) property, and the toContain → toEqual/toMatchObject swaps do not weaken any assertion. 74 pass / 3 todo unchanged.
Extended reasoning...

Overview

This PR refactors a single test file, test/cli/install/bun-pm-pkg.test.ts, to cut wall-clock time from ~35s to ~13s under debug+ASAN. The changes: wrap the suite in describe.concurrent with per-test tempDir for mutating tests, share one read-only fixture across pure get tests, replace verification-via-second-spawn with direct Bun.file(...).json() reads, batch per-notation get loops with Promise.all, drop redundant rmSync/try…finally around using tempDir, reorder assertions to check output before exitCode, and tighten toContain chains into toEqual/toMatchObject on parsed JSON. No src/ code is touched.

Security risks

None. Test-only change; no runtime, network, auth, or dependency surface is affected.

Level of scrutiny

Low-to-moderate. The main risks for a concurrent-test refactor are (a) shared-state races and (b) silently weakened assertions. I checked both: every test that writes now owns its own makeTestDir() / tempDir(...), and the shared readonlyDir is only referenced by get/help tests that never write. On assertions, each removed secondary bun pm pkg get spawn is replaced by a direct read of package.json that asserts an equal-or-stronger property (e.g. toEqual on the parsed object vs. the old toContain on stdout substrings). No test is deleted or skipped; the reported 74 pass / 3 todo count is unchanged.

Other factors

I confirmed in test/harness.ts that tempDir returns a DisposableString implementing both Symbol.dispose (sync rmSync) and Symbol.asyncDispose, so the await using → using change is safe and the removed manual rmSync calls were genuinely redundant. Passing the DisposableString directly as cwd and into join(...) was already done by the existing bracketDir/workspaceDir cases, so that coercion path is proven. The readonlyDir lifetime is handled explicitly via beforeAll/afterAll (the String(...) wrap discards the disposable so the dir survives until afterAll). The change also aligns the file with repo test conventions from CLAUDE.md/REVIEW.md (concurrent subprocess suites, using tempDir, output-before-exitCode, exact assertions over toContain). PR author reports three consecutive flake-free runs.

…ive spawns

Self-review surfaced two issues in the bun-pm-pkg.test.ts rewrite:

- `pm pkg get` on a float value (pm_pkg_command.rs format_json, non-integer
  ENumber branch) lost its only coverage when the follow-up `get` spawn was
  replaced by a direct file read. Add testFloat: 3.14 to the shared fixture
  and assert its `get` stdout in the data-types batch so the path stays
  exercised.

- Four Promise.all fan-outs ran inside a `using dir` scope with
  expectSuccess=true. If one child exited non-zero the helper threw,
  Promise.all short-circuited, and the tempDir was rmSync'd while sibling
  processes were still alive with it as cwd (EBUSY/SuppressedError on
  Windows). Pass expectSuccess=false at those sites and rely on the
  explicit exit-code assertions that follow, so every child is awaited
  before disposal.

@claude claude Bot 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.

LGTM — test-only speedup with tightened assertions and preserved coverage.

What was reviewed:

  • Concurrency safety: mutating tests each own a using tempDir; the shared readonlyDir is only touched by pure get/help tests and removed in afterAll.
  • Promise.all fan-outs inside a using scope pass expectSuccess=false so every child is awaited before disposal (b0bb4f5).
  • Float stdout coverage: restored via the testFloat fixture field and the data-types loop; other removed follow-up get spawns are covered by the dedicated get suite.
  • toContain chains replaced by toEqual/toMatchObject on parsed JSON are equal-or-stronger; 74 pass / 3 todo unchanged.
Extended reasoning...

Overview

Single-file, test-only refactor of test/cli/install/bun-pm-pkg.test.ts. Switches the outer describe to .concurrent, gives every mutating test its own using tempDir, shares one read-only fixture across pure get tests, replaces follow-up bun pm pkg get verification spawns with direct package.json reads, parallelises per-notation loops via Promise.all, drops redundant rmSync/try…finally around using fixtures, reorders assertions to check stdout/stderr before exitCode, and tightens toContain chains into toEqual/toMatchObject on parsed JSON. No src/ changes.

Security risks

None. Test-only; spawns the local bunExe() against per-test temp dirs, no network, no new inputs.

Level of scrutiny

Low-medium. The risks with a serial→concurrent conversion are shared mutable state and fixture lifetime vs. child-process lifetime. I checked both:

  • Shared state: the only cross-test fixture is readonlyDir, created in beforeAll (wrapped in String() so it isn't auto-disposed) and removed in afterAll. Every test that references it is a read-only get/help invocation; every set/delete/fix test allocates its own using dir = makeTestDir().
  • Fixture lifetime: the four Promise.all fan-outs that run inside a using tempDir scope pass expectSuccess=false, so runPmPkg never throws mid-batch and every child is awaited (via await using proc + proc.exited) before the scope exits and the dir is removed. The remaining fan-outs target readonlyDir, which outlives all tests. This was the concern addressed in b0bb4f5 and it checks out.

Other factors

  • Coverage: the removed secondary get spawns only re-read a value the test just wrote; get itself is still exercised by the dedicated get suite plus the notation/compat blocks. The one case where the follow-up get was the only stdout check for a value shape (float 3.14) was restored via the testFloat fixture field and the data-types loop. Reading package.json directly is an equal-or-stronger assertion on the on-disk result.
  • Assertion strength: replacing multi-toContain on raw stdout with toEqual on parsed JSON is strictly tighter (exact shape, no substring false positives). Test count unchanged at 74 pass / 3 todo.
  • Conventions: matches CLAUDE.md/REVIEW.md guidance — tempDir from harness with using, stdout/stderr asserted before exitCode, test.concurrent for independent subprocess tests, no manual cleanup alongside using.
  • CI on 9a3387d passed this file on every lane; the one red job was an unrelated proxy stress test.
  • Overlap with stale omnibus #33704 is acknowledged; this is standalone and goes further (spawn reduction, structural assertions).

@robobun

robobun commented Jul 29, 2026 •

Copy link
Copy Markdown
Collaborator Author
Updated 6:05 AM PT - Jul 29th, 2026

@robobun, your commit b0bb4f5 is building: #85102

@Jarred-Sumner
Jarred-Sumner merged commit e1b8e61 into main Jul 29, 2026
48 of 52 checks passed
@Jarred-Sumner
Jarred-Sumner deleted the farm/f99eb546/speedup-pm-pkg-test branch July 29, 2026 12:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants