Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 19 additions & 8 deletions test/js/bun/http/bun-server.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3181,11 +3181,25 @@ describe("handler GC tracing (heapStats wrapper-count)", () => {
const echoed = Promise.withResolvers();
const closed = Promise.withResolvers();

// Scope server so the only post-stop root is the connected websocket.
// Assign client directly to the outer var rather than returning it —
// returning keeps the async frame's scope (which contains server)
// alive via the resolved-value chain in JSC.
// The client and its handlers are created here, outside the scope that
// holds server. The client's close handler is the last function native
// code calls before the measurement below, and a pointer to it stays on
// the native stack (conservatively scanned) for a while. Had it been
// created next to server, it would share server's scope and keep the
// server alive through that stale pointer, which is not what this test
// measures.
let client;
function connect(url) {
client = new WebSocket(url);
client.onopen = () => clientOpen.resolve();
client.onmessage = e => echoed.resolve(e.data);
client.onclose = () => closed.resolve();
}

// Scope server so the only post-stop root is the connected websocket.
// Nothing is returned from the arrow: a returned value would keep the
// async frame's scope (which contains server) alive via the
// resolved-value chain in JSC.
await (async () => {
const server = Bun.serve({
port: 0,
Expand All @@ -3197,10 +3211,7 @@ describe("handler GC tracing (heapStats wrapper-count)", () => {
message(ws, m) { ws.send(server.port + ":" + m); },
},
});
client = new WebSocket(server.url.href.replace("http", "ws"));
client.onopen = () => clientOpen.resolve();
client.onmessage = e => echoed.resolve(e.data);
client.onclose = () => closed.resolve();
connect(server.url.href.replace("http", "ws"));
await opened.promise; // server-side ws created (roots wrapper)
await clientOpen.promise; // client ready to send (avoid InvalidStateError)
server.stop(); // graceful — listener gone, ws stays
Expand Down