73 Commits

Author SHA1 Message Date
robobun
a394063a7d refactor(test): use container-based postgres_tls for TLS SQL tests (#26518)
## Summary
- Refactors `tls-sql.test.ts` to use `describeWithContainer` with a
local Docker container instead of external Neon secrets
- Updates `postgres_tls` service to build from Dockerfile (fixes SSL key
permission issues)
- Fixes pg_hba.conf to allow local socket connections for init scripts

## Test plan
- [x] Verified tests pass locally with `bun bd test
test/js/sql/tls-sql.test.ts` (30 tests pass)
- [ ] CI passes on x64 Linux (arm64 Docker tests are currently disabled)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-27 23:32:39 -08:00
Markus Schmidt
b6abbd50a0 fix(Bun.SQL): handle binary columns in MySQL correctly (#26011)
## What does this PR do?
Currently binary columns are returned as strings which means they get
corrupted when encoded in UTF8. This PR returns binary columns as
Buffers which is what user's actually expect and is also consistent with
PostgreSQL and SQLite.
### How did you verify your code works?
I added tests to verify the correct behavior. Before there were no tests
for binary columns at all.

This fixes #23991
2026-01-12 11:56:02 -08:00
Alistair Smith
bf937f7294 sql: filter out undefined values in INSERT helper instead of treating as NULL (#25830)
### What does this PR do?

the `sql()` helper now filters out `undefined` values in INSERT
statements instead of converting them to `NULL`. This allows columns
with `DEFAULT` values to use their defaults when `undefined` is passed,
rather than being overridden with `NULL`.

**Before:** `sql({ foo: undefined, id: "123" })` in INSERT would
generate `(foo, id) VALUES (NULL, "123")`, causing NOT NULL constraint
violations even when the column has a DEFAULT.

**After:** `sql({ foo: undefined, id: "123" })` in INSERT generates
`(id) VALUES ("123")`, omitting the undefined column entirely and
letting the database use the DEFAULT value.

Also fixes a data loss bug in bulk inserts where columns were determined
only from the first item - now all items are checked, so values in later
items aren't silently dropped.

  Fixes #25829

  ### How did you verify your code works?

  - Added regression test for #25829 (NOT NULL column with DEFAULT)
- Added tests for bulk insert with mixed undefined patterns which is the
data loss scenario
2026-01-05 15:03:20 -08:00
Angus Comrie
d9459f8540 Fix postgres empty check when handling arrays (#25607)
### What does this PR do?
Closes #25505. This adjusts the byte length check in `DataCell:
fromBytes` to 12 bytes instead of 16, as zero-dimensional arrays will
have a shorter preamble.

### How did you verify your code works?
Test suite passes, and I've added a new test that fails in the main
branch but passes with this change. The issue only seems to crop up when
a connection is _reused_, which is curious.
2025-12-19 14:49:12 -08:00
Meghan Denny
998ec54da9 test: fix spacing in sql.test.ts (#24691) 2025-11-28 14:40:58 -08:00
Ciro Spaciari
1e3e693f4a fix(MySQL) ref and status usage (#23873)
### What does this PR do?
Let MySQL unref when idle and make sure that is behaving like this.
Only set up the timers after all status changes are complete since the
timers rely on the status to determine timeouts, this was causing the
CPU usage spike to 100% (thats why only happened in TLS)
CPU usage it self will be improved in
https://github.com/oven-sh/bun/pull/23700 not in this PR

Fixes: https://github.com/oven-sh/bun/issues/23273
Fixes: https://github.com/oven-sh/bun/issues/23256
### How did you verify your code works?
Test

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-10-20 17:40:48 -07:00
robobun
1c4d8b1c1c fix(sql): throw proper exception for invalid MySQL parameter types (#23839)
## Summary

Fixes a panic that occurred when passing `NumberObject` or
`BooleanObject` as MySQL query parameters.

**Panic message:** `A JavaScript exception was thrown, but it was
cleared before it could be read.`

## Root Cause

The `FieldType.fromJS` function in `src/sql/mysql/MySQLTypes.zig` was
returning `error.JSError` without throwing a JavaScript exception first
for:
- `NumberObject` (created via `new Number(42)`)
- `BooleanObject` (created via `new Boolean(true)`)
- Non-indexable types

This violated the contract that `error.JSError` means "an exception has
already been thrown and is ready to be taken."

## Call Chain

1. User executes `await sql\`SELECT ${new Number(42)} as value\``
2. `FieldType.fromJS()` detects `.NumberObject` and returns
`error.JSError` without throwing
3. Error propagates to `MySQLQuery.runPreparedQuery()`
4. Code checks `hasException()` → returns false (no exception exists!)
5. Calls `mysqlErrorToJS(globalObject, "...", error.JSError)`
6. `mysqlErrorToJS` tries to `takeException(error.JSError)` but there's
no exception
7. **PANIC**

## Fix

The fix throws a proper exception with a helpful message before
returning `error.JSError`:
- `"Cannot bind NumberObject to query parameter. Use a primitive number
instead."`
- `"Cannot bind BooleanObject to query parameter. Use a primitive
boolean instead."`
- `"Cannot bind this type to query parameter"`

## Test Plan

Added regression tests in `test/js/sql/sql-mysql.test.ts`:
- Test passing `NumberObject` as parameter
- Test passing `BooleanObject` as parameter

Both tests verify that a proper error is thrown instead of crashing.

Verified manually with local MySQL server that:
-  NumberObject now throws proper error (was crashing)
-  BooleanObject now throws proper error (was crashing)
-  Primitive numbers still work correctly

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
2025-10-20 12:31:08 -07:00
Ciro Spaciari
3c9433f9af fix(sqlite) enable order by and limit in delete/update statements on windows (#23227)
### What does this PR do?

Enable compiler flags
Update SQLite amalgamation using https://www.sqlite.org/download.html
source code
[sqlite-src-3500400.zip](https://www.sqlite.org/2025/sqlite-src-3500400.zip)
with:

```bash
./configure CFLAGS="-DSQLITE_ENABLE_UPDATE_DELETE_LIMIT"
make sqlite3.c
```

This is the same version that before just with this adicional flag that
must be enabled when generating the amalgamation so we are actually able
to use this option. You can also see that without this the build will
happen but the feature will not be enable
https://buildkite.com/bun/bun/builds/27940, as informed in
https://www.sqlite.org/howtocompile.html topic 5.

### How did you verify your code works?
Add in CI two tests that check if the feature is enabled on windows

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
2025-10-04 02:48:50 -07:00
Ciro Spaciari
e3bd03628a fix(Bun.SQL) fix command detection on sqlite (#23221)
### What does this PR do?
Returning clause should work with insert now
### How did you verify your code works?
Tests

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-10-03 17:50:47 -07:00
Ciro Spaciari
55f8e8add3 fix(Bun.SQL) time should be represented as a string and date as a time (#23193)
### What does this PR do?
Time should be represented as HH:MM:SS or HHH:MM:SS string
### How did you verify your code works?
Test

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-10-02 19:00:14 -07:00
Ciro Spaciari
5fe3e3774c fix(Bun.SQL) fix IN, UPDATE support in helpers, and fix JSONB/JSON serialization (#22700)
### What does this PR do?
Fixes https://github.com/oven-sh/bun/issues/20669
Fixes https://github.com/oven-sh/bun/issues/18775
Fixes https://github.com/oven-sh/bun/issues/22156
Fixes https://github.com/oven-sh/bun/issues/22164
Fixes https://github.com/oven-sh/bun/issues/18254
Fixes https://github.com/oven-sh/bun/issues/21267
Fixes https://github.com/oven-sh/bun/issues/20669
Fixes https://github.com/oven-sh/bun/issues/1317
Fixes https://github.com/oven-sh/bun/pull/22700
Partially Fixes https://github.com/oven-sh/bun/issues/22757 (sqlite
pending, need a followup and probably @alii help here)
### How did you verify your code works?
Tests

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-09-30 13:26:15 -07:00
Ciro Spaciari
cf1367137d feat(sql.array) add support to sql.array (#22946)
### What does this PR do?
Fixes https://github.com/oven-sh/bun/issues/17030 
In this case should work as expected just passing a normal array should
be serialized as JSON/JSONB

Fixes https://github.com/oven-sh/bun/issues/17798
Insert and update helpers should work as expected here when using
sql.array helper:

```sql
CREATE TABLE user (
    id SERIAL PRIMARY KEY,
    name VARCHAR NOT NULL,
    roles TEXT[]
);
```

```js
const item = { id: 1, name: "test", role: sql.array(['a', 'b'], "TEXT") };
await sql`
  UPDATE user
  SET ${sql(item)}
  WHERE id = 1
`;
```
Fixes https://github.com/oven-sh/bun/issues/22281
Should work using  sql.array(array, "TEXT")

Fixes https://github.com/oven-sh/bun/issues/22165
Fixes https://github.com/oven-sh/bun/issues/22155
Add sql.array(array, typeNameOrTypeID) in Bun.SQL
(https://github.com/oven-sh/bun/issues/15088)

### How did you verify your code works?
Tests

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-09-27 01:12:29 -07:00
pfg
250d30eb7d Concurrent limit --max-concurrency, defaults to 20 (#22944)
### What does this PR do?

Adds a max-concurrency flag to limit the amount of concurrent tests that
run at once. Defaults to 20. Jest and Vitest both default to 5.

### How did you verify your code works?

Tests

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
2025-09-26 16:39:08 -07:00
Meghan Denny
51ce3bc269 [publish images] ci: ensure tests that require docker have it available (#22781) 2025-09-25 19:03:22 -07:00
Meghan Denny
92bc522e85 lsan: fix reporting on linux ci (#22806) 2025-09-24 00:47:52 -07:00
Ciro Spaciari
db22b7f402 fix(Bun.sql) handle numeric correctly (#22925)
### What does this PR do?
Fixes https://github.com/oven-sh/bun/issues/21225
### How did you verify your code works?
Tests

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-09-23 20:14:19 -07:00
Jarred Sumner
0b549321e9 Start using test.concurrent in our tests (#22823)
### What does this PR do?

### How did you verify your code works?

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Claude Bot <claude-bot@bun.sh>
2025-09-22 05:30:34 -07:00
pfg
d2201eb1fe Rewrite test/describe, add test.concurrent (#22534)
# bun test

Fixes #8768, Fixes #14624, Fixes #20100, Fixes #19875, Fixes #14135,
Fixes #20980, Fixes #21830, Fixes #5738, Fixes #19758, Fixes #12782,
Fixes #5585, Fixes #9548, Might fix 5996

# New features:

## Concurrent tests

Concurrent tests allow running multiple async tests at the same time.

```ts
// concurrent.test.ts
test.concurrent("this takes a while 1", async () => {
  await Bun.sleep(1000);
});
test.concurrent("this takes a while 2", async () => {
  await Bun.sleep(1000);
});
test.concurrent("this takes a while 3", async () => {
  await Bun.sleep(1000);
});
```

Without `.concurrent`, this test file takes 3 seconds to run because
each one has to wait for the one before it to finish before it can
start.

With `.concurrent`, this file takes 1 second because all three sleeps
can run at once.

```
$> bun-after test concurrent
concurrent.test.js:
✓ this takes a while 1 [1005.36ms]
✓ this takes a while 2 [1012.51ms]
✓ this takes a while 3 [1013.15ms]

 3 pass
 0 fail
Ran 3 tests across 1 file. [1081.00ms]
```

To run all tests as concurrent, pass the `--concurrent` flag when
running tests.

Limitations:

- concurrent tests cannot attribute `expect()` call counts to the test,
meaning `expect.assertions()` does not function
- concurrent tests cannot use `toMatchSnapshot`. `toMatchInlineSnapshot`
is still supported.
- `beforeAll`/`afterAll` will never be executed concurrently.
`beforeEach`/`afterEach` will.

## Chaining

Chaining multiple describe/test qualifiers is now allowed. Previously,
it would fail.

```ts
// chaining-test-qualifiers.test.ts
test.failing.each([1, 2, 3])("each %i", async i => {
  throw new Error(i);
});
```

```
$> bun-after test chaining-test-qualifiers
a.test.js:
✓ each 1
✓ each 2
✓ each 3
```

# Breaking changes:

## Describe ordering

Previously, describe callbacks were called immediately. Now, they are
deferred until the outer callback has finished running. The previous
order matched Jest. The new order is similar to Vitest, but does not
match exactly.

```ts
// describe-ordering.test.ts
describe("outer", () => {
  console.log("outer before");
  describe("inner", () => {
    console.log("inner");
  });
  console.log("outer after");
});
```

Before, this would print

```
$> bun-before test describe-ordering
outer before
inner
outer after
```

Now, this will print

```
$> bun-after test describe-ordering
outer before
outer after
inner
```

## Test ordering

Describes are no longer always called before tests. They are now in
order.

```ts
// test-ordering.test.ts
test("one", () => {});
describe("scope", () => {
  test("two", () => {});
});
test("three", () => {});
```

Before, this would print

```
$> bun-before test test-ordering
✓ scope > two
✓ one
✓ three
```

Now, this will print

```
$> bun-after test test-ordering
✓ one
✓ scope > two
✓ three
```

## Preload hooks

Previously, beforeAll in a preload ran before the first file and
afterAll ran after the last file. Now, beforeAll will run at the start
of each file and afterAll will run at the end of each file. This
behaviour matches Jest and Vitest.

```ts
// preload.ts
beforeAll(() => console.log("preload: beforeAll"));
afterAll(() => console.log("preload: afterAll"));
```

```ts
// preload-ordering-1.test.ts
test("demonstration file 1", () => {});
```

```ts
// preload-ordering-2.test.ts
test("demonstration file 2", () => {});
```

```
$> bun-before test --preload=./preload preload-ordering
preload-ordering-1.test.ts:
preload: beforeAll
✓ demonstration file 1

preload-ordering-2.test.ts:
✓ demonstration file 2
preload: afterAll
```

```
$> bun-after test --preload=./preload preload-ordering
preload-ordering-1.test.ts:
preload: beforeAll
✓ demonstration file 1
preload: afterAll

preload-ordering-2.test.ts:
preload: beforeAll
✓ demonstration file 2
preload: afterAll
```

## Describe failures

Current behaviour is that when an error is thrown inside a describe
callback, none of the tests declared there will run. Now, describes
declared inside will also not run. The new behaviour matches the
behaviour of Jest and Vitest.

```ts
// describe-failures.test.ts
describe("erroring describe", () => {
  test("this test does not run because its describe failed", () => {
    expect(true).toBe(true);
  });
  describe("inner describe", () => {
    console.log("does the inner describe callback get called?");
    test("does the inner test run?", () => {
      expect(true).toBe(true);
    });
  });
  throw new Error("uh oh!");
});
```

Before, the inner describe callback would be called and the inner test
would run, although the outer test would not:

```
$> bun-before test describe-failures
describe-failures.test.ts:
does the inner describe callback get called?

# Unhandled error between tests
-------------------------------
11 |   throw new Error("uh oh!");
             ^
error: uh oh!
-------------------------------

✓ erroring describe > inner describe > does the inner test run?

 1 pass
 0 fail
 1 error
 1 expect() calls
Ran 1 test across 1 file.
Exited with code [1]
```

Now, the inner describe callback is not called at all.

```
$> bun-after test describe-failures
describe-failures.test.ts:

# Unhandled error between tests
-------------------------------
11 |   throw new Error("uh oh!");
             ^
error: uh oh!
-------------------------------


 0 pass
 0 fail
 1 error
Ran 0 tests across 1 file.
Exited with code [1]
```

## Hook failures

Previously, a beforeAll failure would skip subsequent beforeAll()s, the
test, and the afterAll. Now, a beforeAll failure skips any subsequent
beforeAll()s and the test, but not the afterAll.

```js
beforeAll(() => {
  throw new Error("before all: uh oh!");
});
test("my test", () => {
  console.log("my test");
});
afterAll(() => console.log("after all"));
```

```
$> bun-before test hook-failures
Error: before all: uh oh!

$> bun-after test hook-failures
Error: before all: uh oh!
after all
```

Previously, an async beforeEach failure would still allow the test to
run. Now, an async beforeEach failure will prevent the test from running

```js
beforeEach(() => {
  await 0;
  throw "uh oh!";
});
it("the test", async () => {
  console.log("does the test run?");
});
```

```
$> bun-before test async-beforeeach-failure
does the test run?
error: uh oh!
uh oh!
✗ the test

$> bun-after test async-beforeeach-failure
error: uh oh!
uh oh!
✗ the test
```

## Hook timeouts

Hooks will now time out, and can have their timeout configured in an
options parameter

```js
beforeAll(async () => {
  await Bun.sleep(1000);
}, 500);
test("my test", () => {
  console.log("ran my test");
});
```

```
$> bun-before test hook-timeouts
ran my test
Ran 1 test across 1 file. [1011.00ms]

$> bun-after test hook-timeouts
✗ my test [501.15ms]
  ^ a beforeEach/afterEach hook timed out for this test.
```

## Hook execution order

beforeAll will now execute before the tests in the scope, rather than
immediately when it is called.

```ts
describe("d1", () => {
  beforeAll(() => {
    console.log("<d1>");
  });
  test("test", () => {
    console.log("  test");
  });
  afterAll(() => {
    console.log("</d1>");
  });
});
describe("d2", () => {
  beforeAll(() => {
    console.log("<d2>");
  });
  test("test", () => {
    console.log("  test");
  });
  afterAll(() => {
    console.log("</d2>");
  });
});
```

```
$> bun-before test ./beforeall-ordering.test.ts
<d1>
<d2>
  test
</d1>
  test
</d2>

$> bun-after test ./beforeall-ordering.test.ts
<d1>
  test
</d1>
<d2>
  test
</d2>
```

## test inside test

test() inside test() now errors rather than silently failing. Support
for this may be added in the future.

```ts
test("outer", () => {
    console.log("outer");
    test("inner", () => {
        console.log("inner");
    });
});
```

```
$> bun-before test
outer
✓ outer [0.06ms]

 1 pass
 0 fail
Ran 1 test across 1 file. [8.00ms]

$> bun-after test
outer
1 | test("outer", () => {
2 |     console.log("outer");
3 |     test("inner", () => {
        ^
error: Cannot call test() inside a test. Call it inside describe() instead.
✗ outer [0.71ms]

 0 pass
 1 fail
```

## afterAll inside test

afterAll inside a test is no longer allowed

```ts
test("test 1", () => {
  afterAll(() => console.log("afterAll"));
  console.log("test 1");
});
test("test 2", () => {
  console.log("test 2");
});
```

```
$> bun-before
test 1
✓ test 1 [0.05ms]
test 2
✓ test 2
afterAll

$> bun-after
error: Cannot call afterAll() inside a test. Call it inside describe() instead.
✗ test 1 [1.00ms]
test 2
✓ test 2 [0.20ms]
```

# Only inside only

Previously, an outer 'describe.only' would run all tests inside it even
if there was an inner 'test.only'. Now, only the innermost only tests
are executed.

```ts
describe.only("outer", () => {
    test("one", () => console.log("should not run"));
    test.only("two", () => console.log("should run"));
});
```

```
$> bun-before test
should not run
should run

$> bun-after test
should run
```

With no inner only, the outer only will still run all tests:

```ts
describe.only("outer", () => {
    test("test 1", () => console.log("test 1 runs"));
    test("test 2", () => console.log("test 2 runs"));
});
```

# Potential follow-up work

- [ ] for concurrent tests, display headers before console.log messages
saying which test it is for
  - this will need async context or similar
- refActiveExecutionEntry should also be able to know the current test
even in test.concurrent
- [ ] `test("rerun me", () => { console.log("run one time!"); });`
`--rerun-each=3` <- this runs the first and third time but not the
second time. fix.
- [ ] should to cache the JSValue created from
DoneCallback.callAsFunction
- [ ] implement retry and rerun params for tests.
- [ ] Remove finalizer on ScopeFunctions.zig by storing the data in 3
jsvalues passed in bind rather than using a custom class. We should also
migrate off of the ClassGenerator for ScopeFunctions
- [ ] support concurrent limit, how many concurrent tests are allowed to
run at a time. ie `--concurrent-limit=25`
- [ ] flag to run tests in random order
- [ ] `test.failing` should have its own style in the same way
`test.todo` passing marks as 'todo' insetead of 'passing'. right now
it's `✓` which is confusing.
- [ ] remove all instances of bun.jsc.Jest.Jest.current
  - [ ] test options should be in BunTestRoot
- [ ] we will need one global still, stored in the globalobject/vm/?.
but it should not be a Jest instance.
- [ ] consider allowing test() inside test(), as well as afterEach and
afterAll. could even allow describe() too. to do this we would switch
from indices to pointers and they would be in a linked list. they would
be allocated in memorypools for perf/locality. some special
consideration is needed for making sure repeated tests lose their
temporary items. this could also improve memory usage soomewhat.
- [ ] consider using a jsc Bound Function rather than CallbackWithArgs.
bound functions allow adding arguments and they are only one value for
GC instead of many. and this removes our unnecessary three copies.
- [ ] eliminate Strong.Safe. we should be using a C++ class instead.
- [ ] consider modifying the junit reporter to print the whole describe
tree at the end instead of trying to output as test results come in. and
move it into its own file.
- [ ] expect_call_count/expect_assertions is confusing. rename to
`expect_calls`, `assert_expect_calls`. or something.
- [ ] Should make line_no be an enum with a none option and a function
to get if line nombers are enabled
- [ ] looks like we don't need to use file_id anymore (remove
`bun.jsc.Jest.Jest.runner.?.getOrPutFile(file_path).file_id;`, store the
file path directly)
- [ ] 'dot' test reporter like vitest?
- [ ] `test.failing.if(false)` errors because it can't replace mode
'failing' with mode 'skip'. this should probably be allowed instead.
- [ ] trigger timeout termination exception for `while(true) {}`
- [ ] clean up unused callbacks. as soon as we advance to the next
execution group, we can fully clean out the previous one. sometimes
within an execution sequence we can do the same.
  - clean by swapping held values with undefined
- [ ] structure cache for performance for donecallback/scopefunctions
- [ ] consider migrating CallbackWithArgs to be a bound function. the
length of the bound function can exclude the specified args.
- [ ] setting both result and maybe_skip is not ideal, maybe there
should be a function to do both at once?
- [ ] try using a linked list rather than arraylist for describe/test
children, see how it affects performance
- [ ] consider a memory pool for describescope/executionentry. test if
it improves performance.
- [ ] consider making RefDataValue methods return the reason for failure
rather than ?value. that way we can improve error messages. the reason
could be a string or it could be a defined error set
- [ ] instead of 'description orelse (unnamed)', let's have description
default to 'unnamed' and not free it if it === the global that defines
that
- [ ] Add a phase before ordering results that inherits properties to
the parents. (eg inherit only from the child and inherit has_callback
from the child. and has_callback can be on describe/test individually
rather than on base). then we won't have that happening in an init()
function (terrible!)
- [ ] this test was incidentally passing because resolves.pass() wasn't
waiting for promise
  ```
  test("fetching with Request object - issue #1527", async () => {
    const server = createServer((req, res) => {
      res.end();
    }).listen(0);
    try {
      await once(server, "listening");

      const body = JSON.stringify({ foo: "bar" });
const request = new Request(`http://localhost:${server.address().port}`,
{
        method: "POST",
        body,
      });

      expect(fetch(request)).resolves.pass();
    } finally {
      server.closeAllConnections();
    }
  });
  ```
- [ ] the error "expect.assertions() is not supported in the describe
phase, in concurrent tests, between tests, or after test execution has
completed" is not very good. we should be able to identify which of
those it is and print the right error for the context
- [ ] consider: instead of storing weak pointers to BunTest, we can
instead give the instance an id and check that it is correct when
getting the current bun test instance from the ref
- [ ] auto_killer: add three layers of auto_killer:
  - preload (includes file & test)
  - file (includes test)
  - test
- that way at the end of the test, we kill the test processes. at the
end of the file, we kill the file processes. at the end of all, we kill
anything remaining.

AsyncLocalStorage

- store active_id & refdatavalue. active_id is a replacement for the
above weak pointers thing. refdatavalue is for determining which test it
is. this probably fits in 2×u64
- use for auto_killer so timeouts can kill even in concurrent tests

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-09-20 00:35:42 -07:00
robobun
f8aed4826b Migrate all Docker usage to unified docker-compose infrastructure (#22740)
## Summary

This PR migrates all Docker container usage in tests from individual
`docker run` commands to a centralized Docker Compose setup. This makes
tests run **10x faster**, eliminates port conflicts, and provides a much
better developer experience.

## What is Docker Compose?

Docker Compose is a tool for defining and running multi-container Docker
applications. Instead of each test file managing its own containers with
complex `docker run` commands, we define all services once in a YAML
file and Docker Compose handles the orchestration.

## The Problem (Before)

```javascript
// Each test file managed its own container
const container = await Bun.spawn({
  cmd: ["docker", "run", "-d", "-p", "0:5432", "postgres:15"],
  // ... complex setup
});
```

**Issues:**
- Each test started its own container (30+ seconds for PostgreSQL tests)
- Containers were killed after each test (wasteful!)
- Random port conflicts between tests
- No coordination between test suites
- Docker configuration scattered across dozens of test files

## The Solution (After)

```javascript
// All tests share managed containers
const pg = await dockerCompose.ensure("postgres_plain");
// Container starts only if needed, returns connection info
```

**Benefits:**
- Containers start once and stay running (3 seconds for PostgreSQL tests
- **10x faster!**)
- Automatic port management (no conflicts)
- All services defined in one place
- Lazy loading (services only start when needed)
- Same setup locally and in CI

## What Changed

### New Infrastructure
- `test/docker/docker-compose.yml` - Defines all test services
- `test/docker/index.ts` - TypeScript API for managing services  
- `test/docker/README.md` - Comprehensive documentation
- Configuration files and init scripts for services

### Services Migrated

| Service | Status | Tests |
|---------|--------|--------|
| PostgreSQL (plain, TLS, auth) |  | All passing |
| MySQL (plain, native_password, TLS) |  | All passing |
| S3/MinIO |  | 276 passing |
| Redis/Valkey |  | 25/26 passing* |
| Autobahn WebSocket |  | 517 available |

*One Redis test was already broken before migration (reconnection test
times out)

### Key Features

- **Dynamic Ports**: Docker assigns available ports automatically (no
conflicts!)
- **Unix Sockets**: Proxy support for PostgreSQL and Redis Unix domain
sockets
- **Persistent Data**: Volumes for services that need data to survive
restarts
- **Health Checks**: Proper readiness detection for all services
- **Backward Compatible**: Fallback to old Docker method if needed

## Performance Improvements

| Test Suite | Before | After | Improvement |
|------------|--------|-------|-------------|
| PostgreSQL | ~30s | ~3s | **10x faster** |
| MySQL | ~25s | ~3s | **8x faster** |
| Redis | ~20s | ~2s | **10x faster** |

The improvements come from container reuse - containers start once and
stay running instead of starting/stopping for each test.

## How to Use

```typescript
import * as dockerCompose from "../../docker/index.ts";

test("database test", async () => {
  // Ensure service is running (starts if needed)
  const pg = await dockerCompose.ensure("postgres_plain");
  
  // Connect using provided info
  const client = new PostgresClient({
    host: pg.host,
    port: pg.ports[5432],  // Mapped to random available port
  });
});
```

## Testing

All affected test suites have been run and verified:
- `bun test test/js/sql/sql.test.ts` 
- `bun test test/js/sql/sql-mysql*.test.ts` 
- `bun test test/js/bun/s3/s3.test.ts` 
- `bun test test/js/valkey/valkey.test.ts` 
- `bun test test/js/web/websocket/autobahn.test.ts` 

## Documentation

Comprehensive documentation added in `test/docker/README.md` including:
- Detailed explanation of Docker Compose for beginners
- Architecture overview
- Usage examples
- Debugging guide
- Migration guide for adding new services

## Notes

- The Redis reconnection test that's skipped was already broken before
this migration. It's a pre-existing issue with the Redis client's
reconnection logic, not related to Docker changes.
- All tests that were passing before continue to pass after migration.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <claude@anthropic.ai>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
2025-09-19 04:20:58 -07:00
Ciro Spaciari
d85207f179 fix(Bun.SQL) fix MySQL execution on windows (#22696)
### What does this PR do?
Fixes https://github.com/oven-sh/bun/issues/22695
Fixes https://github.com/oven-sh/bun/issues/22654

### How did you verify your code works?
Added mysql:9 + run mysql tests on windows

<img width="1035" height="708"
alt="489727987-3cca2da4-0ff8-4b4a-b5be-9fbdd1c9862d"
src="https://github.com/user-attachments/assets/02c6880d-547e-43b5-8af8-0b7c895c6166"
/>
2025-09-17 08:46:23 -07:00
Ciro Spaciari
beea7180f3 refactor(MySQL) (#22619)
### What does this PR do?

### How did you verify your code works?

---------

Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-09-13 14:52:19 -07:00
Ciro Spaciari
1e4935cf3e fix(Bun.SQL) fix postgres error handling when pipelining and state reset (#22505)
### What does this PR do?
Fixes: https://github.com/oven-sh/bun/issues/22395

### How did you verify your code works?
Test
2025-09-08 21:00:39 -07:00
Alistair Smith
e63608fced Fix: Make SQL connection string parsing more sensible (#22260)
This PR makes connection string parsing more sensible in Bun.SQL,
without breaking the default fallback of postgres

Added some tests checking for connection string precedence

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Ciro Spaciari <ciro.spaciari@gmail.com>
2025-09-08 20:59:24 -07:00
Ciro Spaciari
b79bbfe289 fix(Bun.SQL) fix SSLRequest (#22378)
### What does this PR do?
Fixes https://github.com/oven-sh/bun/issues/22312
Fixes https://github.com/oven-sh/bun/issues/22313

The correct flow for TLS handshaking is:

Server sending
[Protocol::Handshake](https://dev.mysql.com/doc/dev/mysql-server/8.4.5/page_protocol_connection_phase_packets_protocol_handshake.html)
Client replying with
[Protocol::SSLRequest:](https://dev.mysql.com/doc/dev/mysql-server/8.4.5/page_protocol_connection_phase_packets_protocol_ssl_request.html)
The usual SSL exchange leading to establishing SSL connection
Client sends
[Protocol::HandshakeResponse:](https://dev.mysql.com/doc/dev/mysql-server/8.4.5/page_protocol_connection_phase_packets_protocol_handshake_response.html)

<img width="460" height="305" alt="Screenshot 2025-09-03 at 15 02 25"
src="https://github.com/user-attachments/assets/091bbc54-75bc-44ac-98b8-5996e8d69ed8"
/>

Source:
https://dev.mysql.com/doc/dev/mysql-server/8.4.5/page_protocol_connection_phase.html

### How did you verify your code works?
Tests

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-09-03 18:59:15 -07:00
Ciro Spaciari
60ab798991 fix(Bun.SQL) fix timers test and disable describeWithContainer on macos (#22382)
### What does this PR do?
Actually run the Timer/TimerZ tests in CI and disable
describeWithContainer in macos
### How did you verify your code works?
CI

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-09-03 17:36:03 -07:00
Jarred Sumner
de7c947161 bump webkit (#22256)
### What does this PR do?

### How did you verify your code works?

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
2025-09-01 16:20:13 -07:00
Jarred Sumner
c8e3a91602 Revert "Update sql-mysql.helpers.test.ts"
This reverts commit 559c95ee2c.
2025-08-30 23:08:37 -07:00
Jarred Sumner
559c95ee2c Update sql-mysql.helpers.test.ts 2025-08-30 21:48:26 -07:00
Ciro Spaciari
a34e10db53 fix(Bun.SQL) handle MySQL Int24 (#22241)
### What does this PR do?
handle Int24 to be numbers
### How did you verify your code works?
tests

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-08-29 17:03:26 -07:00
Ciro Spaciari
1085908386 fix(Bun.SQL) MYSQL fix old auth and auth switch + add lastInsertRowid and affectedRows (#22132)
### What does this PR do?

add `lastInsertRowid` (matching SQLite)
add `affectedRows`
fix `mysql_native_password` deprecated authentication
fix AuthSwitch
Fixes:
https://github.com/oven-sh/bun/issues/22178#issuecomment-3228716080
### How did you verify your code works?
tests

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-08-29 01:03:17 -07:00
Ciro Spaciari
a56488f221 fix(Bun.SQL) handle better BIT(1) in MySQL (#22224)
### What does this PR do?
Fix handling BIT(1) and BIT(N) on binary protocol and text protocol, now
behavior is consistent
### How did you verify your code works?
Tests
2025-08-28 19:14:53 -07:00
Ciro Spaciari
196182f8ec fix(Bun.SQL) fix MySQL by not converting tinyint to bool (#22159)
### What does this PR do?
Change tinyint/bool type from mysql to number instead of bool to match
mariadb and mysql2 behavior since tinyint/bool can be bigger than 1 in
mysql
Fixes https://github.com/oven-sh/bun/issues/22158
### How did you verify your code works?
Test

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-08-26 17:58:08 -07:00
Carl Jackson
92b38fdf80 sql: support array of strings in SQLHelper (#21572)
### What does this PR do?
Support the following:
```javascript
const nom = await sql`SELECT name FROM food WHERE category IN ${sql(['bun', 'baozi', 'xiaolongbao'])}`;
```

Previously, only e.g., `sql([1, 2, 3])` was supported.

To be honest I'm not sure what the semantics of SQLHelper *ought* to be.
I'm pretty sure objects ought to be auto-inferred. I'm not sure about
arrays, but given the rest of the code in `SQLHelper` trying to read the
tea leaves on stringified numeric keys I figured someone cared about
this use case. I don't know about other types, but I'm pretty sure that
`Object.keys("bun") === [0, 1, 2]` is an oversight and unintended.
(Incidentally, the reason numbers previously worked is because
`Object.keys(4) === []`). I decided that all non-objects and non-arrays
should be treated as not having auto-inferred columns.

Fixes #18637 

### How did you verify your code works?
I wrote a test, but was unable to run it (or any other tests in this
file) locally due to Docker struggles. I sure hope it works!
2025-08-22 17:05:05 -07:00
Jarred Sumner
0e37dc4e78 Fixes #20729 (#22048)
### What does this PR do?

Fixes #20729

### How did you verify your code works?

There is a test

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-08-22 03:41:49 -07:00
Ciro Spaciari
ecbf103bf5 feat(MYSQL) Bun.SQL mysql support (#21968)
### What does this PR do?
Add MySQL support, Refactor will be in a followup PR
### How did you verify your code works?
A lot of tests

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: cirospaciari <6379399+cirospaciari@users.noreply.github.com>
2025-08-21 15:28:15 -07:00
Alistair Smith
784271f85e SQLite in Bun.sql (#21640)
### What does this PR do?

Support sqlite in the Bun.sql API

Fixes #18951
Fixes #19701

### How did you verify your code works?

tests

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
2025-08-19 23:15:53 -07:00
Ciro Spaciari
504052d9b0 fix(test) fix sql.test.ts (#21860)
### What does this PR do?
fix test to not include information that can change version to version
### How did you verify your code works?
CI
2025-08-14 12:25:16 -07:00
Alistair Smith
04883a8bdc revert fe28e00d53.
This reverts commit fe28e00d53.
2025-08-05 16:10:29 -07:00
Alistair Smith
fe28e00d53 feat: add Bun.SQL API with initial SQLite support 2025-08-05 16:04:11 -07:00
Ciro Spaciari
258a2a2e3a fix(postgres) memory fix when connection fails sync (#21616)
### What does this PR do?
We should not call .deinit() after .toJS otherwise hasPendingActivity
will access invalid memory

### How did you verify your code works?
Test run it with debug build on macos or asan on and will catch it

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-08-04 19:41:20 -07:00
Jarred Sumner
39eccf89a8 Deflake sql.test.ts 2025-08-01 22:41:05 -07:00
Ciro Spaciari
03afe6ef28 fix(postgres) regression (#21466)
### What does this PR do?
Fix: https://github.com/oven-sh/bun/issues/21351

Relevant changes:
Fix advance to properly cleanup success and failed queries that could be
still be in the queue
Always ref before executing
Use stronger atomics for ref/deref and hasPendingActivity
Fallback when thisValue is freed/null/zero and check if vm is being
shutdown
The bug in --hot in `resolveRopeIfNeeded` Issue is not meant to be fixed
in this PR this is a fix for the postgres regression
Added assertions so this bug is easier to catch on CI
### How did you verify your code works?
Test added

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-07-31 16:26:35 -07:00
Meghan Denny
cc4f840e8b test: remove accidental uses of test.only (#20097) 2025-07-16 23:07:23 -07:00
Alistair Smith
19a855e02b types: Introduce SQL.Helper in Bun.sql (#20809)
Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
2025-07-07 17:47:51 -07:00
Jarred Sumner
14b439a115 Fix formatters not running in CI + delete unnecessary files (#19433) 2025-05-08 23:22:16 -07:00
190n
71c770f3ae fix sql.test.ts (#19544) 2025-05-08 18:51:32 -07:00
Ciro Spaciari
a512ad5155 fix(sql) fix flush (#19177) 2025-04-21 22:21:55 -07:00
Ciro Spaciari
7f948f9c3e fix(sql) fix query parameters options (#18194) 2025-03-14 13:39:55 -07:00
Ciro Spaciari
caff4e6008 fix(sql) fix SQL fragments handling and expand support for helpers (#17691) 2025-02-25 19:46:53 -08:00
Ciro Spaciari
09ab840114 fix(sql) fix binary detection + fix custom types (#17635) 2025-02-24 20:07:16 -08:00