Skip to content

test(cli/upgrade): tolerate the canary re-upload 404 and add a hermetic FILE_SHARE_DELETE test#34300

Open
robobun wants to merge 2 commits into
mainfrom
farm/27d0d7cf/hermetic-upgrade-test
Open

test(cli/upgrade): tolerate the canary re-upload 404 and add a hermetic FILE_SHARE_DELETE test#34300
robobun wants to merge 2 commits into
mainfrom
farm/27d0d7cf/hermetic-upgrade-test

Conversation

@robobun

@robobun robobun commented Jul 16, 2026

Copy link
Copy Markdown
Collaborator

Problem

test/cli/install/bun-upgrade.test.ts went red on the darwin-aarch64 lane in build 73614:

error: expect(received).not.toContain(expected)
Expected to not contain: "error:"
Received: "Downloading... error: Canary builds are not available for this platform yet
   Release: https://github.com/oven-sh/bun/releases/tag/canary
  Filename: bun-darwin-aarch64.zip"

Cause

The zero arguments, should succeed test starts a local TLS server and passes GITHUB_API_DOMAIN=<mock> so the upgrade command would fetch release metadata from it. But GITHUB_API_DOMAIN is only read inside get_latest_version, and that function is only called on the --stable path. On canary builds (every CI build has IS_CANARY = true) bun upgrade constructs a hard-coded https://github.com/oven-sh/bun/releases/download/canary/<zip> URL and downloads it directly, so the mock is never consulted and the test pulls the real canary archive from github.com on every run. Confirmed by request-counting the mock: it sees zero hits on a canary build.

Build 73614 ran 03:57 to 06:17 UTC on 2026-07-16; the bun-darwin-aarch64.zip asset on the canary release was re-created at 06:03:07 UTC. The test caught the brief 404 window between the old asset being removed and the new one appearing. The mock server was introduced in #10387 but the canary path predates it and has always been a direct download.

Two adjacent issues surfaced while investigating:

  • closeTempDirHandle() is called immediately after Bun.spawn() returns, so the Windows FILE_SHARE_DELETE handle is released before the child process has done anything. The original spawnSync version held it for the whole run; the async rewrite (bf1e492) inadvertently dropped that guarantee.
  • The mock server also pointed every browser_download_url at an external R2 host, so even on the --stable path the archive download left the machine.

Fix

Keep the live end-to-end check (it is the only thing that exercises the full download/extract/verify/install path against a real release), but stop the one known non-bug transient from turning CI red, and add a hermetic backstop for the Windows temp-dir path.

  • zero arguments, should succeed: drop the mock server (dead code on canary builds), hold the Windows FILE_SHARE_DELETE handle for the entire child run instead of releasing it right after Bun.spawn(), and only back off the broad expect(stderr).not.toContain("error:") when stderr carries exactly the Canary builds are not available for this platform yet 404 that marks the canary release re-upload window. Any other error: still fails the test. The argument-parser assertion is always enforced.
  • New completes the download when the OS temp dir is held open without FILE_SHARE_DELETE: a hermetic variant that passes --stable so GITHUB_API_DOMAIN is honored, serves both the release JSON and the archive from a local server (with ambient proxy env vars cleared in both casings), holds the temp-dir handle for the whole run, and asserts the mock saw exactly one metadata and one archive request. This covers the temp-dir staging path deterministically so it stays exercised even when the live test has to back off its broad assertion.

Both tests intentionally wrap the upgrade in the FILE_SHARE_DELETE handle: the live test matches what #10387 originally set out to cover, the hermetic test guarantees the path is reached regardless of external network state.

No src/ changes; this is a test-only robustness fix. The stash-src fail-before check does not apply.

Verified: all 9 tests in the file pass on linux-x64 (debug) and windows-x64 (debug).

Fixes #11482

…metic

