Commit Graph

2330 Commits

Author SHA1 Message Date
robobun
46e7a3b3c5 Implement birthtime support on Linux using statx syscall (#23209)
## Summary

- Adds birthtime (file creation time) support on Linux using the `statx`
syscall
- Stores birthtime in architecture-specific unused fields of the kernel
Stat struct (x86_64 and aarch64)
- Falls back to traditional `stat` on kernels < 4.11 that don't support
`statx`
- Includes comprehensive tests validating birthtime behavior

Fixes #6585

## Implementation Details

**src/sys.zig:**
- Added `StatxField` enum for field selection
- Implemented `statxImpl()`, `fstatx()`, `statx()`, and `lstatx()`
functions
- Stores birthtime in unused padding fields (architecture-specific for
x86_64 and aarch64)
- Graceful fallback to traditional stat if statx is not supported

**src/bun.js/node/node_fs.zig:**
- Updated `stat()`, `fstat()`, and `lstat()` to use statx functions on
Linux

**src/bun.js/node/Stat.zig:**
- Added `getBirthtime()` helper to extract birthtime from
architecture-specific storage

**test/js/node/fs/fs-birthtime-linux.test.ts:**
- Tests non-zero birthtime values
- Verifies birthtime immutability across file modifications
- Validates consistency across stat/lstat/fstat
- Tests BigInt stats with nanosecond precision
- Verifies birthtime ordering relative to other timestamps

## Test Plan

- [x] Run `bun bd test test/js/node/fs/fs-birthtime-linux.test.ts` - all
5 tests pass
- [x] Compare behavior with Node.js - identical behavior
- [x] Compare with system Bun - system Bun returns epoch, new
implementation returns real birthtime

🤖 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>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-10-04 04:57:29 -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
pfg
f1204ea2fd bun test dots reporter (#22919)
Adds a simple dots reporter for bun test

<img width="911" height="323" alt="image"
src="https://github.com/user-attachments/assets/45cfe7c8-dc8c-47d6-84dc-e1e0232a0633"
/>

---------

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>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
2025-10-03 17:13:22 -07:00
taylor.fish
f14f3b03bb Add new bindings generator; port SSLConfig (#23169)
Add a new generator for JS → Zig bindings. The bulk of the conversion is
done in C++, after which the data is transformed into an FFI-safe
representation, passed to Zig, and then finally transformed into
idiomatic Zig types.

In its current form, the new bindings generator supports:

* Signed and unsigned integers
* Floats (plus a “finite” variant that disallows NaN and infinities)
* Strings
* ArrayBuffer (accepts ArrayBuffer, TypedArray, or DataView)
* Blob
* Optional types
* Nullable types (allows null, whereas Optional only allows undefined)
* Arrays
* User-defined string enumerations
* User-defined unions (fields can optionally be named to provide a
better experience in Zig)
* Null and undefined, for use in unions (can more efficiently represent
optional/nullable unions than wrapping a union in an optional)
* User-defined dictionaries (arbitrary key-value pairs; expects a JS
object and parses it into a struct)
* Default values for dictionary members
* Alternative names for dictionary members (e.g., to support both
`serverName` and `servername` without taking up twice the space)
* Descriptive error messages
* Automatic `fromJS` functions in Zig for dictionaries
* Automatic `deinit` functions for the generated Zig types

Although this bindings generator has many features not present in
`bindgen.ts`, it does not yet implement all of `bindgen.ts`'s
functionality, so for the time being, it has been named `bindgenv2`, and
its configuration is specified in `.bindv2.ts` files. Once all
`bindgen.ts`'s functionality has been incorporated, it will be renamed.

This PR ports `SSLConfig` to use the new bindings generator; see
`SSLConfig.bindv2.ts`.

(For internal tracking: fixes STAB-1319, STAB-1322, STAB-1323,
STAB-1324)

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Alistair Smith <hi@alistair.sh>
2025-10-03 17:10:28 -07:00
robobun
a9b383bac5 fix(crypto): hkdf callback should pass null (not undefined) on success (#23216)
## Summary
- Fixed crypto.hkdf callback to pass `null` instead of `undefined` for
the error parameter on success
- Added regression test to verify the fix

## Details

Fixes #23211

Node.js convention requires crypto callbacks to receive `null` as the
error parameter on success, but Bun was passing `undefined`. This caused
compatibility issues with code that relies on strict null checks (e.g.,
[matter.js](fdbec2cf88/packages/general/src/crypto/NodeJsStyleCrypto.ts (L169))).

### Changes
- Updated `CryptoHkdf.cpp` to pass `jsNull()` instead of `jsUndefined()`
for the error parameter in the success callback
- Added regression test in `test/regression/issue/23211.test.ts`

## Test plan
- [x] Added regression test that verifies callback receives `null` on
success
- [x] Test passes with the fix
- [x] Ran existing crypto tests (no failures)

🤖 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>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Dylan Conway <dylan.conway567@gmail.com>
2025-10-03 15:55:57 -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
84f94ca6dd fix(Bun.RedisClient) keep it alive when connecting (#23195)
### What does this PR do?
Fixes https://github.com/oven-sh/bun/issues/23178
Fixes https://github.com/oven-sh/bun/issues/23187
Fixes https://github.com/oven-sh/bun/issues/23198
### 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 18:50:05 -07:00
Ciro Spaciari
4a86d070cf revert 6ab3d93 2025-10-02 15:53:19 -07:00
Ciro Spaciari
6ab3d931c9 opsie 2025-10-02 15:50:58 -07:00
Ciro Spaciari
76545140af fix(node:http) fix closing socket after upgraded to websocket (#23150)
### What does this PR do?
handle socket upgrade in NodeHTTP.cpp
### How did you verify your code works?
Run the test added with asan it should catch the bug

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-10-02 14:55:28 -07:00
pfg
9e6ba35ff7 Allow multiple inline snapshots in one call if they are the same (#23117)
Multiple inline snapshots from one call should be avoided because they
will cause problems if one changes but not the other, but this allows
them if they both have the same value.

### What does this PR do?

bad:

```ts
function oops(a) {
  expect(a).toMatchInlineSnapshot();
}
test("whoops", () => {
  oops(1);
  oops(2);
});
```

```
2 |   expect(a).toMatchInlineSnapshot();
                                      ^
error: Failed to update inline snapshot: Multiple inline snapshots on the same line must all have the same value:
Expected: 1
Received: 2
    at /Users/pfg/Dev/Node/bun/repro.ts:2:35
```

acceptable:

```ts
function ok(a) {
  expect(a).toMatchInlineSnapshot(`1`);
}
test("whokay", () => {
  ok(1);
  ok(1);
});
```

```
✓ whokay

 1 pass
 0 fail
 snapshots: +1 added
 2 expect() calls
```

### How did you verify your code works?

TODO: add tests

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-10-01 12:09:26 -07:00
pfg
613aea1787 run beforeAll before the first file and afterAll after the last file (#23113)
Fixes #23066

Reverts the breaking change to this order made in #22534
2025-09-30 21:47:31 -07:00
pfg
1fb9be3880 Re-enable afterAll inside a test (#23110)
Fixes #23064, Fixes #23077

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
2025-09-30 19:41:35 -07:00
Meghan Denny
f19a1cc3a5 test: break up node-http.test.ts (#23125) 2025-09-30 17:25:17 -07:00
Alistair Smith
b613790451 Many more Redis commands (#23116) 2025-09-30 13:27:25 -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
robobun
621066d0c4 Fix crash in toContainAnyKeys and toContainKeys with non-object values (#22977)
## Summary
- Fixed segmentation fault when calling `toContainAnyKeys`,
`toContainKeys`, and `toContainAllKeys` on non-object values (null,
undefined, numbers, strings, etc.)
- Added proper validation to check if value is an object before calling
`hasOwnPropertyValue` or `keys()`
- Added comprehensive test coverage for edge cases

## Problem
The matchers were crashing with a segmentation fault when called with
non-object values because:

1. `toContainAnyKeys` and `toContainKeys` were calling
`hasOwnPropertyValue` without checking if the value is an object first
2. `toContainAllKeys` was calling `keys()` without checking if the value
is an object first
3. The `hasOwnPropertyValue` function documentation explicitly states:
"If the object is not an object, it will crash. **You must check if the
object is an object before calling this function.**"

## Solution
- Added `value.isObject()` check in `toContainAnyKeys` before attempting
to check for properties
- Fixed `toContainKeys` by replacing the `toBoolean()` check with
`isObject()` check
- Fixed `toContainAllKeys` by adding proper object validation before
calling `keys()`
- For non-objects with empty expected arrays, the matchers return true
(matching jest-extended behavior)

## Test plan
- [x] Added comprehensive test coverage in
`test/js/bun/test/expect.test.js`
- [x] Tests cover: null, undefined, numbers, strings, booleans, symbols,
BigInt, arrays, functions
- [x] All existing jest-extended tests continue to pass
- [x] Debug build compiles and all tests pass

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

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Dylan Conway <dylan.conway567@gmail.com>
2025-09-29 16:10:56 -07:00
Dylan Conway
f6e722b594 fix(glob): fix index out of bounds in GlobWalker (#23055)
### What does this PR do?
Given pattern input "../." we might collapse all path components.
### How did you verify your code works?
Manually and added a test.

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-09-29 02:21:13 -07:00
Jarred Sumner
d9fdb67d70 Deflake bun-server.test.ts 2025-09-28 23:58:21 -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
Meghan Denny
8c9c7894d6 update handle-leak.test.ts
observed higher values under load on windows
will audit again once more memory work has been completed
2025-09-27 00:27:23 -07:00
Jarred Sumner
665ea96076 Deflake test/js/bun/http/bun-server.test.ts 2025-09-26 19:22:07 -07:00
Jarred Sumner
733e7f6165 Fix fetch-preconnect test failure (#23016)
### What does this PR do?

### How did you verify your code works?
2025-09-26 19:01:01 -07:00
Ciro Spaciari
d3ce459f0e fix(valkey/redis) fix tls (includes pub/sub) (#22981)
### What does this PR do?
Fix tls property not being properly set
Fixes https://github.com/oven-sh/bun/issues/22186
### How did you verify your code works?
Tests + Manually test with upstash using `rediss` protocol and tls: true
options

---------

Co-authored-by: Marko Vejnovic <marko.vejnovic@hotmail.com>
Co-authored-by: Marko Vejnovic <marko@bun.com>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-09-26 18:57:06 -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
Marko Vejnovic
17b503b389 Redis PUB/SUB 2.0 (#22568)
### What does this PR do?

**This PR is created because [the previous PR I
opened](https://github.com/oven-sh/bun/pull/21728) had some concerning
issues.** Thanks @Jarred-Sumner for the help.

The goal of this PR is to introduce PUB/SUB functionality to the
built-in Redis client. Based on the fact that the current Redis API does
not appear to have compatibility with `io-redis` or `redis-node`, I've
decided to do away with existing APIs and API compatibility with these
existing libraries.

I have decided to base my implementation on the [`redis-node` pub/sub
API](https://github.com/redis/node-redis/blob/master/docs/pub-sub.md).

#### Random Things That Happened

- [x] Refactored the build scripts so that `valgrind` can be disabled.
- [x] Added a `numeric` namespace in `harness.ts` with useful
mathematical libraries.
- [x] Added a mechanism in `cppbind.ts` to disable static assertions
(specifically to allow `check_slow` even when returning a `JSValue`).
Implemented via `// NOLINT[NEXTLINE]?\(.*\)` macros.
- [x] Fixed inconsistencies in error handling of `JSMap`.

### How did you verify your code works?

I've written a set of unit tests to hopefully catch the major use-cases
of this feature. They all appear to pass.


#### Future Improvements

I would have a lot more confidence in our Redis implementation if we
tested it with a test suite running over a network which emulates a high
network failure rate. There are large amounts of edge cases that are
worthwhile to grab, but I think we can roll that out in a future PR.

### Future Tasks

- [ ] Tests over flaky network
- [ ] Use the custom private members over `_<member>`.

---------

Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
2025-09-26 03:06:18 -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
Jarred Sumner
9746d03ccb Delete slop test 2025-09-25 16:24:24 -07:00
Jarred Sumner
4dfd87a302 Fix aborting fetch() calls while the socket is connecting. Fix a thread-safety issue involving redirects and AbortSignal. (#22842)
### What does this PR do?

When we added "happy eyeballs" support to fetch(), it meant that
`onOpen` would not be called potentially for awhile. If the AbortSignal
is aborted between `connect()` and the socket becoming
readable/writable, then we would delay closing the connection until the
connection opens. Fixing that fixes #18536.

Separately, the `isHTTPS()` function used in abort and in request body
streams was not thread safe. This caused a crash when many redirects
happen simultaneously while either AbortSignal or request body messages
are in-flight.
This PR fixes https://github.com/oven-sh/bun/issues/14137



### How did you verify your code works?

There are tests

---------

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: Ciro Spaciari <ciro.spaciari@gmail.com>
2025-09-25 16:08:06 -07:00
Meghan Denny
20854fb285 node:crypto: add blake2s256 hasher (#22958) 2025-09-25 15:28:42 -07:00
pfg
0ea4ce1bb4 Synchronous concurrent test fix (#22928)
```ts
beforeEach(() => {
  console.log("beforeEach");
});
afterEach(() => {
  console.log("afterEach");
});
test.concurrent("test 1", () => {
  console.log("start test 1");
});
test.concurrent("test 2", async () => {
  console.log("start test 2");
});
test.concurrent("test 3", () => {
  console.log("start test 3");
});
```

```
$> bun-before test synchronous-concurrent
beforeEach
beforeEach
beforeEach
start test 1
start test 2
start test 3
afterEach
afterEach
afterEach

$> bun-after test synchronous-concurrent
beforeEach
start test 1
afterEach
beforeEach
start test 2
afterEach
beforeEach
start test 3
afterEach
```

---------

Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
2025-09-25 03:52:18 -07:00
Ciro Spaciari
7798e6638b Implement NODE_USE_SYSTEM_CA with --use-system-ca CLI flag (#22441)
### What does this PR do?
Resume work on https://github.com/oven-sh/bun/pull/21898
### How did you verify your code works?
Manually tested on MacOS, Windows 11 and Ubuntu 25.04. CI changes are
needed for the tests

---------

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: Jarred Sumner <jarred@jarredsumner.com>
2025-09-24 21:55:57 -07:00
Marko Vejnovic
e3783c244f chore(libuv): Update to 1.51.0 (#22942)
### What does this PR do?

Uprevs `libuv` to version `1.51.0`.

### How did you verify your code works?

CI passes.

---------

Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
2025-09-24 20:55:25 -07:00
robobun
fcd628424a Fix YAML.parse to throw SyntaxError instead of BuildMessage (#22924)
YAML.parse now throws SyntaxError for invalid syntax matching JSON.parse
behavior

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Dylan Conway <dylan.conway567@gmail.com>
2025-09-24 16:29:05 -07:00
pfg
526686fdc9 Prevent test.only and snapshot updates in CI (#21811)
This is feature flagged and will not activate until Bun 1.3

- Makes `test.only()` throw an error in CI
- Unless `--update-snapshots` is passed:
- Makes `expect.toMatchSnapshot()` throw an error instead of adding a
new snapshot in CI
- Makes `expect.toMatchInlineSnapshot()` throw an error instead of
filling in the snapshot value in 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-24 15:19:16 -07:00
pfg
95b18582ec Revert "concurrent limit"
This reverts commit 4252a6df31.
2025-09-24 15:09:20 -07:00
pfg
4252a6df31 concurrent limit 2025-09-24 15:08:36 -07:00
Meghan Denny
92bc522e85 lsan: fix reporting on linux ci (#22806) 2025-09-24 00:47:52 -07:00
Meghan Denny
ebe2e9da14 node:net: fix handle leak (#22913) 2025-09-23 22:02:34 -07:00
robobun
1a23797e82 feat: add test.serial() API for forcing serial test execution (#22899)
## Summary

Adds a new `test.serial()` API that forces tests to run serially even
when the `--concurrent` flag is passed. This is the opposite of
`test.concurrent()` which forces parallel execution.

## Motivation

Some tests genuinely need to run serially even in CI environments with
`--concurrent`:
- Database migration tests that must run in order
- Tests that modify shared global state
- Tests that use fixed ports or file system resources
- Tests that depend on timing or resource constraints

## Implementation

Changed `self_concurrent` from `bool` to `?bool`:
- `null` = default behavior (inherit from parent or use default)
- `true` = force concurrent execution
- `false` = force serial execution

## API Surface

```javascript
// Force serial execution
test.serial("database migration", async () => {
  // This runs serially even with --concurrent flag
});

// All modifiers work
test.serial.skip("skip this serial test", () => {});
test.serial.todo("implement this serial test");
test.serial.only("only run this serial test", () => {});
test.serial.each([[1], [2]])("serial test %i", (n) => {});
test.serial.if(condition)("conditional serial", () => {});

// Works with describe too
describe.serial("serial test suite", () => {
  test("test 1", () => {}); // runs serially
  test("test 2", () => {}); // runs serially
});

// Explicit test-level settings override describe-level
describe.concurrent("concurrent suite", () => {
  test.serial("this runs serially", () => {}); // serial wins
  test("this runs concurrently", () => {});
});
```

## Test Coverage

Comprehensive tests added including:
- Basic `test.serial()` functionality
- All modifiers (skip, todo, only, each, if)
- `describe.serial()` blocks
- Mixing serial and concurrent tests in same describe block
- Nested describe blocks with conflicting settings
- Explicit overrides (test.serial in describe.concurrent and vice versa)

All 36 tests pass 

## Example

```javascript
// Without this PR - these tests might run in parallel with --concurrent
test("migrate database schema v1", async () => { await migrateV1(); });
test("migrate database schema v2", async () => { await migrateV2(); });
test("migrate database schema v3", async () => { await migrateV3(); });

// With this PR - guaranteed serial execution
test.serial("migrate database schema v1", async () => { await migrateV1(); });
test.serial("migrate database schema v2", async () => { await migrateV2(); });
test.serial("migrate database schema v3", async () => { await migrateV3(); });
```

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

---------

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-23 21:06:06 -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
Ciro Spaciari
85271f9dd9 fix(node:http) allow CONNECT in node http/https servers (#22756)
### What does this PR do?
Fixes https://github.com/oven-sh/bun/issues/22755
Fixes https://github.com/oven-sh/bun/issues/19790
Fixes https://github.com/oven-sh/bun/issues/16372
### How did you verify your code works?

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-09-23 16:46:59 -07:00
Don Isaac
beae53e81b fix(test): add EXPECTED_COLOR and RECEIVED_COLOR aliases (#22862)
### What does this PR do?
This PR does two things.

First, it fixes a bug when using
[`jest-dom`](https://github.com/testing-library/jest-dom) where
expectation failures would break as `RECEIVED_COLOR` and
`EXPECTED_COLOR` are not properties of `ExpectMatcherContext`.
<img width="1216" height="139" alt="image"
src="https://github.com/user-attachments/assets/26ef87c2-f763-4a46-83a3-d96c4c534f3d"
/>

Second, it adds some existing timer mock functions that were missing
from the `vi` object.

### How did you verify your code works?

I've added a test.
2025-09-22 18:43:28 -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
Meghan Denny
45760cd53c ci: instrument being able to run leaksanitizer (#21142)
tests not in `test/no-validate-leaksan.txt` will run with leaksanitizer
in CI
leaks documented in `test/leaksan.supp` will not cause a test failure

-- notes about leaksanitizer

- will not catch garbage collected objects accumulated during
long-running processes
- will not catch js objects (eg a strong held to a promise)
- will catch native calls to `malloc` not `free`d
- will catch allocations made in C, Zig, C++, libc, dependencies,
dlopen'd

---------

Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
2025-09-19 02:06:02 -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
robobun
661deb8eaf Fix MessagePort communication after transfer to Worker (#22638)
## Summary

Fixes #22635 - MessagePort communication fails after being transferred
to a Worker thread.
Fixes https://github.com/oven-sh/bun/issues/22636

The issue was that `MessagePort::addEventListener()` only called
`start()` for attribute listeners (like `onmessage = ...`) but not for
regular event listeners added via `addEventListener()` or the Node.js
EventEmitter wrapper (`.on('message', ...)`).

## Changes

- Modified `MessagePort::addEventListener()` to call `start()` for all
message event listeners, not just attribute listeners
- Added regression test for issue #22635

## Test Plan

- [x] Regression test added and passing
- [x] Original reproduction case from issue #22635 now works correctly
- [x] Existing MessagePort tests still pass

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

---------

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: Jarred Sumner <jarred@jarredsumner.com>
2025-09-17 03:33:14 -07:00