aboutsummaryrefslogtreecommitdiff
path: root/test/js/node/net/node-net-server.test.ts
diff options
context:
space:
mode:
authorGravatar Ciro Spaciari <ciro.spaciari@gmail.com> 2023-03-13 20:42:35 -0300
committerGravatar GitHub <noreply@github.com> 2023-03-13 16:42:35 -0700
commitac9f8c0e93b6b91096a6dc8782f09a08c2e4f6c8 (patch)
tree9f710fcd00a4c2987212ab961bd57e67c0c60729 /test/js/node/net/node-net-server.test.ts
parent8d320d137393d88ada6961dc0781de9054a0c453 (diff)
downloadbun-ac9f8c0e93b6b91096a6dc8782f09a08c2e4f6c8.tar.gz
bun-ac9f8c0e93b6b91096a6dc8782f09a08c2e4f6c8.tar.zst
bun-ac9f8c0e93b6b91096a6dc8782f09a08c2e4f6c8.zip
feat(net.createServer) and adds socket.connect IPC support (#2337)
* added net.Server * fix fmt * fix cast and move test * fix node-net.tests.ts but breaks server data receive * fix end and close only emitting when data or pipe was added * fix socket starting paused * add echo test * fix fmt * fix fmt * on close if the socket is paused, keep paused until the user resumes it to match node behavior * resume on connect * fix getConnections, error on close, make _Handler private and create symbols for SocketServerHandlers * add path support (IPC) * fix unix domains support, add connect unix tests * fix unix socket tests * emit listening and listening error on next tick * fix connection flask test * try fix connect error on macos test * merge connection and drop tests * added exclusive option * fix socket.zig fmt * fix validation for options and add test for it * pass prettier fmt
Diffstat (limited to 'test/js/node/net/node-net-server.test.ts')
-rw-r--r--test/js/node/net/node-net-server.test.ts484
1 files changed, 484 insertions, 0 deletions
diff --git a/test/js/node/net/node-net-server.test.ts b/test/js/node/net/node-net-server.test.ts
new file mode 100644
index 000000000..bdaf289a7
--- /dev/null
+++ b/test/js/node/net/node-net-server.test.ts
@@ -0,0 +1,484 @@
+import { describe, expect, it } from "bun:test";
+import { createServer } from "net";
+import { createCallCheckCtx } from "node-harness";
+import { realpathSync } from "fs";
+import { tmpdir } from "os";
+import { join } from "path";
+
+const socket_domain = join(realpathSync(tmpdir()), "node-net-server.sock");
+
+describe("net.createServer listen", () => {
+ it("should throw when no port or path when using options", done => {
+ expect(() => createServer().listen({ exclusive: true })).toThrow(
+ 'The argument \'options\' must have the property "port" or "path". Received {"exclusive":true}',
+ );
+ done();
+ });
+
+ it("should listen on IPv6 by default", done => {
+ const { mustCall, mustNotCall } = createCallCheckCtx(done);
+
+ const server = createServer();
+
+ server.on("error", mustNotCall());
+
+ server.listen(
+ 0,
+ mustCall(() => {
+ const address = server.address();
+ expect(address.address).toStrictEqual("::");
+ //system should provide an port when 0 or no port is passed
+ expect(address.port).toBeGreaterThan(100);
+ expect(address.family).toStrictEqual("IPv6");
+ server.close();
+ }),
+ );
+ done();
+ });
+
+ it("should listen on IPv4", done => {
+ const { mustCall, mustNotCall } = createCallCheckCtx(done);
+
+ const server = createServer();
+
+ server.on("error", mustNotCall());
+
+ server.listen(
+ 0,
+ "127.0.0.1",
+ mustCall(() => {
+ const address = server.address();
+ expect(address.address).toStrictEqual("127.0.0.1");
+ //system should provide an port when 0 or no port is passed
+ expect(address.port).toBeGreaterThan(100);
+ expect(address.family).toStrictEqual("IPv4");
+ server.close();
+ }),
+ );
+ done();
+ });
+
+ it("should listen on localhost", done => {
+ const { mustCall, mustNotCall } = createCallCheckCtx(done);
+
+ const server = createServer();
+
+ server.on("error", mustNotCall());
+
+ server.listen(
+ 0,
+ "::1",
+ mustCall(() => {
+ const address = server.address();
+ expect(address.address).toStrictEqual("::1");
+ //system should provide an port when 0 or no port is passed
+ expect(address.port).toBeGreaterThan(100);
+ expect(address.family).toStrictEqual("IPv6");
+ server.close();
+ }),
+ );
+ done();
+ });
+
+ it("should listen on localhost", done => {
+ const { mustCall, mustNotCall } = createCallCheckCtx(done);
+
+ const server = createServer();
+
+ server.on("error", mustNotCall());
+
+ server.listen(
+ 0,
+ "::1",
+ mustCall(() => {
+ const address = server.address();
+ expect(address.address).toStrictEqual("::1");
+ expect(address.family).toStrictEqual("IPv6");
+ server.close();
+ }),
+ );
+ done();
+ });
+
+ it("should listen without port or host", done => {
+ const { mustCall, mustNotCall } = createCallCheckCtx(done);
+
+ const server = createServer();
+
+ server.on("error", mustNotCall());
+
+ server.listen(
+ mustCall(() => {
+ const address = server.address();
+ expect(address.address).toStrictEqual("::");
+ //system should provide an port when 0 or no port is passed
+ expect(address.port).toBeGreaterThan(100);
+ expect(address.family).toStrictEqual("IPv6");
+ server.close();
+ }),
+ );
+ done();
+ });
+
+ it("should listen on the correct port", done => {
+ const { mustCall, mustNotCall } = createCallCheckCtx(done);
+
+ const server = createServer();
+
+ server.on("error", mustNotCall());
+
+ server.listen(
+ 49027,
+ mustCall(() => {
+ const address = server.address();
+ expect(address.address).toStrictEqual("::");
+ expect(address.port).toStrictEqual(49027);
+ expect(address.family).toStrictEqual("IPv6");
+ server.close();
+ }),
+ );
+ done();
+ });
+
+ it("should listen on the correct port with IPV4", done => {
+ const { mustCall, mustNotCall } = createCallCheckCtx(done);
+
+ const server = createServer();
+
+ server.on("error", mustNotCall());
+
+ server.listen(
+ 49026,
+ "127.0.0.1",
+ mustCall(() => {
+ const address = server.address();
+ expect(address.address).toStrictEqual("127.0.0.1");
+ expect(address.port).toStrictEqual(49026);
+ expect(address.family).toStrictEqual("IPv4");
+ server.close();
+ }),
+ );
+ done();
+ });
+
+ it("should listen on unix domain socket", done => {
+ const { mustCall, mustNotCall } = createCallCheckCtx(done);
+
+ const server = createServer();
+
+ server.on("error", mustNotCall());
+
+ server.listen(
+ socket_domain,
+ mustCall(() => {
+ const address = server.address();
+ expect(address).toStrictEqual(socket_domain);
+ server.close();
+ }),
+ );
+ done();
+ });
+});
+
+it("should receive data", done => {
+ const { mustCall, mustNotCall } = createCallCheckCtx(done);
+ let timeout;
+
+ const onData = mustCall(data => {
+ clearTimeout(timeout);
+ server.close();
+ expect(data.byteLength).toBe(5);
+ expect(data.toString("utf8")).toBe("Hello");
+ done();
+ });
+
+ const server = createServer(socket => {
+ socket.on("data", onData);
+ });
+
+ const closeAndFail = mustNotCall("no data received (timeout)", () => {
+ clearTimeout(timeout);
+ server.close();
+ });
+
+ server.on("error", mustNotCall("no data received"));
+
+ //should be faster than 100ms
+ timeout = setTimeout(() => {
+ closeAndFail();
+ }, 100);
+
+ server.listen(
+ mustCall(() => {
+ const address = server.address();
+ Bun.connect({
+ hostname: address.address,
+ port: address.port,
+ socket: {
+ data(socket) {},
+ open(socket) {
+ socket.write("Hello");
+ socket.end();
+ },
+ connectError: closeAndFail, // connection failed
+ },
+ }).catch(closeAndFail);
+ }),
+ );
+});
+
+it("should call end", done => {
+ const { mustCall, mustNotCall } = createCallCheckCtx(done);
+ let timeout;
+
+ const onEnd = mustCall(() => {
+ clearTimeout(timeout);
+ server.close();
+ done();
+ });
+
+ const server = createServer(socket => {
+ socket.on("end", onEnd);
+ socket.end();
+ });
+
+ const closeAndFail = mustNotCall("end not called (timeout)", () => {
+ clearTimeout(timeout);
+ server.close();
+ });
+ server.on("error", mustNotCall("end not called"));
+
+ //should be faster than 100ms
+ timeout = setTimeout(() => {
+ closeAndFail();
+ }, 100);
+
+ server.listen(
+ mustCall(() => {
+ const address = server.address();
+ Bun.connect({
+ hostname: address.address,
+ port: address.port,
+ socket: {
+ data(socket) {},
+ open(socket) {},
+ connectError: closeAndFail, // connection failed
+ },
+ }).catch(closeAndFail);
+ }),
+ );
+});
+
+it("should call close", done => {
+ let closed = false;
+ const server = createServer();
+ server.listen().on("close", () => {
+ closed = true;
+ });
+ server.close();
+ expect(closed).toBe(true);
+ done();
+});
+
+it("should call connection and drop", done => {
+ const { mustCall, mustNotCall } = createCallCheckCtx(done);
+
+ let timeout;
+ const server = createServer();
+ let maxClients = 2;
+ server.maxConnections = maxClients - 1;
+
+ const closeAndFail = mustNotCall("drop not called (timeout)", () => {
+ clearTimeout(timeout);
+ server.close();
+ done();
+ });
+
+ //should be faster than 100ms
+ timeout = setTimeout(() => {
+ closeAndFail();
+ }, 100);
+ let connection_called = false;
+ server
+ .on(
+ "connection",
+ mustCall(() => {
+ connection_called = true;
+ }),
+ )
+ .on(
+ "drop",
+ mustCall(data => {
+ server.close();
+ clearTimeout(timeout);
+ expect(data.localPort).toBeDefined();
+ expect(data.remotePort).toBeDefined();
+ expect(data.remoteFamily).toBeDefined();
+ expect(data.localFamily).toBeDefined();
+ expect(data.localAddress).toBeDefined();
+ expect(connection_called).toBe(true);
+ done();
+ }),
+ )
+ .listen(() => {
+ const address = server.address();
+
+ function spawnClient() {
+ Bun.connect({
+ port: address.port,
+ hostname: address.address,
+ socket: {
+ data(socket) {},
+ open(socket) {
+ socket.end();
+ },
+ },
+ });
+ }
+ for (let i = 0; i < maxClients; i++) {
+ spawnClient();
+ spawnClient();
+ }
+ });
+});
+
+it("should call listening", done => {
+ const { mustCall, mustNotCall } = createCallCheckCtx(done);
+
+ let timeout;
+ const server = createServer();
+ let maxClients = 2;
+ server.maxConnections = maxClients - 1;
+
+ const closeAndFail = mustNotCall("listening not called (timeout)", () => {
+ clearTimeout(timeout);
+ server.close();
+ done();
+ });
+
+ //should be faster than 100ms
+ timeout = setTimeout(() => {
+ closeAndFail();
+ }, 100);
+
+ server
+ .on(
+ "listening",
+ mustCall(() => {
+ server.close();
+ clearTimeout(timeout);
+ done();
+ }),
+ )
+ .listen();
+});
+
+it("should call error", done => {
+ const { mustCall, mustNotCall } = createCallCheckCtx(done);
+
+ let timeout;
+ const server = createServer();
+ let maxClients = 2;
+ server.maxConnections = maxClients - 1;
+
+ const closeAndFail = mustNotCall("error not called (timeout)", () => {
+ clearTimeout(timeout);
+ server.close();
+ done();
+ });
+
+ //should be faster than 100ms
+ timeout = setTimeout(() => {
+ closeAndFail();
+ }, 100);
+
+ server
+ .on(
+ "error",
+ mustCall(err => {
+ server.close();
+ clearTimeout(timeout);
+ expect(err).toBeDefined();
+ done();
+ }),
+ )
+ .listen(123456);
+});
+
+it("should call abort with signal", done => {
+ const { mustCall, mustNotCall } = createCallCheckCtx(done);
+
+ const controller = new AbortController();
+ let timeout;
+ const server = createServer();
+ let maxClients = 2;
+ server.maxConnections = maxClients - 1;
+
+ const closeAndFail = mustNotCall("close not called (timeout)", () => {
+ clearTimeout(timeout);
+ server.close();
+ done();
+ });
+
+ //should be faster than 100ms
+ timeout = setTimeout(() => {
+ closeAndFail();
+ }, 100);
+
+ server
+ .on(
+ "close",
+ mustCall(() => {
+ clearImmediate(timeout);
+ done();
+ }),
+ )
+ .listen({ port: 0, signal: controller.signal }, () => {
+ controller.abort();
+ });
+});
+
+it("should echo data", done => {
+ const { mustCall, mustNotCall } = createCallCheckCtx(done);
+ let timeout;
+
+ const server = createServer(socket => {
+ socket.pipe(socket);
+ });
+
+ const closeAndFail = mustNotCall("no data received (timeout)", () => {
+ clearTimeout(timeout);
+ server.close();
+ });
+
+ server.on("error", mustNotCall("no data received"));
+
+ //should be faster than 100ms
+ timeout = setTimeout(() => {
+ closeAndFail();
+ }, 100);
+
+ server.listen(
+ mustCall(() => {
+ const address = server.address();
+ Bun.connect({
+ hostname: address.address,
+ port: address.port,
+ socket: {
+ data(socket, data) {
+ clearTimeout(timeout);
+ server.close();
+ socket.end();
+ expect(data.byteLength).toBe(5);
+ expect(data.toString("utf8")).toBe("Hello");
+ done();
+ },
+ open(socket) {
+ socket.write("Hello");
+ },
+ connectError: closeAndFail, // connection failed
+ },
+ }).catch(closeAndFail);
+ }),
+ );
+});