Files
bun.sh/test/js/node/http2/node-http2-memory-leak.js
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

108 lines
3.1 KiB
JavaScript

import { heapStats } from "bun:jsc";
import http2 from "http2";
import path from "path";
function getHeapStats() {
return heapStats().objectTypeCounts;
}
const nodeExecutable = Bun.which("node");
if (!nodeExecutable) {
console.log("No node executable found");
process.exit(99); // 99 no node executable
}
async function nodeEchoServer() {
const subprocess = Bun.spawn([nodeExecutable, path.join(import.meta.dir, "node-echo-server.fixture.js")], {
stdout: "pipe",
});
const reader = subprocess.stdout.getReader();
const data = await reader.read();
const decoder = new TextDecoder("utf-8");
const address = JSON.parse(decoder.decode(data.value));
const url = `https://${address.family === "IPv6" ? `[${address.address}]` : address.address}:${address.port}`;
return { address, url, subprocess };
}
// X iterations should be enough to detect a leak
const ITERATIONS = 50;
// lets send a bigish payload
const PAYLOAD = Buffer.from("a".repeat(128 * 1024));
const info = await nodeEchoServer();
async function runRequests(iterations) {
for (let j = 0; j < iterations; j++) {
let client = http2.connect(info.url, { rejectUnauthorized: false });
let promises = [];
// 100 multiplex POST connections per iteration
for (let i = 0; i < 100; i++) {
const { promise, resolve, reject } = Promise.withResolvers();
const req = client.request({ ":path": "/post", ":method": "POST" });
let got_response = false;
req.on("response", () => {
got_response = true;
});
req.setEncoding("utf8");
req.on("end", () => {
if (got_response) {
resolve();
} else {
reject(new Error("no response"));
}
});
req.write(PAYLOAD);
req.end();
promises.push(promise);
}
await Promise.all(promises);
client.close();
client = null;
promises = null;
Bun.gc(true);
}
}
try {
const startStats = getHeapStats();
// warm up
await runRequests(ITERATIONS);
await Bun.sleep(10);
Bun.gc(true);
// take a baseline
const baseline = process.memoryUsage.rss();
// run requests
await runRequests(ITERATIONS);
await Bun.sleep(10);
Bun.gc(true);
// take an end snapshot
const end = process.memoryUsage.rss();
const delta = end - baseline;
const bodiesLeaked = delta / PAYLOAD.length;
// we executed 10 requests per iteration
if (bodiesLeaked > ITERATIONS) {
console.log("Too many bodies leaked", bodiesLeaked);
process.exit(1);
}
const endStats = getHeapStats();
info.subprocess.kill();
// check for H2FrameParser leaks
const pendingH2Parsers = (endStats.H2FrameParser || 0) - (startStats.H2FrameParser || 0);
if (pendingH2Parsers > 5) {
console.log("Too many pending H2FrameParsers", pendingH2Parsers);
process.exit(pendingH2Parsers);
}
// check for TLSSocket leaks
const pendingTLSSockets = (endStats.TLSSocket || 0) - (startStats.TLSSocket || 0);
if (pendingTLSSockets > 5) {
console.log("Too many pending TLSSockets", pendingTLSSockets);
process.exit(pendingTLSSockets);
}
process.exit(0);
} catch (err) {
console.log(err);
info.subprocess.kill();
process.exit(99); // 99 exception
}