mirror of
https://github.com/oven-sh/bun
synced 2026-02-02 15:08:46 +00:00
fix(node): add all already-passing tests (#18299)
This commit is contained in:
1
test/js/node/test/.gitignore
vendored
1
test/js/node/test/.gitignore
vendored
@@ -7,5 +7,6 @@ fixtures/snapshot
|
||||
fixtures/repl*
|
||||
.tmp.*
|
||||
*shadow-realm*
|
||||
!test-shadow-realm-prepare-stack-trace.js
|
||||
!test-shadow-realm.js
|
||||
**/fails.txt
|
||||
|
||||
@@ -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();
|
||||
}));
|
||||
22
test/js/node/test/parallel/test-cli-options-precedence.js
Normal file
22
test/js/node/test/parallel/test-cli-options-precedence.js
Normal 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');
|
||||
51
test/js/node/test/parallel/test-cluster-dgram-ipv6only.js
Normal file
51
test/js/node/test/parallel/test-cluster-dgram-ipv6only.js
Normal 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);
|
||||
});
|
||||
}));
|
||||
}));
|
||||
}
|
||||
35
test/js/node/test/parallel/test-cluster-dgram-reuse.js
Normal file
35
test/js/node/test/parallel/test-cluster-dgram-reuse.js
Normal 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);
|
||||
});
|
||||
});
|
||||
});
|
||||
39
test/js/node/test/parallel/test-cluster-dgram-reuseport.js
Normal file
39
test/js/node/test/parallel/test-cluster-dgram-reuseport.js
Normal 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);
|
||||
});
|
||||
});
|
||||
@@ -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');
|
||||
}
|
||||
52
test/js/node/test/parallel/test-common-expect-warning.js
Normal file
52
test/js/node/test/parallel/test-common-expect-warning.js
Normal 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');
|
||||
}
|
||||
}
|
||||
44
test/js/node/test/parallel/test-config-json-schema.js
Normal file
44
test/js/node/test/parallel/test-config-json-schema.js
Normal 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.');
|
||||
21
test/js/node/test/parallel/test-debug-process.js
Normal file
21
test/js/node/test/parallel/test-debug-process.js
Normal 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.');
|
||||
}
|
||||
}));
|
||||
@@ -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/);
|
||||
}
|
||||
@@ -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);
|
||||
})
|
||||
);
|
||||
@@ -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'
|
||||
},
|
||||
]
|
||||
});
|
||||
83
test/js/node/test/parallel/test-file-write-stream.js
Normal file
83
test/js/node/test/parallel/test-file-write-stream.js
Normal 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');
|
||||
});
|
||||
@@ -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();
|
||||
});
|
||||
27
test/js/node/test/parallel/test-fs-symlink-longpath.js
Normal file
27
test/js/node/test/parallel/test-fs-symlink-longpath.js
Normal 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));
|
||||
}));
|
||||
35
test/js/node/test/parallel/test-fs-write-stream-encoding.js
Normal file
35
test/js/node/test/parallel/test-fs-write-stream-encoding.js
Normal 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);
|
||||
});
|
||||
@@ -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);
|
||||
}
|
||||
46
test/js/node/test/parallel/test-inspector-strip-types.js
Normal file
46
test/js/node/test/parallel/test-inspector-strip-types.js
Normal 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());
|
||||
@@ -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();
|
||||
}
|
||||
17
test/js/node/test/parallel/test-math-random.js
Normal file
17
test/js/node/test/parallel/test-math-random.js
Normal 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);
|
||||
105
test/js/node/test/parallel/test-module-strip-types.js
Normal file
105
test/js/node/test/parallel/test-module-strip-types.js
Normal 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}`);
|
||||
});
|
||||
@@ -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');
|
||||
}));
|
||||
}));
|
||||
}
|
||||
33
test/js/node/test/parallel/test-net-sync-cork.js
Normal file
33
test/js/node/test/parallel/test-net-sync-cork.js
Normal 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()));
|
||||
}
|
||||
@@ -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();
|
||||
}));
|
||||
}));
|
||||
@@ -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();
|
||||
}));
|
||||
}));
|
||||
104
test/js/node/test/parallel/test-permission-fs-supported.js
Normal file
104
test/js/node/test/parallel/test-permission-fs-supported.js
Normal 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.');
|
||||
}
|
||||
}
|
||||
}
|
||||
23
test/js/node/test/parallel/test-primitive-timer-leak.js
Normal file
23
test/js/node/test/parallel/test-primitive-timer-leak.js
Normal 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);
|
||||
}
|
||||
@@ -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');
|
||||
}
|
||||
@@ -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');
|
||||
}
|
||||
@@ -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());
|
||||
@@ -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 \(.*\)/);
|
||||
}
|
||||
27
test/js/node/test/parallel/test-socket-options-invalid.js
Normal file
27
test/js/node/test/parallel/test-socket-options-invalid.js
Normal 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)
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -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!');
|
||||
});
|
||||
702
test/js/node/test/parallel/test-stream-finished.js
Normal file
702
test/js/node/test/parallel/test-stream-finished.js
Normal 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());
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
32
test/js/node/test/parallel/test-tls-legacy-pfx.js
Normal file
32
test/js/node/test/parallel/test-tls-legacy-pfx.js
Normal 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();
|
||||
}));
|
||||
48
test/js/node/test/parallel/test-tty-stdin-pipe.js
Normal file
48
test/js/node/test/parallel/test-tty-stdin-pipe.js
Normal 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();
|
||||
10
test/js/node/test/parallel/test-v8-flag-pool-size-0.js
Normal file
10
test/js/node/test/parallel/test-v8-flag-pool-size-0.js
Normal 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();
|
||||
@@ -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();
|
||||
107
test/js/node/test/parallel/test-vm-new-script-new-context.js
Normal file
107
test/js/node/test/parallel/test-vm-new-script-new-context.js
Normal 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$/);
|
||||
}
|
||||
26
test/js/node/test/parallel/test-vm-util-lazy-properties.js
Normal file
26
test/js/node/test/parallel/test-vm-util-lazy-properties.js
Normal 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);
|
||||
@@ -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();
|
||||
}));
|
||||
17
test/js/node/test/parallel/test-worker-exit-heapsnapshot.js
Normal file
17
test/js/node/test/parallel/test-worker-exit-heapsnapshot.js
Normal 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);
|
||||
}));
|
||||
}
|
||||
17
test/js/node/test/parallel/test-worker-fs-stat-watcher.js
Normal file
17
test/js/node/test/parallel/test-worker-fs-stat-watcher.js
Normal 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');
|
||||
}
|
||||
@@ -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 });
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
Reference in New Issue
Block a user