Compare commits

..

9 Commits

Author SHA1 Message Date
Meghan Denny
c6e3381346 fix test-net-connect-reset-after-destroy.js 2025-05-28 22:45:50 -07:00
Jarred Sumner
b01ffe6da8 Fix pauseOnConnect semantics for node:net server (#19987) 2025-05-28 22:23:57 -07:00
Kai Tamkun
579f2ecd51 Add node:vm leak tests (#19947)
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
2025-05-28 22:23:30 -07:00
Jarred Sumner
627b0010e0 Fix Node net bytesWritten with pending strings (#19962)
Co-authored-by: Meghan Denny <meghan@bun.sh>
2025-05-28 22:21:28 -07:00
Jarred Sumner
3369e25a70 Update environment.json 2025-05-28 22:04:38 -07:00
Jarred Sumner
06a40f0b29 Configure cursor 2025-05-28 21:55:08 -07:00
Jarred Sumner
7989352b39 Add node server close test (#19972)
Co-authored-by: Meghan Denny <meghan@bun.sh>
2025-05-28 21:38:52 -07:00
Jarred Sumner
e1ab6fe36b Add net autoselectfamily default test (#19970)
Co-authored-by: Jarred-Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2025-05-28 21:30:22 -07:00
Jarred Sumner
14f59568cc Fix net.listen backlog arg & add Node test (#19966)
Co-authored-by: Meghan Denny <meghan@bun.sh>
2025-05-28 21:23:35 -07:00
15 changed files with 574 additions and 80 deletions

26
.cursor/Dockerfile Normal file
View File

@@ -0,0 +1,26 @@
FROM ghcr.io/oven-sh/bun-development-docker-image:prebuilt
# Create a non-root user for development
RUN useradd -m -s /bin/bash ubuntu
# Create workspace directory and give ubuntu user access
RUN mkdir -p /workspace && \
chown -R ubuntu:ubuntu /workspace && \
# Allow ubuntu user to use sudo without password for development tasks
apt-get update && apt-get install -y sudo && \
echo "ubuntu ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers && \
rm -rf /var/lib/apt/lists/*
# Set the user and working directory
USER ubuntu
WORKDIR /workspace/bun
# Configure Git for the ubuntu user (agents often need this)
RUN git config --global user.name "Background Agent" && \
git config --global user.email "agent@cursor.com" && \
git config --global init.defaultBranch main
# Ensure PATH includes Bun binaries for the ubuntu user
ENV PATH="/workspace/bun/build/debug:/workspace/bun/build/release:/usr/local/bin:${PATH}"
RUN git pull

7
.cursor/environment.json Normal file
View File

@@ -0,0 +1,7 @@
{
"build": {
"dockerfile": "Dockerfile",
"context": "."
},
"terminals": []
}

View File

@@ -1,27 +1,13 @@
---
description: How to build Bun
globs:
globs:
alwaysApply: false
---
# How to build Bun
## CMake
Run:
Bun is built using CMake, which you can find in `CMakeLists.txt` and in the `cmake/` directory.
* `CMakeLists.txt`
* `cmake/`
* `Globals.cmake` - macros and functions used by all the other files
* `Options.cmake` - build options for configuring the build (e.g. debug/release mode)
* `CompilerFlags.cmake` - compiler and linker flags used by all the targets
* `tools/` - setup scripts for various build tools (e.g. llvm, zig, webkit, rust, etc.)
* `targets/` - targets for bun and its dependencies (e.g. brotli, boringssl, libuv, etc.)
## How to
There are `package.json` scripts that make it easy to build Bun without calling CMake directly, for example:
```sh
bun run build # builds a debug build: `build/debug/bun-debug`
bun run build:release # builds a release build: `build/release/bun`
bun run build:assert # builds a release build with debug assertions: `build/assert/bun`
```bash
bun bd
```

View File

@@ -478,14 +478,6 @@ function ClientRequest(input, options, cb) {
if (isIP(host) || !options.lookup) {
// Don't need to bother with lookup if it's already an IP address or no lookup function is provided.
if (!this.hasHeader("Host")) {
let hostHeader = host;
const posColon = hostHeader.indexOf(":");
if (posColon !== -1 && hostHeader.includes(":", posColon + 1) && hostHeader.charCodeAt(0) !== 91 /* '[' */) {
hostHeader = `[${hostHeader}]`;
}
this.setHeader("Host", `${hostHeader}:${port}`);
}
const [url, proxy] = getURL(host);
go(url, proxy, false);
return true;
@@ -516,12 +508,7 @@ function ClientRequest(input, options, cb) {
}
if (!this.hasHeader("Host")) {
let hostHeader = host;
const posColon = hostHeader.indexOf(":");
if (posColon !== -1 && hostHeader.includes(":", posColon + 1) && hostHeader.charCodeAt(0) !== 91 /* '[' */) {
hostHeader = `[${hostHeader}]`;
}
this.setHeader("Host", `${hostHeader}:${port}`);
this.setHeader("Host", `${host}:${port}`);
}
// We want to try all possible addresses, beginning with the IPv6 ones, until one succeeds.

View File

@@ -233,6 +233,14 @@ const SocketHandlers: SocketHandler = {
self[kwriteCallback] = null;
callback(error);
}
if (error?.syscall === "connect") {
const ex = new ExceptionWithHostPort(error.errno, "connect", self._host, self._port);
self.emit("error", ex);
if (!self.destroyed) process.nextTick(destroyNT, self, ex);
return;
}
self.emit("error", error);
},
open(socket) {
@@ -409,6 +417,10 @@ const ServerHandlers: SocketHandler = {
self[bunSocketServerConnections]++;
if (pauseOnConnect) {
_socket.pause();
}
if (typeof connectionListener === "function") {
this.pauseOnConnect = pauseOnConnect;
if (!isTLS) {
@@ -463,7 +475,9 @@ const ServerHandlers: SocketHandler = {
// after secureConnection event we emmit secure and secureConnect
self.emit("secure", self);
self.emit("secureConnect", verifyError);
if (!server.pauseOnConnect) {
if (server.pauseOnConnect) {
self.pause();
} else {
self.resume();
}
},
@@ -517,6 +531,9 @@ const SocketHandlers2: SocketHandler<SocketHandleData> = {
$debug("self[kupgraded]", String(self[kupgraded]));
if (!self[kupgraded]) req!.oncomplete(0, self._handle, req, true, true);
socket.data.req = undefined;
if (self.pauseOnConnect) {
self.pause();
}
if (self[kupgraded]) {
self.connecting = false;
const options = self[bunTLSConnectOptions];
@@ -724,6 +741,8 @@ function Socket(options?) {
this[kclosed] = false;
this[kended] = false;
this.connecting = false;
this._host = undefined;
this._port = undefined;
this[bunTLSConnectOptions] = null;
this.timeout = 0;
this[kwriteCallback] = undefined;
@@ -839,7 +858,9 @@ Object.defineProperty(Socket.prototype, "bytesWritten", {
else bytes += Buffer.byteLength(chunk.chunk, chunk.encoding);
}
} else if (data) {
bytes += data.byteLength;
// Writes are either a string or a Buffer.
if (typeof data !== "string") bytes += data.length;
else bytes += Buffer.byteLength(data, this._pendingEncoding || "utf8");
}
return bytes;
},
@@ -857,7 +878,7 @@ Socket.prototype[kAttach] = function (port, socket) {
}
if (this[kSetKeepAlive]) {
socket.setKeepAlive(true, self[kSetKeepAliveInitialDelay]);
socket.setKeepAlive(true, this[kSetKeepAliveInitialDelay]);
}
if (!this[kupgraded]) {
@@ -904,7 +925,9 @@ Socket.prototype.connect = function connect(...args) {
});
}
this.pauseOnConnect = pauseOnConnect;
if (!pauseOnConnect) {
if (pauseOnConnect) {
this.pause();
} else {
process.nextTick(() => {
this.resume();
});
@@ -1546,6 +1569,7 @@ function lookupAndConnect(self, options) {
$debug("connect: find host", host, addressType);
$debug("connect: dns options", dnsopts);
self._host = host;
self._port = port;
const lookup = options.lookup || dns.lookup;
if (dnsopts.family !== 4 && dnsopts.family !== 6 && !localAddress && autoSelectFamily) {
@@ -2185,6 +2209,7 @@ Server.prototype.getConnections = function getConnections(callback) {
};
Server.prototype.listen = function listen(port, hostname, onListen) {
const argsLength = arguments.length;
if (typeof port === "string") {
const numPort = Number(port);
if (!Number.isNaN(numPort)) port = numPort;
@@ -2212,9 +2237,15 @@ Server.prototype.listen = function listen(port, hostname, onListen) {
hostname = undefined;
port = undefined;
} else {
if (typeof hostname === "function") {
if (typeof hostname === "number") {
backlog = hostname;
hostname = undefined;
} else if (typeof hostname === "function") {
onListen = hostname;
hostname = undefined;
} else if (typeof hostname === "string" && typeof onListen === "number") {
backlog = onListen;
onListen = argsLength > 3 ? arguments[3] : undefined;
}
if (typeof port === "function") {
@@ -2231,6 +2262,7 @@ Server.prototype.listen = function listen(port, hostname, onListen) {
ipv6Only = options.ipv6Only;
allowHalfOpen = options.allowHalfOpen;
reusePort = options.reusePort;
backlog = options.backlog;
if (typeof options.fd === "number" && options.fd >= 0) {
fd = options.fd;

View File

@@ -1,41 +0,0 @@
'use strict';
// When using the object form of http.request and using an IPv6 address
// as a hostname, and using a non-standard port, the Host header
// is improperly formatted.
// Issue: https://github.com/nodejs/node/issues/5308
// As per https://tools.ietf.org/html/rfc7230#section-5.4 and
// https://tools.ietf.org/html/rfc3986#section-3.2.2
// the IPv6 address should be enclosed in square brackets
const common = require('../common');
const assert = require('assert');
const http = require('http');
const net = require('net');
const requests = [
{ host: 'foo:1234', headers: { expectedhost: 'foo:1234:80' } },
{ host: '::1', headers: { expectedhost: '[::1]:80' } },
];
function createLocalConnection(options) {
options.host = undefined;
options.port = this.port;
options.path = undefined;
return net.createConnection(options);
}
http.createServer(common.mustCall(function(req, res) {
this.requests ||= 0;
assert.strictEqual(req.headers.host, req.headers.expectedhost);
res.end();
if (++this.requests === requests.length)
this.close();
}, requests.length)).listen(0, function() {
const address = this.address();
for (let i = 0; i < requests.length; ++i) {
requests[i].createConnection =
common.mustCall(createLocalConnection.bind(address));
http.get(requests[i]);
}
});

View File

@@ -0,0 +1,120 @@
'use strict';
const common = require('../common');
const { createMockedLookup } = require('../common/dns');
const assert = require('assert');
const {
createConnection,
createServer,
setDefaultAutoSelectFamily,
} = require('net');
const autoSelectFamilyAttemptTimeout =
common.defaultAutoSelectFamilyAttemptTimeout;
// Test that IPV4 is reached by default if IPV6 is not reachable and the default is enabled
{
const ipv4Server = createServer((socket) => {
socket.on(
'data',
common.mustCall(() => {
socket.write('response-ipv4');
socket.end();
}),
);
});
ipv4Server.listen(
0,
'127.0.0.1',
common.mustCall(() => {
setDefaultAutoSelectFamily(true);
const connection = createConnection({
host: 'example.org',
port: ipv4Server.address().port,
lookup: createMockedLookup('::1', '127.0.0.1'),
autoSelectFamilyAttemptTimeout,
});
let response = '';
connection.setEncoding('utf-8');
connection.on('data', (chunk) => {
response += chunk;
});
connection.on(
'end',
common.mustCall(() => {
assert.strictEqual(response, 'response-ipv4');
ipv4Server.close();
}),
);
connection.write('request');
}),
);
}
// Test that IPV4 is not reached by default if IPV6 is not reachable and the default is disabled
{
const ipv4Server = createServer((socket) => {
socket.on(
'data',
common.mustCall(() => {
socket.write('response-ipv4');
socket.end();
}),
);
});
ipv4Server.listen(
0,
'127.0.0.1',
common.mustCall(() => {
setDefaultAutoSelectFamily(false);
const port = ipv4Server.address().port;
const connection = createConnection({
host: 'example.org',
port,
lookup: createMockedLookup('::1', '127.0.0.1'),
});
connection.on('ready', common.mustNotCall());
connection.on(
'error',
common.mustCall((error) => {
if (common.hasIPv6) {
assert.strictEqual(error.code, 'ECONNREFUSED');
assert.strictEqual(
error.message,
`connect ECONNREFUSED ::1:${port}`,
);
} else if (error.code === 'EAFNOSUPPORT') {
assert.strictEqual(
error.message,
`connect EAFNOSUPPORT ::1:${port} - Local (undefined:undefined)`,
);
} else if (error.code === 'EUNATCH') {
assert.strictEqual(
error.message,
`connect EUNATCH ::1:${port} - Local (:::0)`,
);
} else {
assert.strictEqual(error.code, 'EADDRNOTAVAIL');
assert.strictEqual(
error.message,
`connect EADDRNOTAVAIL ::1:${port} - Local (:::0)`,
);
}
ipv4Server.close();
}),
);
}),
);
}

View File

@@ -0,0 +1,77 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
'use strict';
const common = require('../common');
const assert = require('assert');
const net = require('net');
const tcp = net.Server(common.mustCall((s) => {
tcp.close();
let buf = '';
s.setEncoding('utf8');
s.on('data', function(d) {
buf += d;
});
s.on('end', common.mustCall(function() {
console.error('SERVER: end', buf);
assert.strictEqual(buf, "L'État, c'est moi");
s.end();
}));
}));
tcp.listen(0, common.mustCall(function() {
const socket = net.Stream({ highWaterMark: 0 });
let connected = false;
assert.strictEqual(socket.pending, true);
socket.connect(this.address().port, common.mustCall(() => connected = true));
assert.strictEqual(socket.pending, true);
assert.strictEqual(socket.connecting, true);
assert.strictEqual(socket.readyState, 'opening');
// Write a string that contains a multi-byte character sequence to test that
// `bytesWritten` is incremented with the # of bytes, not # of characters.
const a = "L'État, c'est ";
const b = 'moi';
// We're still connecting at this point so the datagram is first pushed onto
// the connect queue. Make sure that it's not added to `bytesWritten` again
// when the actual write happens.
const r = socket.write(a, common.mustCall((er) => {
console.error('write cb');
assert.ok(connected);
assert.strictEqual(socket.bytesWritten, Buffer.from(a + b).length);
assert.strictEqual(socket.pending, false);
}));
socket.on('close', common.mustCall(() => {
assert.strictEqual(socket.pending, true);
}));
assert.strictEqual(socket.bytesWritten, Buffer.from(a).length);
assert.strictEqual(r, false);
socket.end(b);
assert.strictEqual(socket.readyState, 'opening');
}));

View File

@@ -0,0 +1,56 @@
'use strict';
const common = require('../common');
const assert = require('assert');
const net = require('net');
const tcp = net.Server(common.mustCall((s) => {
tcp.close();
let buf = '';
s.setEncoding('utf8');
s.on('data', function(d) {
buf += d;
});
s.on('end', common.mustCall(function() {
console.error('SERVER: end', buf);
assert.strictEqual(buf, "L'État, c'est moi");
s.end();
}));
}));
tcp.listen(0, common.mustCall(function() {
const socket = net.Stream({ highWaterMark: 0 });
let connected = false;
assert.strictEqual(socket.pending, true);
socket.connect(this.address().port, common.mustCall(() => connected = true));
assert.strictEqual(socket.pending, true);
assert.strictEqual(socket.connecting, true);
assert.strictEqual(socket.readyState, 'opening');
// Write a string that contains a multi-byte character sequence to test that
// `bytesWritten` is incremented with the # of bytes, not # of characters.
const a = "L'État, c'est ";
const b = 'moi';
// We're still connecting at this point so the datagram is first pushed onto
// the connect queue. Make sure that it's not added to `bytesWritten` again
// when the actual write happens.
const r = socket.write(a, common.mustCall((er) => {
console.error('write cb');
assert.ok(connected);
assert.strictEqual(socket.bytesWritten, Buffer.from(a + b).length);
assert.strictEqual(socket.pending, false);
}));
socket.on('close', common.mustCall(() => {
assert.strictEqual(socket.pending, true);
}));
assert.strictEqual(socket.bytesWritten, Buffer.from(a).length);
assert.strictEqual(r, false);
socket.end(b);
assert.strictEqual(socket.readyState, 'opening');
}));

View File

@@ -0,0 +1,29 @@
'use strict';
const common = require('../common');
const net = require('net');
const assert = require('assert');
const server = net.createServer();
server.listen(0, common.mustCall(function() {
const port = server.address().port;
const conn = net.createConnection(port);
server.on('connection', (socket) => {
socket.on('error', common.expectsError({
code: 'ECONNRESET',
message: 'read ECONNRESET',
name: 'Error'
}));
});
conn.on('connect', common.mustCall(function() {
assert.strictEqual(conn, conn.resetAndDestroy().destroy());
conn.on('error', common.mustNotCall());
conn.write(Buffer.from('fzfzfzfzfz'), common.expectsError({
code: 'ERR_STREAM_DESTROYED',
message: 'Cannot call write after a stream was destroyed',
name: 'Error'
}));
server.close();
}));
}));

View File

@@ -0,0 +1,45 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
'use strict';
const common = require('../common');
const assert = require('assert');
const net = require('net');
const sockets = [];
const server = net.createServer(function(c) {
c.on('close', common.mustCall());
sockets.push(c);
if (sockets.length === 2) {
assert.strictEqual(server.close(), server);
sockets.forEach((c) => c.destroy());
}
});
server.on('close', common.mustCall());
assert.strictEqual(server, server.listen(0, () => {
net.createConnection(server.address().port);
net.createConnection(server.address().port);
}));

View File

@@ -0,0 +1,49 @@
'use strict';
const common = require('../common');
const assert = require('assert');
const net = require('net');
const msg = 'test';
let stopped = true;
let server1Sock;
const server1ConnHandler = (socket) => {
socket.on('data', function(data) {
if (stopped) {
assert.fail('data event should not have happened yet');
}
assert.strictEqual(data.toString(), msg);
socket.end();
server1.close();
});
server1Sock = socket;
};
const server1 = net.createServer({ pauseOnConnect: true }, server1ConnHandler);
const server2ConnHandler = (socket) => {
socket.on('data', function(data) {
assert.strictEqual(data.toString(), msg);
socket.end();
server2.close();
assert.strictEqual(server1Sock.bytesRead, 0);
server1Sock.resume();
stopped = false;
});
};
const server2 = net.createServer({ pauseOnConnect: false }, server2ConnHandler);
server1.listen(0, function() {
const clientHandler = common.mustCall(function() {
server2.listen(0, function() {
net.createConnection({ port: this.address().port }).write(msg);
});
});
net.createConnection({ port: this.address().port }).write(msg, clientHandler);
});
process.on('exit', function() {
assert.strictEqual(stopped, false);
});

View File

@@ -0,0 +1,64 @@
'use strict';
const common = require('../common');
const assert = require('assert');
const net = require('net');
// With only a callback, server should get a port assigned by the OS
{
const server = net.createServer(common.mustNotCall());
server.listen(common.mustCall(function() {
assert.ok(server.address().port > 100);
server.close();
}));
}
// No callback to listen(), assume we can bind in 100 ms
{
const server = net.createServer(common.mustNotCall());
server.listen(common.PORT);
setTimeout(function() {
const address = server.address();
assert.strictEqual(address.port, common.PORT);
if (address.family === 'IPv6')
assert.strictEqual(server._connectionKey, `6::::${address.port}`);
else
assert.strictEqual(server._connectionKey, `4:0.0.0.0:${address.port}`);
server.close();
}, 100);
}
// Callback to listen()
{
const server = net.createServer(common.mustNotCall());
server.listen(common.PORT + 1, common.mustCall(function() {
assert.strictEqual(server.address().port, common.PORT + 1);
server.close();
}));
}
// Backlog argument
{
const server = net.createServer(common.mustNotCall());
server.listen(common.PORT + 2, '0.0.0.0', 127, common.mustCall(function() {
assert.strictEqual(server.address().port, common.PORT + 2);
server.close();
}));
}
// Backlog argument without host argument
{
const server = net.createServer(common.mustNotCall());
server.listen(common.PORT + 3, 127, common.mustCall(function() {
assert.strictEqual(server.address().port, common.PORT + 3);
server.close();
}));
}

View File

@@ -0,0 +1,27 @@
const vm = require("vm");
const { describe, it, expect } = require("bun:test");
describe("vm.Script", () => {
it("shouldn't leak memory", () => {
const initialUsage = process.memoryUsage.rss();
{
const source = `/*\n${Buffer.alloc(10000, " * aaaaa\n").toString("utf8")}\n*/ Buffer.alloc(10, 'hello');`;
function go(i) {
const script = new vm.Script(source + "//" + i);
script.runInThisContext();
}
for (let i = 0; i < 10000; ++i) {
go(i);
}
}
Bun.gc(true);
const finalUsage = process.memoryUsage.rss();
const megabytes = Math.round(((finalUsage - initialUsage) / 1024 / 1024) * 100) / 100;
expect(megabytes).toBeLessThan(200);
});
});

View File

@@ -0,0 +1,30 @@
const vm = require("vm");
const { describe, it, expect } = require("bun:test");
describe("vm.SourceTextModule", () => {
it("shouldn't leak memory", async () => {
const initialUsage = process.memoryUsage.rss();
{
const source = `/*\n${Buffer.alloc(50_000, " * aaaaa\n").toString("utf8")}\n*/ Buffer.alloc(10, 'hello');`;
async function go(i) {
const mod = new vm.SourceTextModule(source + "//" + i, {
identifier: Buffer.alloc(64, i.toString()).toString("utf8"),
});
await mod.link(() => {});
await mod.evaluate();
}
for (let i = 0; i < 50_000; ++i) {
await go(i);
}
}
Bun.gc(true);
const finalUsage = process.memoryUsage.rss();
const megabytes = Math.round(((finalUsage - initialUsage) / 1024 / 1024) * 100) / 100;
expect(megabytes).toBeLessThan(3000);
});
});