The 'zero arguments, should succeed' test set up a mock release server and
passed GITHUB_API_DOMAIN pointing at it, but on canary builds (every CI
build) bun upgrade constructs a hard-coded
https://github.com/oven-sh/bun/releases/download/canary/<zip> URL and
never calls get_latest_version, so the mock was never consulted and the
test downloaded the real canary archive from github.com on every run.
When the canary release is being re-uploaded the asset briefly 404s and
the test fails with 'Canary builds are not available for this platform
yet', as seen on the darwin-aarch64 lane in build 73614.

Split the two concerns the old test mixed:
- 'zero arguments, should succeed' is now a pure argument-parser test
  matching its siblings: the download is routed through a proxy nothing
  is listening on so it fails locally, and only the package-name error
  is asserted against.
- The Windows FILE_SHARE_DELETE coverage moves to a new hermetic test
  that serves both the release JSON and the archive from a local server
  via --stable, and holds the temp-dir handle for the entire upgrade run
  (it was previously released immediately after Bun.spawn returned, so
  the handle was already closed by the time the child touched the temp
  dir).
@coderabbitai

coderabbitai Bot commented Jul 16, 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: 3 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: e484aeec-7f2d-4426-ab71-1f0536dfa3d2

📥 Commits

Reviewing files that changed from the base of the PR and between fbe467c and 81c36ce.

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

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

@robobun

robobun commented Jul 16, 2026

Copy link
Copy Markdown
Collaborator Author
Updated 12:55 AM PT - Jul 16th, 2026

@robobun, your commit 81c36ce has 2 failures in Build #73683 (All Failures):


🧪   To try this PR locally:

bunx bun-pr 34300

That installs a local version of the PR into your bun-34300 executable, so you can run:

bun-34300 --bun

@github-actions

Copy link
Copy Markdown
Contributor

Found 1 issue this PR may fix:

  1. Fix flaky test bun-upgrade.test.ts #11482 - Tracks the exact flaky bun-upgrade.test.ts test that this PR makes hermetic by removing the live canary release dependency

If this is helpful, copy the block below into the PR description to auto-close this issue on merge.

Fixes #11482

🤖 Generated with Claude Code

@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 hermetic-ness fix that mirrors the existing sibling tests in this file. The one nit (lowercase proxy vars) is optional and can't reintroduce the flake given the narrow assertion.

Extended reasoning...

Overview

This PR touches a single test file, test/cli/install/bun-upgrade.test.ts, to fix a flake caused by the zero arguments, should succeed test silently downloading the live canary release from github.com on every CI run. The fix splits the test into (1) a pure arg-parser check that routes the download through a dead proxy, and (2) a new dedicated FILE_SHARE_DELETE test that uses --stable so GITHUB_API_DOMAIN is honored and the mock server is actually consulted. No src/ changes.

Security risks

None. Test-only change; the new test uses a local TLS mock server with the same tls fixture and NODE_TLS_REJECT_UNAUTHORIZED=0 pattern already used by the two sibling tests directly below it.

Level of scrutiny

Low-to-moderate. This is test infrastructure with no runtime impact, and the new FILE_SHARE_DELETE test is structurally near-identical to the existing recreates the staging directory and verifies the downloaded release archive tests in the same file (same assetNames loop, same mock-server shape, same --stable + GITHUB_API_DOMAIN + ASAN_OPTIONS env setup). The root-cause analysis in the PR description is detailed and verifiable — GITHUB_API_DOMAIN is indeed only read on the --stable path, so the old test's mock was dead code on canary CI builds.

Other factors

  • The new test correctly moves outside describe.concurrent() (global openTempDirWithoutSharingDelete state) and holds the handle in a try/finally for the full child lifetime, fixing the premature closeTempDirHandle() the PR description calls out.
  • The apiHits > 0 assertion guards against the mock silently going unused again — the exact failure mode that let the old test pass for years while hitting github.com.
  • Resource management is sound: using server, await using proc scoped inside the try block so disposal precedes closeTempDirHandle().
  • The one inline nit (lowercase https_proxy / NO_PROXY precedence) is real but cannot cause a flake: the assertion only checks that the arg-parser error line is absent, which holds regardless of whether the download fails, times out, or succeeds. Worth the four-line follow-up but not blocking.
  • Verified passing on linux-x64 and windows-x64 debug per the PR description.

