fix(node): add all already-passing tests (#18299)

This commit is contained in:
Don Isaac
2025-03-20 20:04:08 -07:00
committed by GitHub
parent 8e246e1e67
commit eae2d61f12
47 changed files with 2554 additions and 0 deletions

View File

@@ -7,5 +7,6 @@ fixtures/snapshot
fixtures/repl*
.tmp.*
*shadow-realm*
!test-shadow-realm-prepare-stack-trace.js
!test-shadow-realm.js
**/fails.txt

View File

@@ -0,0 +1,35 @@
'use strict';
const common = require('../common');
const { checkSupportReusePort, options } = require('../common/udp');
const assert = require('assert');
const child_process = require('child_process');
const dgram = require('dgram');
if (!process.env.isWorker) {
checkSupportReusePort().then(() => {
const socket = dgram.createSocket(options);
socket.bind(0, common.mustCall(() => {
const port = socket.address().port;
const workerOptions = { env: { ...process.env, isWorker: 1, port } };
let count = 2;
for (let i = 0; i < 2; i++) {
const worker = child_process.fork(__filename, workerOptions);
worker.on('exit', common.mustCall((code) => {
assert.strictEqual(code, 0);
if (--count === 0) {
socket.close();
}
}));
}
}));
}, () => {
common.skip('The `reusePort` is not supported');
});
return;
}
const socket = dgram.createSocket(options);
socket.bind(+process.env.port, common.mustCall(() => {
socket.close();
}));

View File

@@ -0,0 +1,22 @@
'use strict';
require('../common');
const assert = require('assert');
const { spawnSync } = require('child_process');
// The last option on the command line takes precedence:
assert.strictEqual(spawnSync(process.execPath, [
'--max-http-header-size=1234',
'--max-http-header-size=5678',
'-p', 'http.maxHeaderSize',
], {
encoding: 'utf8'
}).stdout.trim(), '5678');
// The command line takes precedence over NODE_OPTIONS:
assert.strictEqual(spawnSync(process.execPath, [
'--max-http-header-size=5678',
'-p', 'http.maxHeaderSize',
], {
encoding: 'utf8',
env: { ...process.env, NODE_OPTIONS: '--max-http-header-size=1234' }
}).stdout.trim(), '5678');

View File

@@ -0,0 +1,51 @@
'use strict';
const common = require('../common');
if (!common.hasIPv6)
common.skip('no IPv6 support');
if (common.isWindows)
common.skip('dgram clustering is currently not supported on windows.');
const assert = require('assert');
const cluster = require('cluster');
const dgram = require('dgram');
// This test ensures that the `ipv6Only` option in `dgram.createSock()`
// works as expected.
if (cluster.isPrimary) {
cluster.fork().on('exit', common.mustCall((code) => {
assert.strictEqual(code, 0);
}));
} else {
let waiting = 2;
function close() {
if (--waiting === 0)
cluster.worker.disconnect();
}
const socket1 = dgram.createSocket({
type: 'udp6',
ipv6Only: true
});
const socket2 = dgram.createSocket({
type: 'udp4',
});
socket1.on('error', common.mustNotCall());
socket2.on('error', common.mustNotCall());
socket1.bind({
port: 0,
address: '::',
}, common.mustCall(() => {
const { port } = socket1.address();
socket2.bind({
port,
address: '0.0.0.0',
}, common.mustCall(() => {
process.nextTick(() => {
socket1.close(close);
socket2.close(close);
});
}));
}));
}

View File

@@ -0,0 +1,35 @@
'use strict';
const common = require('../common');
if (common.isWindows)
common.skip('dgram clustering is currently not supported on windows.');
const assert = require('assert');
const cluster = require('cluster');
const dgram = require('dgram');
if (cluster.isPrimary) {
cluster.fork().on('exit', common.mustCall((code) => {
assert.strictEqual(code, 0);
}));
return;
}
let waiting = 2;
function close() {
if (--waiting === 0)
cluster.worker.disconnect();
}
const options = { type: 'udp4', reuseAddr: true };
const socket1 = dgram.createSocket(options);
const socket2 = dgram.createSocket(options);
socket1.bind(0, () => {
socket2.bind(socket1.address().port, () => {
// Work around health check issue
process.nextTick(() => {
socket1.close(close);
socket2.close(close);
});
});
});

View File

@@ -0,0 +1,39 @@
'use strict';
const common = require('../common');
if (common.isWindows)
common.skip('dgram clustering is currently not supported on windows.');
const { checkSupportReusePort, options } = require('../common/udp');
const assert = require('assert');
const cluster = require('cluster');
const dgram = require('dgram');
if (cluster.isPrimary) {
checkSupportReusePort().then(() => {
cluster.fork().on('exit', common.mustCall((code) => {
assert.strictEqual(code, 0);
}));
}, () => {
common.skip('The `reusePort` option is not supported');
});
return;
}
let waiting = 2;
function close() {
if (--waiting === 0)
cluster.worker.disconnect();
}
// Test if the worker requests the main process to create a socket
cluster._getServer = common.mustNotCall();
const socket1 = dgram.createSocket(options);
const socket2 = dgram.createSocket(options);
socket1.bind(0, () => {
socket2.bind(socket1.address().port, () => {
socket1.close(close);
socket2.close(close);
});
});

View File

@@ -0,0 +1,30 @@
'use strict';
const common = require('../common');
const cluster = require('cluster');
const assert = require('assert');
if (cluster.isPrimary) {
const worker = cluster.fork();
assert.strictEqual(worker.isConnected(), true);
worker.on('disconnect', common.mustCall(() => {
assert.strictEqual(worker.isConnected(), false);
}));
worker.on('message', function(msg) {
if (msg === 'readyToDisconnect') {
worker.disconnect();
}
});
} else {
function assertNotConnected() {
assert.strictEqual(cluster.worker.isConnected(), false);
}
assert.strictEqual(cluster.worker.isConnected(), true);
cluster.worker.on('disconnect', common.mustCall(assertNotConnected));
cluster.worker.process.on('disconnect', common.mustCall(assertNotConnected));
process.send('readyToDisconnect');
}

View File

@@ -0,0 +1,52 @@
'use strict';
const common = require('../common');
const assert = require('assert');
const { spawn } = require('child_process');
if (process.argv[2] !== 'child') {
// Expected error not emitted.
{
const child = spawn(
process.execPath, [__filename, 'child', 0], { encoding: 'utf8' }
);
child.on('exit', common.mustCall((status) => {
assert.notStrictEqual(status, 0);
}));
}
// Expected error emitted.
{
const child = spawn(
process.execPath, [__filename, 'child', 1], { encoding: 'utf8' }
);
child.on('exit', common.mustCall((status) => {
assert.strictEqual(status, 0);
}));
}
// Expected error emitted too many times.
{
const child = spawn(
process.execPath, [__filename, 'child', 2], { encoding: 'utf8' }
);
child.stderr.setEncoding('utf8');
let stderr = '';
child.stderr.on('data', (data) => {
stderr += data;
});
child.stderr.on('end', common.mustCall(() => {
assert.match(stderr, /Unexpected extra warning received/);
}));
child.on('exit', common.mustCall((status) => {
assert.notStrictEqual(status, 0);
}));
}
} else {
const iterations = +process.argv[3];
common.expectWarning('fhqwhgads', 'fhqwhgads', 'fhqwhgads');
for (let i = 0; i < iterations; i++) {
process.emitWarning('fhqwhgads', 'fhqwhgads', 'fhqwhgads');
}
}

View File

@@ -0,0 +1,44 @@
// Flags: --no-warnings --expose-internals
'use strict';
const common = require('../common');
common.skipIfInspectorDisabled();
if (!common.hasCrypto) {
common.skip('missing crypto');
}
const { hasOpenSSL3 } = require('../common/crypto');
if (!hasOpenSSL3) {
common.skip('this test requires OpenSSL 3.x');
}
if (!common.hasIntl) {
// A handful of the tests fail when ICU is not included.
common.skip('missing Intl');
}
if (process.config.variables.node_quic) {
common.skip('this test assumes default configuration options');
}
const {
generateConfigJsonSchema,
} = require('internal/options');
const schemaInDoc = require('../../doc/node-config-schema.json');
const assert = require('assert');
const schema = generateConfigJsonSchema();
// This assertion ensures that whenever we add a new env option, we also add it
// to the JSON schema. The function getEnvOptionsInputType() returns all the available
// env options, so we can generate the JSON schema from it and compare it to the
// current JSON schema.
// To regenerate the JSON schema, run:
// out/Release/node --expose-internals tools/doc/generate-json-schema.mjs
// And then run make doc to update the out/doc/node-config-schema.json file.
assert.strictEqual(JSON.stringify(schema), JSON.stringify(schemaInDoc), 'JSON schema is outdated.' +
'Run `out/Release/node --expose-internals tools/doc/generate-json-schema.mjs` to update it.');

View File

@@ -0,0 +1,21 @@
'use strict';
const common = require('../common');
const assert = require('assert');
const child = require('child_process');
if (!common.isWindows) {
common.skip('This test is specific to Windows to test winapi_strerror');
}
// Ref: https://github.com/nodejs/node/issues/23191
// This test is specific to Windows.
const cp = child.spawn('pwd');
cp.on('exit', common.mustCall(function() {
try {
process._debugProcess(cp.pid);
} catch (error) {
assert.strictEqual(error.message, 'The system cannot find the file specified.');
}
}));

View File

@@ -0,0 +1,28 @@
'use strict';
const common = require('../common');
const dc = require('diagnostics_channel');
const assert = require('assert');
const input = {
foo: 'bar'
};
const symbol = Symbol('test');
// Individual channel objects can be created to avoid future lookups
const channel = dc.channel(symbol);
// Expect two successful publishes later
channel.subscribe(common.mustCall((message, name) => {
assert.strictEqual(name, symbol);
assert.deepStrictEqual(message, input);
}));
channel.publish(input);
{
assert.throws(() => {
dc.channel(null);
}, /ERR_INVALID_ARG_TYPE/);
}

View File

@@ -0,0 +1,38 @@
'use strict';
const common = require('../common');
const dc = require('diagnostics_channel');
const assert = require('assert');
const channel = dc.tracingChannel('test');
const expectedError = new Error('test');
const input = { foo: 'bar' };
const thisArg = { baz: 'buz' };
function check(found) {
assert.deepStrictEqual(found, input);
}
const handlers = {
start: common.mustCall(check),
end: common.mustCall(check),
asyncStart: common.mustCall(check),
asyncEnd: common.mustCall(check),
error: common.mustCall((found) => {
check(found);
assert.deepStrictEqual(found.error, expectedError);
})
};
channel.subscribe(handlers);
channel.tracePromise(function(value) {
assert.deepStrictEqual(this, thisArg);
return Promise.reject(value);
}, input, thisArg, expectedError).then(
common.mustNotCall(),
common.mustCall((value) => {
assert.deepStrictEqual(value, expectedError);
})
);

View File

@@ -0,0 +1,34 @@
'use strict';
const common = require('../common');
if ((!common.hasCrypto) || (!common.hasIntl)) {
common.skip('ESLint tests require crypto and Intl');
}
common.skipIfEslintMissing();
const RuleTester = require('../../tools/eslint/node_modules/eslint').RuleTester;
const rule = require('../../tools/eslint-rules/prefer-optional-chaining');
new RuleTester().run('prefer-optional-chaining', rule, {
valid: [
{
code: 'hello?.world',
options: []
},
],
invalid: [
{
code: 'hello && hello.world',
options: [],
errors: [{ message: 'Prefer optional chaining.' }],
output: 'hello?.world'
},
{
code: 'hello && hello.world && hello.world.foobar',
options: [],
errors: [{ message: 'Prefer optional chaining.' }],
output: 'hello?.world?.foobar'
},
]
});

View File

@@ -0,0 +1,83 @@
// 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 fs = require('fs');
const tmpdir = require('../common/tmpdir');
const fn = tmpdir.resolve('write.txt');
tmpdir.refresh();
const file = fs.createWriteStream(fn, {
highWaterMark: 10
});
const EXPECTED = '012345678910';
const callbacks = {
open: -1,
drain: -2,
close: -1
};
file
.on('open', function(fd) {
console.error('open!');
callbacks.open++;
assert.strictEqual(typeof fd, 'number');
})
.on('drain', function() {
console.error('drain!', callbacks.drain);
callbacks.drain++;
if (callbacks.drain === -1) {
assert.strictEqual(fs.readFileSync(fn, 'utf8'), EXPECTED);
file.write(EXPECTED);
} else if (callbacks.drain === 0) {
assert.strictEqual(fs.readFileSync(fn, 'utf8'), EXPECTED + EXPECTED);
file.end();
}
})
.on('close', function() {
console.error('close!');
assert.strictEqual(file.bytesWritten, EXPECTED.length * 2);
callbacks.close++;
file.write('should not work anymore', common.expectsError({
code: 'ERR_STREAM_WRITE_AFTER_END',
name: 'Error',
message: 'write after end'
}));
file.on('error', common.mustNotCall());
fs.unlinkSync(fn);
});
for (let i = 0; i < 11; i++) {
file.write(`${i}`);
}
process.on('exit', function() {
for (const k in callbacks) {
assert.strictEqual(callbacks[k], 0, `${k} count off by ${callbacks[k]}`);
}
console.log('ok');
});

View File

@@ -0,0 +1,23 @@
// Flags: --expose-gc
'use strict';
const common = require('../common');
// This test verifies that when a V8 FinalizationRegistryCleanupTask is queue
// at the last moment when JavaScript can be executed, the callback of a
// FinalizationRegistry will not be invoked and the process should exit
// normally.
const reg = new FinalizationRegistry(
common.mustNotCall('This FinalizationRegistry callback should never be called'));
function register() {
// Create a temporary object in a new function scope to allow it to be GC-ed.
reg.register({});
}
process.on('exit', () => {
// This is the final chance to execute JavaScript.
register();
// Queue a FinalizationRegistryCleanupTask by a testing gc request.
globalThis.gc();
});

View File

@@ -0,0 +1,27 @@
'use strict';
const common = require('../common');
const assert = require('assert');
const path = require('path');
const fs = require('fs');
const tmpdir = require('../common/tmpdir');
tmpdir.refresh();
const tmpDir = tmpdir.path;
const longPath = path.join(...[tmpDir].concat(Array(30).fill('1234567890')));
fs.mkdirSync(longPath, { recursive: true });
// Test if we can have symlinks to files and folders with long filenames
const targetDirectory = path.join(longPath, 'target-directory');
fs.mkdirSync(targetDirectory);
const pathDirectory = path.join(tmpDir, 'new-directory');
fs.symlink(targetDirectory, pathDirectory, 'dir', common.mustSucceed(() => {
assert(fs.existsSync(pathDirectory));
}));
const targetFile = path.join(longPath, 'target-file');
fs.writeFileSync(targetFile, 'data');
const pathFile = path.join(tmpDir, 'new-file');
fs.symlink(targetFile, pathFile, common.mustSucceed(() => {
assert(fs.existsSync(pathFile));
}));

View File

@@ -0,0 +1,35 @@
'use strict';
require('../common');
const assert = require('assert');
const fixtures = require('../common/fixtures');
const fs = require('fs');
const stream = require('stream');
const tmpdir = require('../common/tmpdir');
const firstEncoding = 'base64';
const secondEncoding = 'latin1';
const examplePath = fixtures.path('x.txt');
const dummyPath = tmpdir.resolve('x.txt');
tmpdir.refresh();
const exampleReadStream = fs.createReadStream(examplePath, {
encoding: firstEncoding
});
const dummyWriteStream = fs.createWriteStream(dummyPath, {
encoding: firstEncoding
});
exampleReadStream.pipe(dummyWriteStream).on('finish', function() {
const assertWriteStream = new stream.Writable({
write: function(chunk, enc, next) {
const expected = Buffer.from('xyz\n');
assert(chunk.equals(expected));
}
});
assertWriteStream.setDefaultEncoding(secondEncoding);
fs.createReadStream(dummyPath, {
encoding: secondEncoding
}).pipe(assertWriteStream);
});

View File

@@ -0,0 +1,65 @@
'use strict';
// Flags: --expose-gc
// just like test-gc-http-client.js,
// but aborting every connection that comes in.
const common = require('../common');
const { onGC } = require('../common/gc');
const http = require('http');
const os = require('os');
const cpus = os.availableParallelism();
let createClients = true;
let done = 0;
let count = 0;
let countGC = 0;
function serverHandler(req, res) {
res.connection.destroy();
}
const server = http.createServer(serverHandler);
server.listen(0, common.mustCall(() => {
for (let i = 0; i < cpus; i++)
getAll();
}));
function getAll() {
if (!createClients)
return;
const req = http.get({
hostname: 'localhost',
pathname: '/',
port: server.address().port
}, cb).on('error', cb);
count++;
onGC(req, { ongc });
setImmediate(getAll);
}
function cb(res) {
done += 1;
}
function ongc() {
countGC++;
}
setImmediate(status);
function status() {
if (done > 0) {
createClients = false;
globalThis.gc();
console.log(`done/collected/total: ${done}/${countGC}/${count}`);
if (countGC === count) {
server.close();
return;
}
}
setImmediate(status);
}

View File

@@ -0,0 +1,46 @@
'use strict';
const common = require('../common');
common.skipIfInspectorDisabled();
if (!process.config.variables.node_use_amaro) common.skip('Requires Amaro');
const { NodeInstance } = require('../common/inspector-helper.js');
const fixtures = require('../common/fixtures');
const assert = require('assert');
const { pathToFileURL } = require('url');
const scriptPath = fixtures.path('typescript/ts/test-typescript.ts');
const scriptURL = pathToFileURL(scriptPath);
async function runTest() {
const child = new NodeInstance(
['--inspect-brk=0'],
undefined,
scriptPath);
const session = await child.connectInspectorSession();
await session.send({ method: 'NodeRuntime.enable' });
await session.waitForNotification('NodeRuntime.waitingForDebugger');
await session.send([
{ 'method': 'Debugger.enable' },
{ 'method': 'Runtime.enable' },
{ 'method': 'Runtime.runIfWaitingForDebugger' },
]);
await session.send({ method: 'NodeRuntime.disable' });
const scriptParsed = await session.waitForNotification((notification) => {
if (notification.method !== 'Debugger.scriptParsed') return false;
return notification.params.url === scriptPath || notification.params.url === scriptURL.href;
});
// Verify that the script has a sourceURL, hinting that it is a generated source.
assert(scriptParsed.params.hasSourceURL || common.isInsideDirWithUnusualChars);
await session.waitForPauseOnStart();
await session.runToCompletion();
assert.strictEqual((await child.expectShutdown()).exitCode, 0);
}
runTest().then(common.mustCall());

View File

@@ -0,0 +1,78 @@
'use strict';
const common = require('../common');
common.skipIfInspectorDisabled();
const { Worker, isMainThread, parentPort, workerData } =
require('worker_threads');
if (!isMainThread || workerData !== 'launched by test') {
common.skip('This test only works on a main thread');
}
const { Session } = require('inspector');
const MAX_DEPTH = 3;
let rootWorker = null;
const runTest = common.mustCall(function() {
let reportedWorkersCount = 0;
const session = new Session();
session.connect();
session.on('NodeWorker.attachedToWorker', common.mustCall(
({ params: { workerInfo } }) => {
console.log(`Worker ${workerInfo.title} was reported`);
if (++reportedWorkersCount === MAX_DEPTH) {
rootWorker.postMessage({ done: true });
}
}, MAX_DEPTH));
session.post('NodeWorker.enable', { waitForDebuggerOnStart: false });
});
function processMessage({ child }) {
console.log(`Worker ${child} is running`);
if (child === MAX_DEPTH) {
runTest();
}
}
function workerCallback(message) {
parentPort.postMessage(message);
}
function startWorker(depth, messageCallback) {
const worker = new Worker(__filename, { workerData: 'launched by test' });
worker.on('message', messageCallback);
worker.postMessage({ depth });
return worker;
}
function runMainThread() {
rootWorker = startWorker(1, processMessage);
}
function runChildWorkerThread() {
let worker = null;
parentPort.on('message', ({ child, depth, done }) => {
if (done) {
if (worker) {
worker.postMessage({ done: true });
}
parentPort.close();
} else if (depth) {
parentPort.postMessage({ child: depth });
if (depth < MAX_DEPTH) {
worker = startWorker(depth + 1, workerCallback);
}
} else if (child) {
parentPort.postMessage({ child });
}
});
}
if (isMainThread) {
runMainThread();
} else {
runChildWorkerThread();
}

View File

@@ -0,0 +1,17 @@
'use strict';
require('../common');
const assert = require('assert');
const { spawnSync } = require('child_process');
const results = new Set();
for (let i = 0; i < 10; i++) {
const result = spawnSync(process.execPath, ['-p', 'Math.random()']);
assert.strictEqual(result.status, 0);
results.add(result.stdout.toString());
}
// It's theoretically possible if _very_ unlikely to see some duplicates.
// Therefore, don't expect that the size of the set is exactly 10 but do
// assume it's > 1 because if you get 10 duplicates in a row you should
// go out real quick and buy some lottery tickets, you lucky devil you!
assert(results.size > 1);

View File

@@ -0,0 +1,105 @@
'use strict';
const common = require('../common');
if (!process.config.variables.node_use_amaro) common.skip('Requires Amaro');
const assert = require('assert');
const vm = require('node:vm');
const { stripTypeScriptTypes } = require('node:module');
const { test } = require('node:test');
common.expectWarning(
'ExperimentalWarning',
'stripTypeScriptTypes is an experimental feature and might change at any time',
);
const sourceToBeTransformed = `
namespace MathUtil {
export const add = (a: number, b: number) => a + b;
}`;
const sourceToBeTransformedMapping = 'UACY;aACK,MAAM,CAAC,GAAW,IAAc,IAAI;AACnD,GAFU,aAAA';
test('stripTypeScriptTypes', () => {
const source = 'const x: number = 1;';
const result = stripTypeScriptTypes(source);
assert.strictEqual(result, 'const x = 1;');
});
test('stripTypeScriptTypes explicit', () => {
const source = 'const x: number = 1;';
const result = stripTypeScriptTypes(source, { mode: 'strip' });
assert.strictEqual(result, 'const x = 1;');
});
test('stripTypeScriptTypes code is not a string', () => {
assert.throws(() => stripTypeScriptTypes({}),
{ code: 'ERR_INVALID_ARG_TYPE' });
});
test('stripTypeScriptTypes invalid mode', () => {
const source = 'const x: number = 1;';
assert.throws(() => stripTypeScriptTypes(source, { mode: 'invalid' }), { code: 'ERR_INVALID_ARG_VALUE' });
});
test('stripTypeScriptTypes sourceMap throws when mode is strip', () => {
const source = 'const x: number = 1;';
assert.throws(() => stripTypeScriptTypes(source,
{ mode: 'strip', sourceMap: true }),
{ code: 'ERR_INVALID_ARG_VALUE' });
});
test('stripTypeScriptTypes sourceUrl throws when mode is strip', () => {
const source = 'const x: number = 1;';
const result = stripTypeScriptTypes(source, { mode: 'strip', sourceUrl: 'foo.ts' });
assert.strictEqual(result, 'const x = 1;\n\n//# sourceURL=foo.ts');
});
test('stripTypeScriptTypes source map when mode is transform', () => {
const result = stripTypeScriptTypes(sourceToBeTransformed, { mode: 'transform', sourceMap: true });
const script = new vm.Script(result);
const sourceMap =
{
version: 3,
sources: [''],
names: [],
mappings: sourceToBeTransformedMapping,
};
const inlinedSourceMap = Buffer.from(JSON.stringify(sourceMap)).toString('base64');
assert.strictEqual(script.sourceMapURL, `data:application/json;base64,${inlinedSourceMap}`);
});
test('stripTypeScriptTypes source map when mode is transform and sourceUrl', () => {
const result = stripTypeScriptTypes(sourceToBeTransformed, {
mode: 'transform',
sourceMap: true,
sourceUrl: 'test.ts'
});
const script = new vm.Script(result);
const sourceMap =
{
version: 3,
sources: ['test.ts'],
names: [],
mappings: sourceToBeTransformedMapping,
};
const inlinedSourceMap = Buffer.from(JSON.stringify(sourceMap)).toString('base64');
assert.strictEqual(script.sourceMapURL, `data:application/json;base64,${inlinedSourceMap}`);
});
test('stripTypeScriptTypes source map when mode is transform and sourceUrl with non-latin-1 chars', () => {
const sourceUrl = 'dir%20with $unusual"chars?\'åß∂ƒ©∆¬…`.cts';
const result = stripTypeScriptTypes(sourceToBeTransformed, {
mode: 'transform',
sourceMap: true,
sourceUrl,
});
const script = new vm.Script(result);
const sourceMap =
{
version: 3,
sources: [sourceUrl],
names: [],
mappings: sourceToBeTransformedMapping,
};
const inlinedSourceMap = Buffer.from(JSON.stringify(sourceMap)).toString('base64');
assert.strictEqual(script.sourceMapURL, `data:application/json;base64,${inlinedSourceMap}`);
});

View File

@@ -0,0 +1,47 @@
'use strict';
const common = require('../common');
const assert = require('assert');
const { spawn } = require('child_process');
const net = require('net');
if (process.argv[2] === 'child') {
const server = net.createServer(common.mustCall());
server.listen(0, common.mustCall(() => {
process.send({ type: 'ready', data: { port: server.address().port } });
}));
} else {
const cp = spawn(process.execPath,
[__filename, 'child'],
{
stdio: ['ipc', 'inherit', 'inherit']
});
cp.on('exit', common.mustCall((code, signal) => {
assert.strictEqual(code, null);
assert.strictEqual(signal, 'SIGKILL');
}));
cp.on('message', common.mustCall((msg) => {
const { type, data } = msg;
assert.strictEqual(type, 'ready');
const port = data.port;
const conn = net.createConnection({
port,
onread: {
buffer: Buffer.alloc(65536),
callback: () => {},
}
});
conn.on('error', (err) => {
// Error emitted on Windows.
assert.strictEqual(err.code, 'ECONNRESET');
});
conn.on('connect', common.mustCall(() => {
cp.kill('SIGKILL');
}));
}));
}

View File

@@ -0,0 +1,33 @@
'use strict';
const common = require('../common');
const assert = require('assert');
const net = require('net');
const server = net.createServer(handle);
const N = 100;
const buf = Buffer.alloc(2, 'a');
server.listen(0, function() {
const conn = net.connect(this.address().port);
conn.on('connect', () => {
let res = true;
let i = 0;
for (; i < N && res; i++) {
conn.cork();
conn.write(buf);
res = conn.write(buf);
conn.uncork();
}
assert.strictEqual(i, N);
conn.end();
});
});
function handle(socket) {
socket.resume();
socket.on('error', common.mustNotCall())
.on('close', common.mustCall(() => server.close()));
}

View File

@@ -0,0 +1,34 @@
'use strict';
// Flags: --expose-gc
// Note: This is a variant of test-net-write-fully-async-hex-string.js.
// This always worked, but it seemed appropriate to add a test that checks the
// behavior for Buffers, too.
const common = require('../common');
const net = require('net');
const data = Buffer.alloc(1000000);
const server = net.createServer(common.mustCall(function(conn) {
conn.resume();
server.close();
})).listen(0, common.mustCall(function() {
const conn = net.createConnection(this.address().port, common.mustCall(() => {
let count = 0;
function writeLoop() {
if (count++ === 20) {
conn.end();
return;
}
while (conn.write(Buffer.from(data)));
globalThis.gc({ type: 'major' });
// The buffer allocated above should still be alive.
}
conn.on('drain', writeLoop);
writeLoop();
}));
}));

View File

@@ -0,0 +1,32 @@
'use strict';
// Flags: --expose-gc
// Regression test for https://github.com/nodejs/node/issues/8251.
const common = require('../common');
const net = require('net');
const data = Buffer.alloc(1000000).toString('hex');
const server = net.createServer(common.mustCall(function(conn) {
conn.resume();
server.close();
})).listen(0, common.mustCall(function() {
const conn = net.createConnection(this.address().port, common.mustCall(() => {
let count = 0;
function writeLoop() {
if (count++ === 20) {
conn.end();
return;
}
while (conn.write(data, 'hex'));
globalThis.gc({ type: 'major' });
// The buffer allocated inside the .write() call should still be alive.
}
conn.on('drain', writeLoop);
writeLoop();
}));
}));

View File

@@ -0,0 +1,104 @@
'use strict';
require('../common');
const assert = require('assert');
// Most of the times, the function called for async and Sync
// methods are the same on node_file.cc
function syncAndAsyncAPI(funcName) {
return [funcName, funcName + 'Sync'];
}
// This tests guarantee whenever a new API under fs module is exposed
// it must contain a test to the permission model.
// Otherwise, a vulnerability might be exposed. If you are adding a new
// fs method, please, make sure to include a test for it on test-permission-fs-*
// and include to the supportedApis list.
//
//
// This list is synced with
// fixtures/permission/fs-read and
// fixtures/permission/fs-write
const supportedApis = [
...syncAndAsyncAPI('appendFile'),
...syncAndAsyncAPI('access'),
...syncAndAsyncAPI('chown'),
...syncAndAsyncAPI('chmod'),
...syncAndAsyncAPI('copyFile'),
...syncAndAsyncAPI('cp'),
'createReadStream',
'createWriteStream',
...syncAndAsyncAPI('exists'),
...syncAndAsyncAPI('lchown'),
...syncAndAsyncAPI('lchmod'),
...syncAndAsyncAPI('link'),
...syncAndAsyncAPI('lutimes'),
...syncAndAsyncAPI('mkdir'),
...syncAndAsyncAPI('mkdtemp'),
...syncAndAsyncAPI('open'),
'openAsBlob',
...syncAndAsyncAPI('mkdtemp'),
...syncAndAsyncAPI('readdir'),
...syncAndAsyncAPI('readFile'),
...syncAndAsyncAPI('readlink'),
...syncAndAsyncAPI('rename'),
...syncAndAsyncAPI('rm'),
...syncAndAsyncAPI('rmdir'),
...syncAndAsyncAPI('stat'),
...syncAndAsyncAPI('statfs'),
...syncAndAsyncAPI('statfs'),
...syncAndAsyncAPI('symlink'),
...syncAndAsyncAPI('truncate'),
...syncAndAsyncAPI('unlink'),
...syncAndAsyncAPI('utimes'),
'watch',
'watchFile',
...syncAndAsyncAPI('writeFile'),
...syncAndAsyncAPI('opendir'),
];
// Non functions
const ignoreList = [
'constants',
'promises',
'X_OK',
'W_OK',
'R_OK',
'F_OK',
'Dir',
'FileReadStream',
'FileWriteStream',
'_toUnixTimestamp',
'Stats',
'ReadStream',
'WriteStream',
'Dirent',
// fs.watch is already blocked
'unwatchFile',
...syncAndAsyncAPI('lstat'),
...syncAndAsyncAPI('realpath'),
// fd required methods
...syncAndAsyncAPI('close'),
...syncAndAsyncAPI('fchown'),
...syncAndAsyncAPI('fchmod'),
...syncAndAsyncAPI('fdatasync'),
...syncAndAsyncAPI('fstat'),
...syncAndAsyncAPI('fsync'),
...syncAndAsyncAPI('ftruncate'),
...syncAndAsyncAPI('futimes'),
...syncAndAsyncAPI('read'),
...syncAndAsyncAPI('readv'),
...syncAndAsyncAPI('write'),
...syncAndAsyncAPI('writev'),
...syncAndAsyncAPI('glob'),
];
{
const fsList = Object.keys(require('fs'));
for (const k of fsList) {
if (!supportedApis.includes(k) && !ignoreList.includes(k)) {
assert.fail(`fs.${k} was exposed but is neither on the supported list ` +
'of the permission model nor on the ignore list.');
}
}
}

View File

@@ -0,0 +1,23 @@
'use strict';
// Flags: --expose-gc
require('../common');
const { onGC } = require('../common/gc');
// See https://github.com/nodejs/node/issues/53335
const poller = setInterval(() => {
globalThis.gc();
}, 100);
let count = 0;
for (let i = 0; i < 10; i++) {
const timer = setTimeout(() => {}, 0);
onGC(timer, {
ongc: () => {
if (++count === 10) {
clearInterval(poller);
}
}
});
console.log(+timer);
}

View File

@@ -0,0 +1,31 @@
'use strict';
// Refs: https://github.com/nodejs/node/issues/947
const common = require('../common');
const assert = require('assert');
const cp = require('child_process');
if (process.argv[2] === 'child') {
process.on('message', common.mustCall((msg) => {
assert.strictEqual(msg, 'go');
// The following console.log is an integral part
// of the test. If this regress, this call will
// cause the process to exit with 1
console.log('logging should not cause a crash');
process.disconnect();
}));
} else {
// Passing '--inspect', '--inspect-brk' to child.spawn enables
// the debugger. This test was added to help debug the fork-based
// test with the same name.
const child = cp.spawn(process.execPath, [__filename, 'child'], {
stdio: ['pipe', 'pipe', 'pipe', 'ipc']
});
child.on('close', common.mustCall((exitCode, signal) => {
assert.strictEqual(exitCode, 0);
assert.strictEqual(signal, null);
}));
child.stdout.destroy();
child.send('go');
}

View File

@@ -0,0 +1,26 @@
'use strict';
// Refs: https://github.com/nodejs/node/issues/947
const common = require('../common');
const assert = require('assert');
const cp = require('child_process');
if (process.argv[2] === 'child') {
process.on('message', common.mustCall((msg) => {
assert.strictEqual(msg, 'go');
// The following console.log is an integral part
// of the test. If this regress, this call will
// cause the process to exit with 1
console.log('logging should not cause a crash');
process.disconnect();
}));
} else {
const child = cp.fork(__filename, ['child'], { silent: true });
child.on('close', common.mustCall((exitCode, signal) => {
assert.strictEqual(exitCode, 0);
assert.strictEqual(signal, null);
}));
child.stdout.destroy();
child.send('go');
}

View File

@@ -0,0 +1,58 @@
'use strict';
const common = require('../common');
const assert = require('assert');
const { Readable } = require('stream');
const readline = require('readline');
const CONTENT = 'content';
const LINES_PER_PUSH = 2051;
const REPETITIONS = 3;
(async () => {
const readable = new Readable({ read() {} });
let salt = 0;
for (let i = 0; i < REPETITIONS; i++) {
readable.push(`${CONTENT}\n`.repeat(LINES_PER_PUSH + i));
salt += i;
}
const TOTAL_LINES = LINES_PER_PUSH * REPETITIONS + salt;
const rli = readline.createInterface({
input: readable,
crlfDelay: Infinity
});
const it = rli[Symbol.asyncIterator]();
const watermarkData = it[Symbol.for('nodejs.watermarkData')];
const highWaterMark = watermarkData.high;
// For this test to work, we have to queue up more than the number of
// highWaterMark items in rli. Make sure that is the case.
assert(TOTAL_LINES > highWaterMark, `TOTAL_LINES (${TOTAL_LINES}) isn't greater than highWaterMark (${highWaterMark})`);
let iterations = 0;
let readableEnded = false;
let notPaused = 0;
for await (const line of it) {
assert.strictEqual(readableEnded, false);
assert.strictEqual(line, CONTENT);
assert.ok(watermarkData.size <= TOTAL_LINES);
assert.strictEqual(readable.isPaused(), watermarkData.size >= 1);
if (!readable.isPaused()) {
notPaused++;
}
iterations += 1;
// We have to end the input stream asynchronously for back pressure to work.
// Only end when we have reached the final line.
if (iterations === TOTAL_LINES) {
readable.push(null);
readableEnded = true;
}
}
assert.strictEqual(iterations, TOTAL_LINES);
assert.strictEqual(notPaused, REPETITIONS);
})().then(common.mustCall());

View File

@@ -0,0 +1,53 @@
// Flags: --experimental-shadow-realm
'use strict';
require('../common');
const assert = require('assert');
let principalRealmPrepareStackTraceCalled = false;
Error.prepareStackTrace = (error, trace) => {
principalRealmPrepareStackTraceCalled = true;
return `${String(error)}\n at ${trace.join('\n at ')}`;
};
{
// Validates inner Error.prepareStackTrace can not leak into the outer realm.
const shadowRealm = new ShadowRealm();
const stack = shadowRealm.evaluate(`
Error.prepareStackTrace = (error, trace) => {
globalThis.leaked = 'inner';
return 'from shadow realm';
};
try {
throw new Error('boom');
} catch (e) {
e.stack;
}
`);
assert.ok(!principalRealmPrepareStackTraceCalled);
assert.strictEqual(stack, 'from shadow realm');
assert.strictEqual('leaked' in globalThis, false);
}
{
// Validates stacks can be generated in the ShadowRealm.
const shadowRealm = new ShadowRealm();
const stack = shadowRealm.evaluate(`
function myFunc() {
throw new Error('boom');
}
try {
myFunc();
} catch (e) {
e.stack;
}
`);
assert.ok(!principalRealmPrepareStackTraceCalled);
const lines = stack.split('\n');
assert.strictEqual(lines[0], 'Error: boom');
assert.match(lines[1], /^ {4}at myFunc \(.*\)/);
}

View File

@@ -0,0 +1,27 @@
'use strict';
require('../common');
const assert = require('assert');
const net = require('net');
{
const invalidKeys = [
'objectMode',
'readableObjectMode',
'writableObjectMode',
];
invalidKeys.forEach((invalidKey) => {
const option = {
[invalidKey]: true
};
const message = `The property 'options.${invalidKey}' is not supported. Received true`;
assert.throws(() => {
const socket = new net.Socket(option);
socket.connect({ port: 8080 });
}, {
code: 'ERR_INVALID_ARG_VALUE',
name: 'TypeError',
message: new RegExp(message)
});
});
}

View File

@@ -0,0 +1,62 @@
'use strict';
require('../common');
const assert = require('assert');
// This is similar to simple/test-socket-write-after-fin, except that
// we don't set allowHalfOpen. Then we write after the client has sent
// a FIN, and this is an error. However, the standard "write after end"
// message is too vague, and doesn't actually tell you what happens.
const net = require('net');
let serverData = '';
let gotServerEnd = false;
let clientData = '';
let gotClientEnd = false;
let gotServerError = false;
const server = net.createServer(function(sock) {
sock.setEncoding('utf8');
sock.on('error', function() {});
sock.on('data', function(c) {
serverData += c;
});
sock.on('end', function() {
gotServerEnd = true;
setImmediate(() => {
sock.write(serverData, function(er) {
console.error(`${er.code}: ${er.message}`);
gotServerError = er;
});
sock.end();
});
});
server.close();
});
server.listen(0, function() {
const sock = net.connect(this.address().port);
sock.setEncoding('utf8');
sock.on('data', function(c) {
clientData += c;
});
sock.on('end', function() {
gotClientEnd = true;
});
process.on('exit', function() {
assert.strictEqual(clientData, '');
assert.strictEqual(serverData, 'hello1hello2hello3\nTHUNDERMUSCLE!');
assert(gotClientEnd);
assert(gotServerEnd);
assert(gotServerError);
assert.strictEqual(gotServerError.code, 'EPIPE');
assert.notStrictEqual(gotServerError.message, 'write after end');
console.log('ok');
});
sock.write('hello1');
sock.write('hello2');
sock.write('hello3\n');
sock.end('THUNDERMUSCLE!');
});

View File

@@ -0,0 +1,702 @@
'use strict';
const common = require('../common');
const {
Writable,
Readable,
Transform,
finished,
Duplex,
PassThrough,
Stream,
} = require('stream');
const assert = require('assert');
const EE = require('events');
const fs = require('fs');
const { promisify } = require('util');
const http = require('http');
{
const rs = new Readable({
read() {}
});
finished(rs, common.mustSucceed());
rs.push(null);
rs.resume();
}
{
const ws = new Writable({
write(data, enc, cb) {
cb();
}
});
finished(ws, common.mustSucceed());
ws.end();
}
{
const tr = new Transform({
transform(data, enc, cb) {
cb();
}
});
let finish = false;
let ended = false;
tr.on('end', () => {
ended = true;
});
tr.on('finish', () => {
finish = true;
});
finished(tr, common.mustSucceed(() => {
assert(finish);
assert(ended);
}));
tr.end();
tr.resume();
}
{
const rs = fs.createReadStream(__filename);
rs.resume();
finished(rs, common.mustCall());
}
{
const finishedPromise = promisify(finished);
async function run() {
const rs = fs.createReadStream(__filename);
const done = common.mustCall();
let ended = false;
rs.resume();
rs.on('end', () => {
ended = true;
});
await finishedPromise(rs);
assert(ended);
done();
}
run();
}
{
// Check pre-cancelled
const signal = new EventTarget();
signal.aborted = true;
const rs = Readable.from((function* () {})());
finished(rs, { signal }, common.mustCall((err) => {
assert.strictEqual(err.name, 'AbortError');
}));
}
{
// Check cancelled before the stream ends sync.
const ac = new AbortController();
const { signal } = ac;
const rs = Readable.from((function* () {})());
finished(rs, { signal }, common.mustCall((err) => {
assert.strictEqual(err.name, 'AbortError');
}));
ac.abort();
}
{
// Check cancelled before the stream ends async.
const ac = new AbortController();
const { signal } = ac;
const rs = Readable.from((function* () {})());
setTimeout(() => ac.abort(), 1);
finished(rs, { signal }, common.mustCall((err) => {
assert.strictEqual(err.name, 'AbortError');
}));
}
{
// Check cancelled after doesn't throw.
const ac = new AbortController();
const { signal } = ac;
const rs = Readable.from((function* () {
yield 5;
setImmediate(() => ac.abort());
})());
rs.resume();
finished(rs, { signal }, common.mustSucceed());
}
{
// Promisified abort works
const finishedPromise = promisify(finished);
async function run() {
const ac = new AbortController();
const { signal } = ac;
const rs = Readable.from((function* () {})());
setImmediate(() => ac.abort());
await finishedPromise(rs, { signal });
}
assert.rejects(run, { name: 'AbortError' }).then(common.mustCall());
}
{
// Promisified pre-aborted works
const finishedPromise = promisify(finished);
async function run() {
const signal = new EventTarget();
signal.aborted = true;
const rs = Readable.from((function* () {})());
await finishedPromise(rs, { signal });
}
assert.rejects(run, { name: 'AbortError' }).then(common.mustCall());
}
{
const rs = fs.createReadStream('file-does-not-exist');
finished(rs, common.expectsError({
code: 'ENOENT'
}));
}
{
const rs = new Readable();
finished(rs, common.mustSucceed());
rs.push(null);
rs.emit('close'); // Should not trigger an error
rs.resume();
}
{
const rs = new Readable();
finished(rs, common.mustCall((err) => {
assert(err, 'premature close error');
}));
rs.emit('close'); // Should trigger error
rs.push(null);
rs.resume();
}
// Test faulty input values and options.
{
const rs = new Readable({
read() {}
});
assert.throws(
() => finished(rs, 'foo'),
{
code: 'ERR_INVALID_ARG_TYPE',
message: /callback/
}
);
assert.throws(
() => finished(rs, 'foo', () => {}),
{
code: 'ERR_INVALID_ARG_TYPE',
message: /options/
}
);
assert.throws(
() => finished(rs, {}, 'foo'),
{
code: 'ERR_INVALID_ARG_TYPE',
message: /callback/
}
);
finished(rs, null, common.mustCall());
rs.push(null);
rs.resume();
}
// Test that calling returned function removes listeners
{
const ws = new Writable({
write(data, env, cb) {
cb();
}
});
const removeListener = finished(ws, common.mustNotCall());
removeListener();
ws.end();
}
{
const rs = new Readable();
const removeListeners = finished(rs, common.mustNotCall());
removeListeners();
rs.emit('close');
rs.push(null);
rs.resume();
}
{
const streamLike = new EE();
streamLike.readableEnded = true;
streamLike.readable = true;
assert.throws(
() => {
finished(streamLike, () => {});
},
{ code: 'ERR_INVALID_ARG_TYPE' }
);
streamLike.emit('close');
}
{
const writable = new Writable({ write() {} });
writable.writable = false;
writable.destroy();
finished(writable, common.mustCall((err) => {
assert.strictEqual(err.code, 'ERR_STREAM_PREMATURE_CLOSE');
}));
}
{
const readable = new Readable();
readable.readable = false;
readable.destroy();
finished(readable, common.mustCall((err) => {
assert.strictEqual(err.code, 'ERR_STREAM_PREMATURE_CLOSE');
}));
}
{
const w = new Writable({
write(chunk, encoding, callback) {
setImmediate(callback);
}
});
finished(w, common.mustCall((err) => {
assert.strictEqual(err.code, 'ERR_STREAM_PREMATURE_CLOSE');
}));
w.end('asd');
w.destroy();
}
function testClosed(factory) {
{
// If already destroyed but finished is cancelled in same tick
// don't invoke the callback,
const s = factory();
s.destroy();
const dispose = finished(s, common.mustNotCall());
dispose();
}
{
// If already destroyed invoked callback.
const s = factory();
s.destroy();
finished(s, common.mustCall());
}
{
// Don't invoke until destroy has completed.
let destroyed = false;
const s = factory({
destroy(err, cb) {
setImmediate(() => {
destroyed = true;
cb();
});
}
});
s.destroy();
finished(s, common.mustCall(() => {
assert.strictEqual(destroyed, true);
}));
}
{
// Invoke callback even if close is inhibited.
const s = factory({
emitClose: false,
destroy(err, cb) {
cb();
finished(s, common.mustCall());
}
});
s.destroy();
}
{
// Invoke with deep async.
const s = factory({
destroy(err, cb) {
setImmediate(() => {
cb();
setImmediate(() => {
finished(s, common.mustCall());
});
});
}
});
s.destroy();
}
}
testClosed((opts) => new Readable({ ...opts }));
testClosed((opts) => new Writable({ write() {}, ...opts }));
{
const w = new Writable({
write(chunk, encoding, cb) {
cb();
},
autoDestroy: false
});
w.end('asd');
process.nextTick(() => {
finished(w, common.mustCall());
});
}
{
const w = new Writable({
write(chunk, encoding, cb) {
cb(new Error());
},
autoDestroy: false
});
w.write('asd');
w.on('error', common.mustCall(() => {
finished(w, common.mustCall());
}));
}
{
const r = new Readable({
autoDestroy: false
});
r.push(null);
r.resume();
r.on('end', common.mustCall(() => {
finished(r, common.mustCall());
}));
}
{
const rs = fs.createReadStream(__filename, { autoClose: false });
rs.resume();
rs.on('close', common.mustNotCall());
rs.on('end', common.mustCall(() => {
finished(rs, common.mustCall());
}));
}
{
const d = new EE();
d._writableState = {};
d._writableState.finished = true;
finished(d, { readable: false, writable: true }, common.mustCall((err) => {
assert.strictEqual(err.code, 'ERR_STREAM_PREMATURE_CLOSE');
}));
d._writableState.errored = true;
d.emit('close');
}
{
const r = new Readable();
finished(r, common.mustCall((err) => {
assert.strictEqual(err.code, 'ERR_STREAM_PREMATURE_CLOSE');
}));
r.push('asd');
r.push(null);
r.destroy();
}
{
const d = new Duplex({
final(cb) { }, // Never close writable side for test purpose
read() {
this.push(null);
}
});
d.on('end', common.mustCall());
finished(d, { readable: true, writable: false }, common.mustCall());
d.end();
d.resume();
}
{
const d = new Duplex({
final(cb) { }, // Never close writable side for test purpose
read() {
this.push(null);
}
});
d.on('end', common.mustCall());
d.end();
finished(d, { readable: true, writable: false }, common.mustCall());
d.resume();
}
{
// Test for compat for e.g. fd-slicer which implements
// non standard destroy behavior which might not emit
// 'close'.
const r = new Readable();
finished(r, common.mustCall());
r.resume();
r.push('asd');
r.destroyed = true;
r.push(null);
}
{
// Regression https://github.com/nodejs/node/issues/33130
const response = new PassThrough();
class HelloWorld extends Duplex {
constructor(response) {
super({
autoDestroy: false
});
this.response = response;
this.readMore = false;
response.once('end', () => {
this.push(null);
});
response.on('readable', () => {
if (this.readMore) {
this._read();
}
});
}
_read() {
const { response } = this;
this.readMore = true;
if (response.readableLength) {
this.readMore = false;
}
let data;
while ((data = response.read()) !== null) {
this.push(data);
}
}
}
const instance = new HelloWorld(response);
instance.setEncoding('utf8');
instance.end();
(async () => {
await EE.once(instance, 'finish');
setImmediate(() => {
response.write('chunk 1');
response.write('chunk 2');
response.write('chunk 3');
response.end();
});
let res = '';
for await (const data of instance) {
res += data;
}
assert.strictEqual(res, 'chunk 1chunk 2chunk 3');
})().then(common.mustCall());
}
{
const p = new PassThrough();
p.end();
finished(p, common.mustNotCall());
}
{
const p = new PassThrough();
p.end();
p.on('finish', common.mustCall(() => {
finished(p, common.mustNotCall());
}));
}
{
const server = http.createServer(common.mustCall((req, res) => {
res.on('close', common.mustCall(() => {
finished(res, common.mustCall(() => {
server.close();
}));
}));
res.end();
}))
.listen(0, function() {
http.request({
method: 'GET',
port: this.address().port
}).end()
.on('response', common.mustCall());
});
}
{
const server = http.createServer(common.mustCall((req, res) => {
req.on('close', common.mustCall(() => {
finished(req, common.mustCall(() => {
server.close();
}));
}));
req.destroy();
})).listen(0, function() {
http.request({
method: 'GET',
port: this.address().port
}).end().on('error', common.mustCall());
});
}
{
const w = new Writable({
write(chunk, encoding, callback) {
process.nextTick(callback);
}
});
w.aborted = false;
w.end();
let closed = false;
w.on('finish', () => {
assert.strictEqual(closed, false);
w.emit('aborted');
});
w.on('close', common.mustCall(() => {
closed = true;
}));
finished(w, common.mustCall(() => {
assert.strictEqual(closed, true);
}));
}
{
const w = new Writable();
const _err = new Error();
w.destroy(_err);
assert.strictEqual(w.errored, _err);
finished(w, common.mustCall((err) => {
assert.strictEqual(_err, err);
assert.strictEqual(w.closed, true);
finished(w, common.mustCall((err) => {
assert.strictEqual(_err, err);
}));
}));
}
{
const w = new Writable();
w.destroy();
assert.strictEqual(w.errored, null);
finished(w, common.mustCall((err) => {
assert.strictEqual(w.closed, true);
assert.strictEqual(err.code, 'ERR_STREAM_PREMATURE_CLOSE');
finished(w, common.mustCall((err) => {
assert.strictEqual(err.code, 'ERR_STREAM_PREMATURE_CLOSE');
}));
}));
}
{
// Legacy Streams do not inherit from Readable or Writable.
// We cannot really assume anything about them, so we cannot close them
// automatically.
const s = new Stream();
finished(s, common.mustNotCall());
}
{
const server = http.createServer(common.mustCall(function(req, res) {
fs.createReadStream(__filename).pipe(res);
finished(res, common.mustCall(function(err) {
assert.strictEqual(err, undefined);
}));
})).listen(0, function() {
http.request(
{ method: 'GET', port: this.address().port },
common.mustCall(function(res) {
res.resume();
finished(res, common.mustCall(() => {
server.close();
}));
})
).end();
});
}
{
let isCalled = false;
const stream = new Duplex({
write(chunk, enc, cb) {
setImmediate(() => {
isCalled = true;
cb();
});
}
});
stream.end('foo');
finished(stream, { readable: false }, common.mustCall((err) => {
assert(!err);
assert.strictEqual(isCalled, true);
assert.strictEqual(stream._writableState.pendingcb, 0);
}));
}
{
const stream = new Duplex({
write(chunk, enc, cb) {}
});
stream.end('foo');
// Simulate an old stream implementation that doesn't have pendingcb
delete stream._writableState.pendingcb;
finished(stream, { readable: false }, common.mustCall());
}

View File

@@ -0,0 +1,32 @@
'use strict';
const common = require('../common');
const assert = require('assert');
const OVERFLOW = Math.pow(2, 31); // TIMEOUT_MAX is 2^31-1
function timerNotCanceled() {
assert.fail('Timer should be canceled');
}
process.on('warning', common.mustCall((warning) => {
if (warning.name === 'DeprecationWarning') return;
const lines = warning.message.split('\n');
assert.strictEqual(warning.name, 'TimeoutOverflowWarning');
assert.strictEqual(lines[0], `${OVERFLOW} does not fit into a 32-bit signed` +
' integer.');
assert.strictEqual(lines.length, 2);
}, 2));
{
const timeout = setTimeout(timerNotCanceled, OVERFLOW);
clearTimeout(timeout);
}
{
const interval = setInterval(timerNotCanceled, OVERFLOW);
clearInterval(interval);
}

View File

@@ -0,0 +1,32 @@
'use strict';
const common = require('../common');
if (!common.hasCrypto) {
common.skip('missing crypto');
}
const { hasOpenSSL3 } = require('../common/crypto');
if (!hasOpenSSL3) {
common.skip('OpenSSL legacy failures are only testable with OpenSSL 3+');
}
const fixtures = require('../common/fixtures');
const {
assert, connect, keys
} = require(fixtures.path('tls-connect'));
const legacyPfx = fixtures.readKey('legacy.pfx');
connect({
client: {
pfx: legacyPfx,
passphrase: 'legacy',
rejectUnauthorized: false
},
server: keys.agent1
}, common.mustCall((e, pair, cleanup) => {
assert.strictEqual(e.code, 'ERR_CRYPTO_UNSUPPORTED_OPERATION');
assert.strictEqual(e.message, 'Unsupported PKCS12 PFX data');
cleanup();
}));

View File

@@ -0,0 +1,48 @@
// 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';
require('../common');
// This test ensures piping from `stdin` isn't broken.
// https://github.com/nodejs/node/issues/5927
const assert = require('assert');
const readline = require('readline');
const rl = readline.createInterface(process.stdin, process.stdout);
rl.resume();
let hasPaused = false;
const origPause = rl.pause;
rl.pause = function() {
hasPaused = true;
origPause.apply(this, arguments);
};
const origSetRawMode = rl._setRawMode;
rl._setRawMode = function(mode) {
assert.ok(hasPaused);
origSetRawMode.apply(this, arguments);
};
rl.close();

View File

@@ -0,0 +1,10 @@
// Flags: --v8-pool-size=0 --expose-gc
'use strict';
require('../common');
// This verifies that V8 tasks scheduled by GC are handled on worker threads if
// `--v8-pool-size=0` is given. The worker threads are managed by Node.js'
// `v8::Platform` implementation.
globalThis.gc();

View File

@@ -0,0 +1,9 @@
'use strict';
require('../common');
const v8 = require('v8');
// Regression test for https://github.com/nodejs/node/issues/35559
// It is important that the return value of the first call is not used, i.e.
// that the first snapshot is GC-able while the second one is being created.
v8.getHeapSnapshot();
v8.getHeapSnapshot();

View File

@@ -0,0 +1,107 @@
// 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';
require('../common');
const assert = require('assert');
const Script = require('vm').Script;
{
const script = new Script('\'passed\';');
const result1 = script.runInNewContext();
const result2 = script.runInNewContext();
assert.strictEqual(result1, 'passed');
assert.strictEqual(result2, 'passed');
}
{
const script = new Script('throw new Error(\'test\');');
assert.throws(() => {
script.runInNewContext();
}, /^Error: test$/);
}
{
const script = new Script('foo.bar = 5;');
assert.throws(() => {
script.runInNewContext();
}, /^ReferenceError: foo is not defined$/);
}
{
globalThis.hello = 5;
const script = new Script('hello = 2');
script.runInNewContext();
assert.strictEqual(globalThis.hello, 5);
// Cleanup
delete globalThis.hello;
}
{
globalThis.code = 'foo = 1;' +
'bar = 2;' +
'if (baz !== 3) throw new Error(\'test fail\');';
globalThis.foo = 2;
globalThis.obj = { foo: 0, baz: 3 };
const script = new Script(globalThis.code);
/* eslint-disable no-unused-vars */
const baz = script.runInNewContext(globalThis.obj);
/* eslint-enable no-unused-vars */
assert.strictEqual(globalThis.obj.foo, 1);
assert.strictEqual(globalThis.obj.bar, 2);
assert.strictEqual(globalThis.foo, 2);
// cleanup
delete globalThis.code;
delete globalThis.foo;
delete globalThis.obj;
}
{
const script = new Script('f()');
function changeFoo() { globalThis.foo = 100; }
script.runInNewContext({ f: changeFoo });
assert.strictEqual(globalThis.foo, 100);
// cleanup
delete globalThis.foo;
}
{
const script = new Script('f.a = 2');
const f = { a: 1 };
script.runInNewContext({ f });
assert.strictEqual(f.a, 2);
assert.throws(() => {
script.runInNewContext();
}, /^ReferenceError: f is not defined$/);
}
{
const script = new Script('');
assert.throws(() => {
script.runInNewContext.call('\'hello\';');
}, /^TypeError: this\.runInContext is not a function$/);
}

View File

@@ -0,0 +1,26 @@
'use strict';
require('../common');
const vm = require('node:vm');
const util = require('node:util');
const assert = require('node:assert');
// This verifies that invoking property getters defined with
// `require('internal/util').defineLazyProperties` does not crash
// the process.
const ctx = vm.createContext();
const getter = vm.runInContext(`
function getter(object, property) {
return object[property];
}
getter;
`, ctx);
// `util.parseArgs` is a lazy property.
const parseArgs = getter(util, 'parseArgs');
assert.strictEqual(parseArgs, util.parseArgs);
// `globalThis.TextEncoder` is a lazy property.
const TextEncoder = getter(globalThis, 'TextEncoder');
assert.strictEqual(TextEncoder, globalThis.TextEncoder);

View File

@@ -0,0 +1,23 @@
'use strict';
const common = require('../common');
const { Resolver } = require('dns');
const dgram = require('dgram');
const { Worker, isMainThread } = require('worker_threads');
// Test that Workers can terminate while DNS queries are outstanding.
if (isMainThread) {
return new Worker(__filename);
}
const socket = dgram.createSocket('udp4');
socket.bind(0, common.mustCall(() => {
const resolver = new Resolver();
resolver.setServers([`127.0.0.1:${socket.address().port}`]);
resolver.resolve4('example.org', common.mustNotCall());
}));
socket.on('message', common.mustCall(() => {
process.exit();
}));

View File

@@ -0,0 +1,17 @@
'use strict';
const common = require('../common');
const assert = require('assert');
const { getHeapSnapshot } = require('v8');
const { isMainThread, Worker } = require('worker_threads');
// Checks taking heap snapshot at the exit event listener of Worker doesn't
// crash the process.
// Regression for https://github.com/nodejs/node/issues/43122.
if (isMainThread) {
const worker = new Worker(__filename);
worker.once('exit', common.mustCall((code) => {
assert.strictEqual(code, 0);
getHeapSnapshot().pipe(process.stdout);
}));
}

View File

@@ -0,0 +1,17 @@
'use strict';
const common = require('../common');
const { Worker, parentPort } = require('worker_threads');
const fs = require('fs');
// Checks that terminating Workers does not crash the process if fs.watchFile()
// has active handles.
// Do not use isMainThread so that this test itself can be run inside a Worker.
if (!process.env.HAS_STARTED_WORKER) {
process.env.HAS_STARTED_WORKER = 1;
const worker = new Worker(__filename);
worker.on('message', common.mustCall(() => worker.terminate()));
} else {
fs.watchFile(__filename, () => {});
parentPort.postMessage('running');
}

View File

@@ -0,0 +1,53 @@
'use strict';
const common = require('../common');
const assert = require('assert');
const { MessageChannel, Worker } = require('worker_threads');
// Test that SharedArrayBuffer instances created from WASM are transferable
// through MessageChannels (without crashing).
const fixtures = require('../common/fixtures');
const wasmSource = fixtures.readSync('shared-memory.wasm');
const wasmModule = new WebAssembly.Module(wasmSource);
const instance = new WebAssembly.Instance(wasmModule);
const { buffer } = instance.exports.memory;
assert(buffer instanceof SharedArrayBuffer);
{
const { port1, port2 } = new MessageChannel();
port1.postMessage(buffer);
port2.once('message', common.mustCall((buffer2) => {
// Make sure serialized + deserialized buffer refer to the same memory.
const expected = 'Hello, world!';
const bytes = Buffer.from(buffer).write(expected);
const deserialized = Buffer.from(buffer2).toString('utf8', 0, bytes);
assert.deepStrictEqual(deserialized, expected);
}));
}
{
// Make sure we can free WASM memory originating from a thread that already
// stopped when we exit.
const worker = new Worker(`
const { parentPort } = require('worker_threads');
// Compile the same WASM module from its source bytes.
const wasmSource = new Uint8Array([${wasmSource.join(',')}]);
const wasmModule = new WebAssembly.Module(wasmSource);
const instance = new WebAssembly.Instance(wasmModule);
parentPort.postMessage(instance.exports.memory);
// Do the same thing, except we receive the WASM module via transfer.
parentPort.once('message', ({ wasmModule }) => {
const instance = new WebAssembly.Instance(wasmModule);
parentPort.postMessage(instance.exports.memory);
});
`, { eval: true });
worker.on('message', common.mustCall(({ buffer }) => {
assert(buffer instanceof SharedArrayBuffer);
worker.buf = buffer; // Basically just keep the reference to buffer alive.
}, 2));
worker.once('exit', common.mustCall());
worker.postMessage({ wasmModule });
}

View File

@@ -0,0 +1,39 @@
'use strict';
const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');
const assert = require('assert');
const http2 = require('http2');
const { duplexPair } = require('stream');
const { Worker, isMainThread } = require('worker_threads');
// This is a variant of test-http2-generic-streams-sendfile for checking
// that Workers can be terminated during a .respondWithFile() operation.
if (isMainThread) {
return new Worker(__filename);
}
{
const server = http2.createServer();
server.on('stream', common.mustCall((stream, headers) => {
stream.respondWithFile(process.execPath); // Use a large-ish file.
}));
const [ clientSide, serverSide ] = duplexPair();
server.emit('connection', serverSide);
const client = http2.connect('http://localhost:80', {
createConnection: common.mustCall(() => clientSide)
});
const req = client.request();
req.on('response', common.mustCall((headers) => {
assert.strictEqual(headers[':status'], 200);
}));
req.on('data', common.mustCall(() => process.exit()));
req.on('end', common.mustNotCall());
req.end();
}