mirror of
https://github.com/oven-sh/bun
synced 2026-02-02 15:08:46 +00:00
test(net): use await using and AbortSignal for disposal/timeouts
Address additional CodeRabbit review feedback: - Use `await using` for automatic server disposal instead of try/finally - Use `once()` from node:events for cleaner event waiting - Replace setTimeout-based timeout with AbortSignal.timeout() - Simplify helper functions Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,12 +1,14 @@
|
||||
import { describe, it } from "bun:test";
|
||||
import { connect, createServer, Server, Socket } from "node:net";
|
||||
import { once } from "node:events";
|
||||
import type { AddressInfo } from "node:net";
|
||||
import { connect, createServer, Socket } from "node:net";
|
||||
import { Duplex, Writable } from "node:stream";
|
||||
|
||||
describe("issue/026418", () => {
|
||||
it("net.Socket data events fire when socket is piped to another stream", async () => {
|
||||
const { promise: dataPromise, resolve: dataResolve } = Promise.withResolvers<void>();
|
||||
|
||||
const server = createServer((socket: Socket) => {
|
||||
await using server = createServer((socket: Socket) => {
|
||||
socket.on("data", () => {
|
||||
dataResolve();
|
||||
});
|
||||
@@ -19,24 +21,20 @@ describe("issue/026418", () => {
|
||||
socket.pipe(writable);
|
||||
});
|
||||
|
||||
try {
|
||||
const port = await listenOnRandomPort(server);
|
||||
const client = connect({ host: "127.0.0.1", port });
|
||||
await once(server.listen(0, "127.0.0.1"), "listening");
|
||||
const { port } = server.address() as AddressInfo;
|
||||
|
||||
try {
|
||||
await waitForConnect(client);
|
||||
const client = connect({ host: "127.0.0.1", port });
|
||||
|
||||
// Send data
|
||||
client.write("HELLO");
|
||||
await once(client, "connect");
|
||||
|
||||
// Wait for data to be received with timeout
|
||||
await Promise.race([dataPromise, rejectAfterTimeout(1000, "data event not received")]);
|
||||
} finally {
|
||||
client.destroy();
|
||||
}
|
||||
} finally {
|
||||
await closeServer(server);
|
||||
}
|
||||
// Send data
|
||||
client.write("HELLO");
|
||||
|
||||
// Wait for data to be received with AbortSignal timeout
|
||||
await Promise.race([dataPromise, abortAfterTimeout(1000, "data event not received")]);
|
||||
|
||||
client.destroy();
|
||||
});
|
||||
|
||||
it("net.Socket bidirectional pipe works (SSH tunnel pattern)", async () => {
|
||||
@@ -58,7 +56,7 @@ describe("issue/026418", () => {
|
||||
});
|
||||
}
|
||||
|
||||
const server = createServer((socket: Socket) => {
|
||||
await using server = createServer((socket: Socket) => {
|
||||
socket.on("data", () => {
|
||||
dataResolve();
|
||||
});
|
||||
@@ -72,70 +70,41 @@ describe("issue/026418", () => {
|
||||
});
|
||||
});
|
||||
|
||||
try {
|
||||
const port = await listenOnRandomPort(server);
|
||||
const client = connect({ host: "127.0.0.1", port });
|
||||
await once(server.listen(0, "127.0.0.1"), "listening");
|
||||
const { port } = server.address() as AddressInfo;
|
||||
|
||||
try {
|
||||
await waitForConnect(client);
|
||||
const client = connect({ host: "127.0.0.1", port });
|
||||
|
||||
client.on("data", (chunk: Buffer) => {
|
||||
if (chunk.toString().includes("RESPONSE:")) {
|
||||
responseResolve();
|
||||
}
|
||||
});
|
||||
await once(client, "connect");
|
||||
|
||||
// Wait for forward stream to be set up
|
||||
await Promise.race([pipeReadyPromise, rejectAfterTimeout(1000, "pipe setup timeout")]);
|
||||
|
||||
// Send data
|
||||
client.write("REQUEST");
|
||||
|
||||
// Wait for data and response with timeout
|
||||
await Promise.race([
|
||||
Promise.all([dataPromise, responsePromise]),
|
||||
rejectAfterTimeout(1000, "data/response not received"),
|
||||
]);
|
||||
} finally {
|
||||
client.destroy();
|
||||
client.on("data", (chunk: Buffer) => {
|
||||
if (chunk.toString().includes("RESPONSE:")) {
|
||||
responseResolve();
|
||||
}
|
||||
} finally {
|
||||
await closeServer(server);
|
||||
}
|
||||
});
|
||||
|
||||
// Wait for forward stream to be set up
|
||||
await Promise.race([pipeReadyPromise, abortAfterTimeout(1000, "pipe setup timeout")]);
|
||||
|
||||
// Send data
|
||||
client.write("REQUEST");
|
||||
|
||||
// Wait for data and response with timeout
|
||||
await Promise.race([
|
||||
Promise.all([dataPromise, responsePromise]),
|
||||
abortAfterTimeout(1000, "data/response not received"),
|
||||
]);
|
||||
|
||||
client.destroy();
|
||||
});
|
||||
});
|
||||
|
||||
// Helper functions
|
||||
|
||||
function listenOnRandomPort(server: Server): Promise<number> {
|
||||
return new Promise((resolve, reject) => {
|
||||
server.on("error", reject);
|
||||
server.listen(0, "127.0.0.1", () => {
|
||||
const addr = server.address();
|
||||
if (addr && typeof addr === "object") {
|
||||
resolve(addr.port);
|
||||
} else {
|
||||
reject(new Error("Failed to get server port"));
|
||||
}
|
||||
// Helper to create a promise that rejects after timeout using AbortSignal
|
||||
function abortAfterTimeout(ms: number, message: string): Promise<never> {
|
||||
const signal = AbortSignal.timeout(ms);
|
||||
return new Promise((_, reject) => {
|
||||
signal.addEventListener("abort", () => {
|
||||
reject(new Error(message));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function waitForConnect(client: Socket): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
client.on("connect", resolve);
|
||||
client.on("error", reject);
|
||||
});
|
||||
}
|
||||
|
||||
function closeServer(server: Server): Promise<void> {
|
||||
return new Promise(resolve => {
|
||||
server.close(() => resolve());
|
||||
});
|
||||
}
|
||||
|
||||
function rejectAfterTimeout(ms: number, message: string): Promise<never> {
|
||||
return new Promise((_, reject) => {
|
||||
setTimeout(() => reject(new Error(message)), ms);
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user