Comment thread test/cli/install/bun-upgrade.test.ts Outdated
…y re-upload 404

- 'zero arguments' runs the real canary upgrade against a copied binary
  again (end-to-end coverage), with the temp-dir handle held for the whole
  run, and only backs off the broad 'error:' assertion when stderr carries
  the specific 'Canary builds are not available for this platform yet'
  404 that marks the canary release re-upload window.
- the hermetic FILE_SHARE_DELETE test now counts the archive download
  separately and asserts both metadata and download hits, so a failure
  before filesystem.tmpdir() no longer satisfies the assertions.
- clear both casings of the proxy env vars and NO_PROXY in the hermetic
  test so an ambient proxy on the runner cannot divert the mock traffic.

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

Thanks for the follow-up — the proxy-env concern from my earlier note is now moot (the dead-proxy approach was dropped from zero arguments, and the new hermetic FILE_SHARE_DELETE test clears both the lowercase and uppercase proxy vars plus no_proxy). Deferring to a human to sign off on the final shape: the latest commit walked back to keeping zero arguments as a live github.com download (now tolerating the canary 404 window) while also adding the hermetic --stable variant, so both tests hold the FILE_SHARE_DELETE handle and the PR title/description ("stop … depending on the live canary release", "No external network") no longer quite match what ships.

Extended reasoning...

Overview

Test-only change to test/cli/install/bun-upgrade.test.ts. Two commits: 14b23e3 made zero arguments, should succeed hermetic via a dead-proxy override and split the Windows FILE_SHARE_DELETE coverage into a new hermetic --stable test that serves both the release JSON and the archive from a local TLS server. 81c36ce (responding to my earlier note) then dropped the dead-proxy approach in favour of keeping the live canary download but tolerating the "Canary builds are not available for this platform yet" 404 window, and applied the lowercase/no_proxy env clearing to the new hermetic test with a tightened { apiHits: 1, downloadHits: 1 } assertion.

Security risks

None. Test-only; no auth, crypto, or permission surface touched. NODE_TLS_REJECT_UNAUTHORIZED: "0" is scoped to a subprocess talking to a self-signed local server, matching neighbouring tests in the same file.

Level of scrutiny

Moderate. It's test infrastructure with no production impact, but it encodes a design choice about whether bun-upgrade.test.ts should keep a live-network end-to-end check. The final revision keeps the ~100 MB live canary download on every CI run (same as before the PR) and only adds a conditional skip for the specific 404 window that caused #11482 — which is fine, but the PR title and description still describe the earlier fully-hermetic approach, so a human should confirm this is the intended trade-off.

Other factors

  • My prior inline nit is stale: the HTTPS_PROXY: "http://127.0.0.1:1" block it referenced no longer exists; the concern was addressed by clearing all six proxy vars in the new hermetic test instead.
  • Both zero arguments (inside describe.concurrent) and the new top-level test call openTempDirWithoutSharingDelete()/closeTempDirHandle(), which back onto a process-global handle. They don't overlap (top-level it runs after the concurrent block completes, and no other test in the concurrent block touches the helper), but it's worth a human glance to confirm the double coverage is intentional rather than an artefact of the mid-PR direction change.
  • The new hermetic test mirrors the shape of the two existing mock-server tests below it (same asset-name matrix, same ASAN_OPTIONS leak-detection opt-out, exitCode === 1 on the bogus zip), and the author reports all 9 tests pass on linux-x64 and windows-x64 debug.

@robobun robobun changed the title test(cli/upgrade): stop bun-upgrade.test.ts depending on the live canary release test(cli/upgrade): tolerate the canary re-upload 404 and add a hermetic FILE_SHARE_DELETE test Jul 16, 2026
@robobun

robobun commented Jul 16, 2026

Copy link
Copy Markdown
Collaborator Author

The diff is ready: bun-upgrade.test.ts passes on every lane in build 73683. The remaining red on that build is test-worker-message-port-transfer-terminate.js (pre-existing on main, unrelated to this change) and two flakes that passed on retry.

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.

Fix flaky test bun-upgrade.test.ts

1 participant