Skip to content

test(sql): drive postgres-datestyle from a scripted backend instead of a docker container - #35738

Open
robobun wants to merge 1 commit into
mainfrom
farm/eadfe1c8/speed-up-postgres-datestyle-test
Open

robobun wants to merge 1 commit into
mainfrom
farm/eadfe1c8/speed-up-postgres-datestyle-test

Conversation

@robobun

@robobun robobun commented Jul 25, 2026 •

Copy link
Copy Markdown
Collaborator

What

test/js/sql/postgres-datestyle.test.ts was taking ~34s on darwin 14 aarch64 in CI (build #80083). All of that was the postgres_plain container cold-start inside describeWithContainer; the two tests themselves run in about a second.

This replaces the container-backed end-to-end test with a scripted v3 backend (the same wire-frames.ts helpers postgres-infinity-date.test.ts already uses), so the file no longer needs docker at all.

Why this is equivalent coverage

The container test did three things:

  1. ALTER DATABASE bun_sql_test SET datestyle = 'SQL, DMY', then opened a new connection and checked current_setting('datestyle') was ISO. That proves a StartupMessage DateStyle parameter outranks an ALTER DATABASE default, which is Postgres's documented GUC precedence (PGC_S_CLIENT > PGC_S_DATABASE); it is not Bun behaviour.
  2. Selected '2026-04-03'::date and '2026-07-22'::date via .simple() and checked the decoded Date objects.
  3. Selected '2026-04-03'::date via the extended protocol and checked the decoded Date.

The scripted backend covers the same ground from Bun's side:

  • It parses the StartupMessage and, like a real server, honours the DateStyle the client sent. If DateStyle=ISO is present it emits ISO date text; if not it emits the SQL, DMY text (03/04/2026, 22/07/2026) that an ALTER DATABASE ... SET datestyle = 'SQL, DMY' default would produce.
  • It serves the simple query (Q) with three columns (current_setting, two dates) and the extended query (P/B) with one date column.
  • The assertions are the same dates, the same .toISOString() values, plus the session DateStyle the client observed.

Because the mock reacts to what Bun actually sends, the test still fails-before the StartupMessage.rs fix: on a build without the DateStyle startup parameter the mock falls through to SQL, DMY, and the decoder produces 2026-03-04 (month/day swapped) and Invalid Date, which the single toEqual shows as a clean diff.

The first test (StartupMessage bytes contain DateStyle=ISO) is unchanged apart from hoisting the key/value-pair parser into a shared parseStartupParams helper.

Side benefit

Without docker and without a BUN_TEST_SERVICE_postgres_plain env override, the old end-to-end test was describe.todo'd (0 coverage). The wire-mock version always runs.

Timing

  • CI darwin 14 aarch64 (build #80083): 34s wall time, entirely container cold-start. After: no container, so that cost is gone; the test body is <1s.
  • Local bun bd test (debug+ASAN, warm Postgres via env var): before ~4–8s, after ~4–8s. Unchanged here because the env-var path never paid the cold-start cost; the whole file is dominated by debug-runner startup either way.
  • Local bun bd test with no Postgres / docker: before ran 1 test (container block todo'd), after runs 2 tests in the same ~4s.

Verification

$ bun bd test test/js/sql/postgres-datestyle.test.ts
(pass) StartupMessage pins DateStyle=ISO so server-side datestyle defaults cannot corrupt dates
(pass) database-level non-ISO DateStyle default does not corrupt date values
 2 pass, 0 fail
fail-before on a build without the StartupMessage fix
error: expect(received).toEqual(expected)
  {
-   "d": "2026-04-03T00:00:00.000Z",
-   "d2": "2026-07-22T00:00:00.000Z",
-   "ds": "ISO, MDY",
-   "ext": "2026-04-03T00:00:00.000Z",
-   "seenDateStyle": "ISO, MDY",
+   "d": "2026-03-04T00:00:00.000Z",
+   "d2": "Invalid Date",
+   "ds": "SQL, DMY",
+   "ext": "2026-03-04T00:00:00.000Z",
+   "seenDateStyle": "",
  }

[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/js/sql/postgres-datestyle.test.ts'
$ BUN_DEBUG_QUIET_LOGS=1 bun scripts/build.ts --profile=debug --quiet test test/js/sql/postgres-datestyle.test.ts
bun test v1.4.0 (3ed2e0fa8)

test/js/sql/postgres-datestyle.test.ts:
(pass) StartupMessage pins DateStyle=ISO so server-side datestyle defaults cannot corrupt dates [692.62ms]
(pass) database-level non-ISO DateStyle default does not corrupt date values [321.71ms]

 2 pass
 0 fail
 3 expect() calls
Ran 2 tests across 1 file. [4.23s]
Exit: 0
diff hotspot
test/js/sql/postgres-datestyle.test.ts | 171 +++++++++++++++++++++++++--------
 1 file changed, 130 insertions(+), 41 deletions(-)

gate history · 1 passed · 0 rejected · iteration 0

evidence per changed file
file                                    reads  edits  tests
test/js/sql/postgres-datestyle.test.ts      3      3      0

self-review · no surviving concerns

28 concerns were raised and did not survive verification.

@coderabbitai

coderabbitai Bot commented Jul 25, 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: 9 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: f8e5e173-67b8-4807-b9a9-bfe160bb7681

📥 Commits

Reviewing files that changed from the base of the PR and between df6c7ee and 3ed2e0f.

📒 Files selected for processing (1)
  • test/js/sql/postgres-datestyle.test.ts

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

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

No bugs found. This is a well-reasoned test refactor that follows the established postgres-infinity-date.test.ts wire-mock pattern, and the fail-before property is demonstrably preserved. Deferring only because swapping a real-Postgres container test for a scripted backend is a coverage trade-off (the mock encodes the GUC-precedence assumption rather than exercising it) — that judgment call is worth a maintainer's quick sign-off rather than a bot approval.

What was reviewed

  • Verified all wire-frames.ts imports exist and the P/B response sequence matches the sibling test's pattern.
  • Checked the mock buffers partial TCP chunks correctly before parsing the StartupMessage and hands the remainder to pgReadFrontendMessages.
  • Confirmed parseStartupParams is a byte-identical hoist of the previously-inlined logic.
  • Confirmed the mock's DateStyle branch keeps the test failing on a build without the StartupMessage fix (fails for the right reason).
Extended reasoning...

Overview

Test-only change to test/js/sql/postgres-datestyle.test.ts. The second test previously ran inside describeWithContainer("postgres", { image: "postgres_plain" }, ...), which cost ~34s of container cold-start on macOS CI and was .todo'd entirely when docker/env-var wasn't available. It is replaced with a scripted v3 backend built from the existing test/js/sql/wire-frames.ts helpers — the same pattern postgres-infinity-date.test.ts already uses for its extended-protocol mock. The first test is unchanged apart from hoisting the StartupMessage key/value parser into a shared parseStartupParams helper. No production code is touched.

Security risks

None. This is a test file talking to an in-process net.createServer on 127.0.0.1:0. No external network, no auth, no crypto, no file writes outside the test's own socket.

Level of scrutiny

Moderate. It's test-only, but REVIEW.md is explicit that weakening or deleting an existing test needs a stated reason and equivalent coverage. The PR body argues equivalence carefully: the container test's "ALTER DATABASE default is overridden by StartupMessage param" step is Postgres's documented GUC precedence (PGC_S_CLIENT > PGC_S_DATABASE), not Bun behaviour, so the mock encodes that precedence and instead exercises what Bun controls — that the StartupMessage carries DateStyle=ISO and that Bun's decoder handles the resulting ISO text on both simple (Q) and extended (P/B) paths. Crucially, the mock branches on the actual StartupMessage bytes, so a build without the StartupMessage.rs fix falls through to SQL, DMY output and the test fails with the month/day-swap and Invalid-Date diff shown in the PR body. That preserves the "fails for the right reason" property REVIEW.md requires.

Why defer rather than approve

The refactor is correct and idiomatic, but it does trade real-server end-to-end coverage for a mock that assumes Postgres honours the startup parameter. That assumption is well-documented and unlikely to break, and the first (unchanged) test already asserts the load-bearing wire bytes directly — so I think the trade is sound. Still, "replace container integration test with a wire mock" is exactly the kind of coverage decision a maintainer should ratify rather than a bot. There's nothing to fix; this just wants a human 👍.

Other factors

  • All imported wire-frames.ts helpers exist and are used with the same message sequencing as postgres-infinity-date.test.ts (ParseComplete + ParameterDescription + RowDescription + RFQ on P; BindComplete + DataRow + CommandComplete + RFQ on B).
  • The socket data handler correctly accumulates partial chunks, length-prefix-frames the StartupMessage, and only then feeds pgReadFrontendMessages — no split-read hazard.
  • Server is closed in finally; connectionTimeout: 5 bounds any hang.
  • The new seenDateStyle: "ISO, MDY" assertion is stricter than the first test's /^ISO\b/ regex, which is fine (it pins the exact value Bun sends).

@robobun

robobun commented Jul 25, 2026 •

Copy link
Copy Markdown
Collaborator Author
Updated 10:14 AM PT - Jul 25th, 2026

❌ @robobun, your commit 3ed2e0f has 1 failures in Build #80970 (All Failures):

  • 📦 Binary size — 12 over 0.50 MB
  • targetthis build canary: main #79916
    sizeΔ
    ❌ bun-darwin-aarch6458.13 MB57.58 MB+564.9 KB
    ❌ bun-darwin-x6463.48 MB62.95 MB+544.5 KB
    ❌ bun-linux-aarch6470.98 MB70.42 MB+576.0 KB
    ❌ bun-linux-x6472.47 MB71.95 MB+528.0 KB
    ❌ bun-linux-aarch64-musl64.88 MB64.32 MB+576.0 KB
    ❌ bun-linux-x64-musl66.98 MB66.45 MB+544.0 KB
    ❌ bun-linux-aarch64-android78.47 MB77.97 MB+512.0 KB
    ❌ bun-linux-x64-android80.62 MB80.10 MB+529.2 KB
    ❌ bun-freebsd-x6483.07 MB82.56 MB+528.0 KB
    ❌ bun-freebsd-aarch6484.84 MB84.31 MB+544.0 KB
    ❌ bun-windows-x6480.26 MB79.70 MB+570.0 KB
    ❌ bun-windows-aarch6470.86 MB70.34 MB+532.5 KB

    Add [skip size check] to the commit message if this increase is intentional.


🧪   To try this PR locally:

bunx bun-pr 35738

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

bun-35738 --bun

@robobun

robobun commented Jul 25, 2026 •

Copy link
Copy Markdown
Collaborator Author

CI is green apart from the binary-size check, which flags a ~530 KB growth against canary #79916. This diff is test-only and touches no native code, so that growth comes from main between the canary and df6c7ee, not from this PR.

Self-review raised no concerns.

Measured wall time on darwin 14 aarch64 (the lane the 34s came from):

  • build #80083 (before): 34s
  • build #80970 (after): 64ms (log)

The file also runs third in its shard now instead of being reordered to the end, because it no longer matches any describeWithContainer scheduling.

This branch has not been deployed

No deployments
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.

1 participant