Files
bun.sh/test/js/node/net/node-net.test.ts
Ciro Spaciari c23579d66c feat(http2) Client Support (#6761)
* init

* WIP fix post data/refactor

* make it compile again

* more things

* undo padding and continue + fix posting + update lshpack

* re-add fixes

* really simple tests + fixes

* add aborted event

* fix trailers

* add getDefaultSettings, getPackedSettings and getUnpackedSettings

* fix + fmt

* fixes

* fix enablePush o be boolean

* fix sendTrailers

* fmt

* fix goaway, fix some error messages

* oops

* revert some changes

* more reverts

* WIP

* get CMAKE building lspack + ping behavior

* remove files that should not be added anymore

* remove old out files

* remove old file

* fix header reduce

* bunch of fixes

* fix socket unref

* fix abort signal, rebase and fmt

* socket unref tests

* oops re-add cmake

* fix stream state

* more tests and fixes

* fixes and ping tests

* lshpack in Dockerfile

* just copy lshpack

* oops

* fix end

* wantTrailers

* encode/decode fixes + grpc

* channel credentials test

* rebase

* support h2c

* fix h2c

* fix h2c connect event + h2c tests

* 'copy ls-hpack

* ls-hpack build sh

* oops

* changing CMake + Docker

* add ps1 build for ls-hpack fix clean

* optimizations + fixes

* remove protect/unprotect from handlers

* more consistent errors

* fix error code

* oops

* add goaway tests

* oops uncoment tests

* better errors more tests

* add broken priority frame

* better memory leak, some fixes and less flask tests

* zig update .Big -> .big

* closer threshold + h2 fix

* remove log

* test should not be flask

* increase timeout on leak memory test

* windows build

* less flasky

* always 127.0.0.1

* [autofix.ci] apply automated fixes

* remove .call and use primordials

* apply socket fix

* fix win-build

* should properly mark inactive

* postgres fix

* increase deadline

* test tests

* high light deadline timeouts

* event loop test

* make memory leak test faster

* use buffer on payload test

* check for socket.data before use

* reduce iterations to see if timeout on mac intel

* fix assertions

* avoid localhost and simplify things

* refactor memory leak test

* Update src/js/node/tls.js

* fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: cirospaciari <ciro.spaciai@gmail.com>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-11-17 18:14:54 -08:00

438 lines
12 KiB
TypeScript

import { ServerWebSocket, TCPSocket, Socket as _BunSocket, TCPSocketListener } from "bun";
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it } from "bun:test";
import { connect, isIP, isIPv4, isIPv6, Socket, createConnection } from "net";
import { realpathSync, mkdtempSync } from "fs";
import { tmpdir } from "os";
import { join } from "path";
import { bunEnv, bunExe } from "harness";
const socket_domain = mkdtempSync(join(realpathSync(tmpdir()), "node-net"));
it("should support net.isIP()", () => {
expect(isIP("::1")).toBe(6);
expect(isIP("foobar")).toBe(0);
expect(isIP("127.0.0.1")).toBe(4);
expect(isIP("127.0.0.1/24")).toBe(0);
expect(isIP("127.000.000.001")).toBe(0);
});
it("should support net.isIPv4()", () => {
expect(isIPv4("::1")).toBe(false);
expect(isIPv4("foobar")).toBe(false);
expect(isIPv4("127.0.0.1")).toBe(true);
expect(isIPv4("127.0.0.1/24")).toBe(false);
expect(isIPv4("127.000.000.001")).toBe(false);
});
it("should support net.isIPv6()", () => {
expect(isIPv6("::1")).toBe(true);
expect(isIPv6("foobar")).toBe(false);
expect(isIPv6("127.0.0.1")).toBe(false);
expect(isIPv6("127.0.0.1/24")).toBe(false);
expect(isIPv6("127.000.000.001")).toBe(false);
});
describe("net.Socket read", () => {
var port = 12345;
var unix_servers = 0;
for (let [message, label] of [
// ["Hello World!".repeat(1024), "long message"],
["Hello!", "short message"],
]) {
describe(label, () => {
function runWithServer(cb: (..._: any[]) => void, unix_domain_path?: any) {
return (done: (_: any) => void) => {
function drain(socket: _BunSocket<{ message: string }>) {
const message = socket.data.message;
const written = socket.write(message);
if (written < message.length) {
socket.data.message = message.slice(written);
} else {
socket.end();
}
}
var server = unix_domain_path
? Bun.listen({
unix: join(unix_domain_path, `${unix_servers++}.sock`),
socket: {
open(socket) {
socket.data.message = message;
drain(socket);
},
drain,
error(socket, err) {
done(err);
},
},
data: {
message: "",
},
})
: Bun.listen({
hostname: "localhost",
port: 0,
socket: {
open(socket) {
socket.data.message = message;
drain(socket);
},
drain,
error(socket, err) {
done(err);
},
},
data: {
message: "",
},
});
function onDone(err: any) {
server.stop();
done(err);
}
try {
cb(server, drain, onDone);
} catch (e) {
onDone(e);
}
};
}
it(
"should work with .connect(port)",
runWithServer((server, drain, done) => {
var data = "";
const socket = new Socket()
.connect(server.port)
.on("connect", () => {
expect(socket).toBeDefined();
expect(socket.connecting).toBe(false);
})
.setEncoding("utf8")
.on("data", chunk => {
data += chunk;
})
.on("end", () => {
try {
expect(data).toBe(message);
done();
} catch (e) {
server.stop();
done(e);
}
})
.on("error", done);
}),
);
it(
"should work with .connect(port, listener)",
runWithServer((server, drain, done) => {
var data = "";
const socket = new Socket()
.connect(server.port, () => {
expect(socket).toBeDefined();
expect(socket.connecting).toBe(false);
})
.setEncoding("utf8")
.on("data", chunk => {
data += chunk;
})
.on("end", () => {
try {
expect(data).toBe(message);
done();
} catch (e) {
server.stop();
done(e);
}
})
.on("error", done);
}),
);
it(
"should work with .connect(port, host, listener)",
runWithServer((server, drain, done) => {
var data = "";
const socket = new Socket()
.connect(server.port, "localhost", () => {
expect(socket).toBeDefined();
expect(socket.connecting).toBe(false);
})
.setEncoding("utf8")
.on("data", chunk => {
data += chunk;
})
.on("end", () => {
try {
expect(data).toBe(message);
done();
} catch (e) {
done(e);
}
})
.on("error", done);
}),
);
it(
"should work with .createConnection(path)",
runWithServer((server, drain, done) => {
var data = "";
const socket = createConnection(server.unix)
.on("connect", () => {
expect(socket).toBeDefined();
expect(socket.connecting).toBe(false);
})
.setEncoding("utf8")
.on("data", chunk => {
data += chunk;
})
.on("end", () => {
try {
expect(data).toBe(message);
done();
} catch (e) {
server.stop();
done(e);
}
})
.on("error", done);
}, socket_domain),
);
it(
"should work with .connect(path)",
runWithServer((server, drain, done) => {
var data = "";
const socket = new Socket()
.connect(server.unix)
.on("connect", () => {
expect(socket).toBeDefined();
expect(socket.connecting).toBe(false);
})
.setEncoding("utf8")
.on("data", chunk => {
data += chunk;
})
.on("end", () => {
try {
expect(data).toBe(message);
done();
} catch (e) {
server.stop();
done(e);
}
})
.on("error", done);
}, socket_domain),
);
it(
"should work with .connect(path, listener)",
runWithServer((server, drain, done) => {
var data = "";
const socket = new Socket()
.connect(server.unix, () => {
expect(socket).toBeDefined();
expect(socket.connecting).toBe(false);
})
.setEncoding("utf8")
.on("data", chunk => {
data += chunk;
})
.on("end", () => {
try {
expect(data).toBe(message);
done();
} catch (e) {
done(e);
}
})
.on("error", done);
}, socket_domain),
);
});
}
});
describe("net.Socket write", () => {
const message = "Hello World!".repeat(1024);
let port = 53213;
function runWithServer(cb: (..._: any[]) => void) {
return (done: (_?: any) => void) => {
let server: TCPSocketListener<unknown>;
function close(socket: _BunSocket<Buffer[]>) {
expect(Buffer.concat(socket.data).toString("utf8")).toBe(message);
done();
}
var leaky;
server = Bun.listen({
hostname: "0.0.0.0",
port: 0,
socket: {
close,
data(socket, buffer) {
leaky = socket;
if (!Buffer.isBuffer(buffer)) {
done(new Error("buffer is not a Buffer"));
}
socket.data.push(buffer);
},
end: close,
error(socket, err) {
leaky = socket;
done(err);
},
open(socket) {
leaky = socket;
socket.data = [];
},
},
data: [] as Buffer[],
});
function onDone(err: any) {
server.stop();
done(err);
}
try {
cb(server, onDone);
} catch (e) {
onDone(e);
}
};
}
it(
"should work with .end(data)",
runWithServer((server, done) => {
const socket = new Socket()
.connect(server.port)
.on("ready", () => {
expect(socket).toBeDefined();
expect(socket.connecting).toBe(false);
})
.on("error", done)
.end(message);
}),
);
it(
"should work with .write(data).end()",
runWithServer((server, done) => {
const socket = new Socket()
.connect(server.port, () => {
expect(socket).toBeDefined();
expect(socket.connecting).toBe(false);
})
.on("error", done);
socket.write(message);
socket.end();
}),
);
it(
"should work with multiple .write()s",
runWithServer((server, done) => {
const socket = new Socket()
.connect(server.port, server.hostname, () => {
expect(socket).toBeDefined();
expect(socket.connecting).toBe(false);
})
.on("error", done);
const size = 10;
for (let i = 0; i < message.length; i += size) {
socket.write(message.slice(i, i + size));
}
socket.end();
}),
);
});
it("should handle connection error", done => {
let errored = false;
// @ts-ignore
const socket = connect(55555, () => {
done(new Error("Should not have connected"));
});
socket.on("error", error => {
if (errored) {
return done(new Error("Should not have errored twice"));
}
errored = true;
expect(error).toBeDefined();
expect(error.message).toBe("Failed to connect");
expect((error as any).code).toBe("ECONNREFUSED");
});
socket.on("connect", () => {
done(new Error("Should not have connected"));
});
socket.on("close", () => {
expect(errored).toBe(true);
done();
});
});
it("should handle connection error (unix)", done => {
let errored = false;
// @ts-ignore
const socket = connect("loser", () => {
done(new Error("Should not have connected"));
});
socket.on("error", error => {
if (errored) {
return done(new Error("Should not have errored twice"));
}
errored = true;
expect(error).toBeDefined();
expect(error.message).toBe("Failed to connect");
expect((error as any).code).toBe("ENOENT");
});
socket.on("connect", () => {
done(new Error("Should not have connected"));
});
socket.on("close", () => {
expect(errored).toBe(true);
done();
});
});
it("Socket has a prototype", () => {
function Connection() {}
function Connection2() {}
require("util").inherits(Connection, Socket);
require("util").inherits(Connection2, require("tls").TLSSocket);
});
it("unref should exit when no more work pending", async () => {
const process = Bun.spawn({
cmd: [bunExe(), join(import.meta.dir, "node-unref-fixture.js")],
env: bunEnv,
});
expect(await process.exited).toBe(0);
});
it("socket should keep process alive if unref is not called", async () => {
const process = Bun.spawn({
cmd: [bunExe(), join(import.meta.dir, "node-ref-default-fixture.js")],
env: bunEnv,
});
expect(await process.exited).toBe(1);
});