mirror of
https://github.com/oven-sh/bun
synced 2026-02-02 15:08:46 +00:00
ci: make sure we're running the sequential node tests too (#17928)
This commit is contained in:
@@ -877,12 +877,21 @@ function isNodeParallelTest(testPath) {
|
||||
return testPath.replaceAll(sep, "/").includes("js/node/test/parallel/");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} testPath
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function isNodeSequentialTest(testPath) {
|
||||
return testPath.replaceAll(sep, "/").includes("js/node/test/sequential/");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} path
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function isTest(path) {
|
||||
if (isNodeParallelTest(path) && targetDoesRunNodeTests()) return true;
|
||||
if (isNodeSequentialTest(path) && targetDoesRunNodeTests()) return true;
|
||||
if (path.replaceAll(sep, "/").startsWith("js/node/cluster/test-") && path.endsWith(".ts")) return true;
|
||||
return isTestStrict(path);
|
||||
}
|
||||
|
||||
59
test/js/node/test/sequential/test-child-process-exit.js
Normal file
59
test/js/node/test/sequential/test-child-process-exit.js
Normal file
@@ -0,0 +1,59 @@
|
||||
// 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');
|
||||
|
||||
// Open a chain of five Node processes each a child of the next. The final
|
||||
// process exits immediately. Each process in the chain is instructed to exit
|
||||
// when its child exits.
|
||||
// https://github.com/joyent/node/issues/1726
|
||||
|
||||
const assert = require('assert');
|
||||
const ch = require('child_process');
|
||||
|
||||
const gen = +(process.argv[2] || 0);
|
||||
const maxGen = 5;
|
||||
|
||||
|
||||
if (gen === maxGen) {
|
||||
console.error('hit maxGen, exiting', maxGen);
|
||||
return;
|
||||
}
|
||||
|
||||
const child = ch.spawn(process.execPath, [__filename, gen + 1], {
|
||||
stdio: [ 'ignore', 'pipe', 'ignore' ]
|
||||
});
|
||||
assert.ok(!child.stdin);
|
||||
assert.ok(child.stdout);
|
||||
assert.ok(!child.stderr);
|
||||
|
||||
console.error('gen=%d, pid=%d', gen, process.pid);
|
||||
|
||||
child.on('exit', function(code) {
|
||||
console.error('exit %d from gen %d', code, gen + 1);
|
||||
});
|
||||
|
||||
child.stdout.pipe(process.stdout);
|
||||
|
||||
child.stdout.on('close', function() {
|
||||
console.error('child.stdout close gen=%d', gen);
|
||||
});
|
||||
18
test/js/node/test/sequential/test-debug-prompt.js
Normal file
18
test/js/node/test/sequential/test-debug-prompt.js
Normal file
@@ -0,0 +1,18 @@
|
||||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
common.skipIfInspectorDisabled();
|
||||
const spawn = require('child_process').spawn;
|
||||
|
||||
const proc = spawn(process.execPath, ['inspect', 'foo']);
|
||||
proc.stdout.setEncoding('utf8');
|
||||
|
||||
let needToSendExit = true;
|
||||
let output = '';
|
||||
proc.stdout.on('data', (data) => {
|
||||
output += data;
|
||||
if (output.includes('debug> ') && needToSendExit) {
|
||||
proc.stdin.write('.exit\n');
|
||||
needToSendExit = false;
|
||||
}
|
||||
});
|
||||
@@ -1,113 +0,0 @@
|
||||
// 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');
|
||||
|
||||
// This test asserts the semantics of dgram::socket.bind({ exclusive })
|
||||
// when called from a cluster.Worker
|
||||
|
||||
const assert = require('assert');
|
||||
const cluster = require('cluster');
|
||||
const dgram = require('dgram');
|
||||
const BYE = 'bye';
|
||||
const WORKER2_NAME = 'wrker2';
|
||||
|
||||
if (cluster.isPrimary) {
|
||||
const worker1 = cluster.fork();
|
||||
|
||||
if (common.isWindows) {
|
||||
worker1.on('error', common.mustCall((err) => {
|
||||
console.log(err);
|
||||
assert.strictEqual(err.code, 'ENOTSUP');
|
||||
worker1.kill();
|
||||
}));
|
||||
return;
|
||||
}
|
||||
|
||||
worker1.on('message', common.mustCall((msg) => {
|
||||
console.log(msg);
|
||||
assert.strictEqual(msg, 'success');
|
||||
|
||||
const worker2 = cluster.fork({ WORKER2_NAME });
|
||||
worker2.on('message', common.mustCall((msg) => {
|
||||
console.log(msg);
|
||||
assert.strictEqual(msg, 'socket3:EADDRINUSE');
|
||||
|
||||
// finish test
|
||||
worker1.send(BYE);
|
||||
worker2.send(BYE);
|
||||
}));
|
||||
worker2.on('exit', common.mustCall((code, signal) => {
|
||||
assert.strictEqual(signal, null);
|
||||
assert.strictEqual(code, 0);
|
||||
}));
|
||||
}));
|
||||
worker1.on('exit', common.mustCall((code, signal) => {
|
||||
assert.strictEqual(signal, null);
|
||||
assert.strictEqual(code, 0);
|
||||
}));
|
||||
// end primary code
|
||||
} else {
|
||||
// worker code
|
||||
process.on('message', common.mustCallAtLeast((msg) => {
|
||||
if (msg === BYE) process.exit(0);
|
||||
}), 1);
|
||||
|
||||
const isSecondWorker = process.env.WORKER2_NAME === WORKER2_NAME;
|
||||
const socket1 = dgram.createSocket('udp4', common.mustNotCall());
|
||||
const socket2 = dgram.createSocket('udp4', common.mustNotCall());
|
||||
const socket3 = dgram.createSocket('udp4', common.mustNotCall());
|
||||
|
||||
socket1.on('error', (err) => assert.fail(err));
|
||||
socket2.on('error', (err) => assert.fail(err));
|
||||
|
||||
// First worker should bind, second should err
|
||||
const socket3OnBind =
|
||||
isSecondWorker ?
|
||||
common.mustNotCall() :
|
||||
common.mustCall(() => {
|
||||
const port3 = socket3.address().port;
|
||||
assert.strictEqual(typeof port3, 'number');
|
||||
process.send('success');
|
||||
});
|
||||
// An error is expected only in the second worker
|
||||
const socket3OnError =
|
||||
!isSecondWorker ?
|
||||
common.mustNotCall() :
|
||||
common.mustCall((err) => {
|
||||
process.send(`socket3:${err.code}`);
|
||||
});
|
||||
const address = common.localhostIPv4;
|
||||
const opt1 = { address, port: 0, exclusive: false };
|
||||
const opt2 = { address, port: common.PORT, exclusive: false };
|
||||
const opt3 = { address, port: common.PORT + 1, exclusive: true };
|
||||
socket1.bind(opt1, common.mustCall(() => {
|
||||
const port1 = socket1.address().port;
|
||||
assert.strictEqual(typeof port1, 'number');
|
||||
socket2.bind(opt2, common.mustCall(() => {
|
||||
const port2 = socket2.address().port;
|
||||
assert.strictEqual(typeof port2, 'number');
|
||||
socket3.on('error', socket3OnError);
|
||||
socket3.bind(opt3, socket3OnBind);
|
||||
}));
|
||||
}));
|
||||
}
|
||||
242
test/js/node/test/sequential/test-fs-opendir-recursive.js
Normal file
242
test/js/node/test/sequential/test-fs-opendir-recursive.js
Normal file
@@ -0,0 +1,242 @@
|
||||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
const assert = require('assert');
|
||||
const fs = require('fs');
|
||||
const fsPromises = fs.promises;
|
||||
const pathModule = require('path');
|
||||
const tmpdir = require('../common/tmpdir');
|
||||
|
||||
const testDir = tmpdir.path;
|
||||
|
||||
const fileStructure = [
|
||||
[ 'a', [ 'a', 'foo', 'bar' ] ],
|
||||
[ 'b', [ 'foo', 'bar' ] ],
|
||||
[ 'c', [ 'foo', 'bar' ] ],
|
||||
[ 'd', [ 'foo', 'bar' ] ],
|
||||
[ 'e', [ 'foo', 'bar' ] ],
|
||||
[ 'f', [ 'foo', 'bar' ] ],
|
||||
[ 'g', [ 'foo', 'bar' ] ],
|
||||
[ 'h', [ 'foo', 'bar' ] ],
|
||||
[ 'i', [ 'foo', 'bar' ] ],
|
||||
[ 'j', [ 'foo', 'bar' ] ],
|
||||
[ 'k', [ 'foo', 'bar' ] ],
|
||||
[ 'l', [ 'foo', 'bar' ] ],
|
||||
[ 'm', [ 'foo', 'bar' ] ],
|
||||
[ 'n', [ 'foo', 'bar' ] ],
|
||||
[ 'o', [ 'foo', 'bar' ] ],
|
||||
[ 'p', [ 'foo', 'bar' ] ],
|
||||
[ 'q', [ 'foo', 'bar' ] ],
|
||||
[ 'r', [ 'foo', 'bar' ] ],
|
||||
[ 's', [ 'foo', 'bar' ] ],
|
||||
[ 't', [ 'foo', 'bar' ] ],
|
||||
[ 'u', [ 'foo', 'bar' ] ],
|
||||
[ 'v', [ 'foo', 'bar' ] ],
|
||||
[ 'w', [ 'foo', 'bar' ] ],
|
||||
[ 'x', [ 'foo', 'bar' ] ],
|
||||
[ 'y', [ 'foo', 'bar' ] ],
|
||||
[ 'z', [ 'foo', 'bar' ] ],
|
||||
[ 'aa', [ 'foo', 'bar' ] ],
|
||||
[ 'bb', [ 'foo', 'bar' ] ],
|
||||
[ 'cc', [ 'foo', 'bar' ] ],
|
||||
[ 'dd', [ 'foo', 'bar' ] ],
|
||||
[ 'ee', [ 'foo', 'bar' ] ],
|
||||
[ 'ff', [ 'foo', 'bar' ] ],
|
||||
[ 'gg', [ 'foo', 'bar' ] ],
|
||||
[ 'hh', [ 'foo', 'bar' ] ],
|
||||
[ 'ii', [ 'foo', 'bar' ] ],
|
||||
[ 'jj', [ 'foo', 'bar' ] ],
|
||||
[ 'kk', [ 'foo', 'bar' ] ],
|
||||
[ 'll', [ 'foo', 'bar' ] ],
|
||||
[ 'mm', [ 'foo', 'bar' ] ],
|
||||
[ 'nn', [ 'foo', 'bar' ] ],
|
||||
[ 'oo', [ 'foo', 'bar' ] ],
|
||||
[ 'pp', [ 'foo', 'bar' ] ],
|
||||
[ 'qq', [ 'foo', 'bar' ] ],
|
||||
[ 'rr', [ 'foo', 'bar' ] ],
|
||||
[ 'ss', [ 'foo', 'bar' ] ],
|
||||
[ 'tt', [ 'foo', 'bar' ] ],
|
||||
[ 'uu', [ 'foo', 'bar' ] ],
|
||||
[ 'vv', [ 'foo', 'bar' ] ],
|
||||
[ 'ww', [ 'foo', 'bar' ] ],
|
||||
[ 'xx', [ 'foo', 'bar' ] ],
|
||||
[ 'yy', [ 'foo', 'bar' ] ],
|
||||
[ 'zz', [ 'foo', 'bar' ] ],
|
||||
[ 'abc', [ ['def', [ 'foo', 'bar' ] ], ['ghi', [ 'foo', 'bar' ] ] ] ],
|
||||
];
|
||||
|
||||
function createFiles(path, fileStructure) {
|
||||
for (const fileOrDir of fileStructure) {
|
||||
if (typeof fileOrDir === 'string') {
|
||||
fs.writeFileSync(pathModule.join(path, fileOrDir), '');
|
||||
} else {
|
||||
const dirPath = pathModule.join(path, fileOrDir[0]);
|
||||
fs.mkdirSync(dirPath);
|
||||
createFiles(dirPath, fileOrDir[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure tmp directory is clean
|
||||
tmpdir.refresh();
|
||||
|
||||
createFiles(testDir, fileStructure);
|
||||
const symlinksRootPath = pathModule.join(testDir, 'symlinks');
|
||||
const symlinkTargetFile = pathModule.join(symlinksRootPath, 'symlink-target-file');
|
||||
const symlinkTargetDir = pathModule.join(symlinksRootPath, 'symlink-target-dir');
|
||||
fs.mkdirSync(symlinksRootPath);
|
||||
fs.writeFileSync(symlinkTargetFile, '');
|
||||
fs.mkdirSync(symlinkTargetDir);
|
||||
fs.symlinkSync(symlinkTargetFile, pathModule.join(symlinksRootPath, 'symlink-src-file'));
|
||||
fs.symlinkSync(symlinkTargetDir, pathModule.join(symlinksRootPath, 'symlink-src-dir'));
|
||||
|
||||
const expected = [
|
||||
'a', 'a/a', 'a/bar', 'a/foo', 'aa', 'aa/bar', 'aa/foo',
|
||||
'abc', 'abc/def', 'abc/def/bar', 'abc/def/foo', 'abc/ghi', 'abc/ghi/bar', 'abc/ghi/foo',
|
||||
'b', 'b/bar', 'b/foo', 'bb', 'bb/bar', 'bb/foo',
|
||||
'c', 'c/bar', 'c/foo', 'cc', 'cc/bar', 'cc/foo',
|
||||
'd', 'd/bar', 'd/foo', 'dd', 'dd/bar', 'dd/foo',
|
||||
'e', 'e/bar', 'e/foo', 'ee', 'ee/bar', 'ee/foo',
|
||||
'f', 'f/bar', 'f/foo', 'ff', 'ff/bar', 'ff/foo',
|
||||
'g', 'g/bar', 'g/foo', 'gg', 'gg/bar', 'gg/foo',
|
||||
'h', 'h/bar', 'h/foo', 'hh', 'hh/bar', 'hh/foo',
|
||||
'i', 'i/bar', 'i/foo', 'ii', 'ii/bar', 'ii/foo',
|
||||
'j', 'j/bar', 'j/foo', 'jj', 'jj/bar', 'jj/foo',
|
||||
'k', 'k/bar', 'k/foo', 'kk', 'kk/bar', 'kk/foo',
|
||||
'l', 'l/bar', 'l/foo', 'll', 'll/bar', 'll/foo',
|
||||
'm', 'm/bar', 'm/foo', 'mm', 'mm/bar', 'mm/foo',
|
||||
'n', 'n/bar', 'n/foo', 'nn', 'nn/bar', 'nn/foo',
|
||||
'o', 'o/bar', 'o/foo', 'oo', 'oo/bar', 'oo/foo',
|
||||
'p', 'p/bar', 'p/foo', 'pp', 'pp/bar', 'pp/foo',
|
||||
'q', 'q/bar', 'q/foo', 'qq', 'qq/bar', 'qq/foo',
|
||||
'r', 'r/bar', 'r/foo', 'rr', 'rr/bar', 'rr/foo',
|
||||
's', 's/bar', 's/foo', 'ss', 'ss/bar', 'ss/foo',
|
||||
'symlinks', 'symlinks/symlink-src-dir', 'symlinks/symlink-src-file',
|
||||
'symlinks/symlink-target-dir', 'symlinks/symlink-target-file',
|
||||
't', 't/bar', 't/foo', 'tt', 'tt/bar', 'tt/foo',
|
||||
'u', 'u/bar', 'u/foo', 'uu', 'uu/bar', 'uu/foo',
|
||||
'v', 'v/bar', 'v/foo', 'vv', 'vv/bar', 'vv/foo',
|
||||
'w', 'w/bar', 'w/foo', 'ww', 'ww/bar', 'ww/foo',
|
||||
'x', 'x/bar', 'x/foo', 'xx', 'xx/bar', 'xx/foo',
|
||||
'y', 'y/bar', 'y/foo', 'yy', 'yy/bar', 'yy/foo',
|
||||
'z', 'z/bar', 'z/foo', 'zz', 'zz/bar', 'zz/foo',
|
||||
];
|
||||
|
||||
// Normalize paths once for non POSIX platforms
|
||||
for (let i = 0; i < expected.length; i++) {
|
||||
expected[i] = pathModule.normalize(expected[i]);
|
||||
}
|
||||
|
||||
function getDirentPath(dirent) {
|
||||
return pathModule.relative(testDir, pathModule.join(dirent.path, dirent.name));
|
||||
}
|
||||
|
||||
function assertDirents(dirents) {
|
||||
assert.strictEqual(dirents.length, expected.length);
|
||||
dirents.sort((a, b) => (getDirentPath(a) < getDirentPath(b) ? -1 : 1));
|
||||
assert.deepStrictEqual(
|
||||
dirents.map((dirent) => {
|
||||
assert(dirent instanceof fs.Dirent);
|
||||
return getDirentPath(dirent);
|
||||
}),
|
||||
expected
|
||||
);
|
||||
}
|
||||
|
||||
function processDirSync(dir) {
|
||||
const dirents = [];
|
||||
let dirent = dir.readSync();
|
||||
while (dirent !== null) {
|
||||
dirents.push(dirent);
|
||||
dirent = dir.readSync();
|
||||
}
|
||||
assertDirents(dirents);
|
||||
}
|
||||
|
||||
// Opendir read results sync
|
||||
|
||||
{
|
||||
const dir = fs.opendirSync(testDir, { recursive: true });
|
||||
processDirSync(dir);
|
||||
dir.closeSync();
|
||||
}
|
||||
|
||||
{
|
||||
fs.opendir(testDir, { recursive: true }, common.mustSucceed((dir) => {
|
||||
processDirSync(dir);
|
||||
dir.close(common.mustSucceed());
|
||||
}));
|
||||
}
|
||||
|
||||
// Opendir read result using callback
|
||||
|
||||
function processDirCb(dir, cb) {
|
||||
const acc = [];
|
||||
|
||||
function _process(dir, acc, cb) {
|
||||
dir.read((err, dirent) => {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
|
||||
if (dirent !== null) {
|
||||
acc.push(dirent);
|
||||
_process(dir, acc, cb);
|
||||
} else {
|
||||
cb(null, acc);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
_process(dir, acc, cb);
|
||||
}
|
||||
|
||||
{
|
||||
const dir = fs.opendirSync(testDir, { recursive: true });
|
||||
processDirCb(dir, common.mustSucceed((dirents) => {
|
||||
assertDirents(dirents);
|
||||
dir.close(common.mustSucceed());
|
||||
}));
|
||||
}
|
||||
|
||||
{
|
||||
fs.opendir(testDir, { recursive: true }, common.mustSucceed((dir) => {
|
||||
processDirCb(dir, common.mustSucceed((dirents) => {
|
||||
assertDirents(dirents);
|
||||
dir.close(common.mustSucceed());
|
||||
}));
|
||||
}));
|
||||
}
|
||||
|
||||
// Opendir read result using AsyncIterator
|
||||
|
||||
{
|
||||
async function test() {
|
||||
const dir = await fsPromises.opendir(testDir, { recursive: true });
|
||||
const dirents = [];
|
||||
for await (const dirent of dir) {
|
||||
dirents.push(dirent);
|
||||
}
|
||||
assertDirents(dirents);
|
||||
}
|
||||
|
||||
test().then(common.mustCall());
|
||||
}
|
||||
|
||||
// Issue https://github.com/nodejs/node/issues/48820 highlights that
|
||||
// opendir recursive does not properly handle the buffer size option.
|
||||
// This test asserts that the buffer size option is respected.
|
||||
{
|
||||
const dir = fs.opendirSync(testDir, { bufferSize: 1, recursive: true });
|
||||
processDirSync(dir);
|
||||
dir.closeSync();
|
||||
}
|
||||
|
||||
{
|
||||
fs.opendir(testDir, { recursive: true, bufferSize: 1 }, common.mustSucceed((dir) => {
|
||||
processDirCb(dir, common.mustSucceed((dirents) => {
|
||||
assertDirents(dirents);
|
||||
dir.close(common.mustSucceed());
|
||||
}));
|
||||
}));
|
||||
}
|
||||
198
test/js/node/test/sequential/test-fs-readdir-recursive.js
Normal file
198
test/js/node/test/sequential/test-fs-readdir-recursive.js
Normal file
@@ -0,0 +1,198 @@
|
||||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
const assert = require('assert');
|
||||
const fs = require('fs');
|
||||
const pathModule = require('path');
|
||||
const tmpdir = require('../common/tmpdir');
|
||||
|
||||
const readdirDir = tmpdir.path;
|
||||
|
||||
const fileStructure = [
|
||||
[ 'a', [ 'a', 'foo', 'bar' ] ],
|
||||
[ 'b', [ 'foo', 'bar' ] ],
|
||||
[ 'c', [ 'foo', 'bar' ] ],
|
||||
[ 'd', [ 'foo', 'bar' ] ],
|
||||
[ 'e', [ 'foo', 'bar' ] ],
|
||||
[ 'f', [ 'foo', 'bar' ] ],
|
||||
[ 'g', [ 'foo', 'bar' ] ],
|
||||
[ 'h', [ 'foo', 'bar' ] ],
|
||||
[ 'i', [ 'foo', 'bar' ] ],
|
||||
[ 'j', [ 'foo', 'bar' ] ],
|
||||
[ 'k', [ 'foo', 'bar' ] ],
|
||||
[ 'l', [ 'foo', 'bar' ] ],
|
||||
[ 'm', [ 'foo', 'bar' ] ],
|
||||
[ 'n', [ 'foo', 'bar' ] ],
|
||||
[ 'o', [ 'foo', 'bar' ] ],
|
||||
[ 'p', [ 'foo', 'bar' ] ],
|
||||
[ 'q', [ 'foo', 'bar' ] ],
|
||||
[ 'r', [ 'foo', 'bar' ] ],
|
||||
[ 's', [ 'foo', 'bar' ] ],
|
||||
[ 't', [ 'foo', 'bar' ] ],
|
||||
[ 'u', [ 'foo', 'bar' ] ],
|
||||
[ 'v', [ 'foo', 'bar' ] ],
|
||||
[ 'w', [ 'foo', 'bar' ] ],
|
||||
[ 'x', [ 'foo', 'bar' ] ],
|
||||
[ 'y', [ 'foo', 'bar' ] ],
|
||||
[ 'z', [ 'foo', 'bar' ] ],
|
||||
[ 'aa', [ 'foo', 'bar' ] ],
|
||||
[ 'bb', [ 'foo', 'bar' ] ],
|
||||
[ 'cc', [ 'foo', 'bar' ] ],
|
||||
[ 'dd', [ 'foo', 'bar' ] ],
|
||||
[ 'ee', [ 'foo', 'bar' ] ],
|
||||
[ 'ff', [ 'foo', 'bar' ] ],
|
||||
[ 'gg', [ 'foo', 'bar' ] ],
|
||||
[ 'hh', [ 'foo', 'bar' ] ],
|
||||
[ 'ii', [ 'foo', 'bar' ] ],
|
||||
[ 'jj', [ 'foo', 'bar' ] ],
|
||||
[ 'kk', [ 'foo', 'bar' ] ],
|
||||
[ 'll', [ 'foo', 'bar' ] ],
|
||||
[ 'mm', [ 'foo', 'bar' ] ],
|
||||
[ 'nn', [ 'foo', 'bar' ] ],
|
||||
[ 'oo', [ 'foo', 'bar' ] ],
|
||||
[ 'pp', [ 'foo', 'bar' ] ],
|
||||
[ 'qq', [ 'foo', 'bar' ] ],
|
||||
[ 'rr', [ 'foo', 'bar' ] ],
|
||||
[ 'ss', [ 'foo', 'bar' ] ],
|
||||
[ 'tt', [ 'foo', 'bar' ] ],
|
||||
[ 'uu', [ 'foo', 'bar' ] ],
|
||||
[ 'vv', [ 'foo', 'bar' ] ],
|
||||
[ 'ww', [ 'foo', 'bar' ] ],
|
||||
[ 'xx', [ 'foo', 'bar' ] ],
|
||||
[ 'yy', [ 'foo', 'bar' ] ],
|
||||
[ 'zz', [ 'foo', 'bar' ] ],
|
||||
[ 'abc', [ ['def', [ 'foo', 'bar' ] ], ['ghi', [ 'foo', 'bar' ] ] ] ],
|
||||
];
|
||||
|
||||
function createFiles(path, fileStructure) {
|
||||
for (const fileOrDir of fileStructure) {
|
||||
if (typeof fileOrDir === 'string') {
|
||||
fs.writeFileSync(pathModule.join(path, fileOrDir), '');
|
||||
} else {
|
||||
const dirPath = pathModule.join(path, fileOrDir[0]);
|
||||
fs.mkdirSync(dirPath);
|
||||
createFiles(dirPath, fileOrDir[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure tmp directory is clean
|
||||
tmpdir.refresh();
|
||||
|
||||
createFiles(readdirDir, fileStructure);
|
||||
const symlinksRootPath = pathModule.join(readdirDir, 'symlinks');
|
||||
const symlinkTargetFile = pathModule.join(symlinksRootPath, 'symlink-target-file');
|
||||
const symlinkTargetDir = pathModule.join(symlinksRootPath, 'symlink-target-dir');
|
||||
fs.mkdirSync(symlinksRootPath);
|
||||
fs.writeFileSync(symlinkTargetFile, '');
|
||||
fs.mkdirSync(symlinkTargetDir);
|
||||
fs.symlinkSync(symlinkTargetFile, pathModule.join(symlinksRootPath, 'symlink-src-file'));
|
||||
fs.symlinkSync(symlinkTargetDir, pathModule.join(symlinksRootPath, 'symlink-src-dir'));
|
||||
|
||||
const expected = [
|
||||
'a', 'a/a', 'a/bar', 'a/foo', 'aa', 'aa/bar', 'aa/foo',
|
||||
'abc', 'abc/def', 'abc/def/bar', 'abc/def/foo', 'abc/ghi', 'abc/ghi/bar', 'abc/ghi/foo',
|
||||
'b', 'b/bar', 'b/foo', 'bb', 'bb/bar', 'bb/foo',
|
||||
'c', 'c/bar', 'c/foo', 'cc', 'cc/bar', 'cc/foo',
|
||||
'd', 'd/bar', 'd/foo', 'dd', 'dd/bar', 'dd/foo',
|
||||
'e', 'e/bar', 'e/foo', 'ee', 'ee/bar', 'ee/foo',
|
||||
'f', 'f/bar', 'f/foo', 'ff', 'ff/bar', 'ff/foo',
|
||||
'g', 'g/bar', 'g/foo', 'gg', 'gg/bar', 'gg/foo',
|
||||
'h', 'h/bar', 'h/foo', 'hh', 'hh/bar', 'hh/foo',
|
||||
'i', 'i/bar', 'i/foo', 'ii', 'ii/bar', 'ii/foo',
|
||||
'j', 'j/bar', 'j/foo', 'jj', 'jj/bar', 'jj/foo',
|
||||
'k', 'k/bar', 'k/foo', 'kk', 'kk/bar', 'kk/foo',
|
||||
'l', 'l/bar', 'l/foo', 'll', 'll/bar', 'll/foo',
|
||||
'm', 'm/bar', 'm/foo', 'mm', 'mm/bar', 'mm/foo',
|
||||
'n', 'n/bar', 'n/foo', 'nn', 'nn/bar', 'nn/foo',
|
||||
'o', 'o/bar', 'o/foo', 'oo', 'oo/bar', 'oo/foo',
|
||||
'p', 'p/bar', 'p/foo', 'pp', 'pp/bar', 'pp/foo',
|
||||
'q', 'q/bar', 'q/foo', 'qq', 'qq/bar', 'qq/foo',
|
||||
'r', 'r/bar', 'r/foo', 'rr', 'rr/bar', 'rr/foo',
|
||||
's', 's/bar', 's/foo', 'ss', 'ss/bar', 'ss/foo',
|
||||
'symlinks', 'symlinks/symlink-src-dir', 'symlinks/symlink-src-file',
|
||||
'symlinks/symlink-target-dir', 'symlinks/symlink-target-file',
|
||||
't', 't/bar', 't/foo', 'tt', 'tt/bar', 'tt/foo',
|
||||
'u', 'u/bar', 'u/foo', 'uu', 'uu/bar', 'uu/foo',
|
||||
'v', 'v/bar', 'v/foo', 'vv', 'vv/bar', 'vv/foo',
|
||||
'w', 'w/bar', 'w/foo', 'ww', 'ww/bar', 'ww/foo',
|
||||
'x', 'x/bar', 'x/foo', 'xx', 'xx/bar', 'xx/foo',
|
||||
'y', 'y/bar', 'y/foo', 'yy', 'yy/bar', 'yy/foo',
|
||||
'z', 'z/bar', 'z/foo', 'zz', 'zz/bar', 'zz/foo',
|
||||
];
|
||||
|
||||
// Normalize paths once for non POSIX platforms
|
||||
for (let i = 0; i < expected.length; i++) {
|
||||
expected[i] = pathModule.normalize(expected[i]);
|
||||
}
|
||||
|
||||
function getDirentPath(dirent) {
|
||||
return pathModule.relative(readdirDir, pathModule.join(dirent.path, dirent.name));
|
||||
}
|
||||
|
||||
function assertDirents(dirents) {
|
||||
assert.strictEqual(dirents.length, expected.length);
|
||||
dirents.sort((a, b) => (getDirentPath(a) < getDirentPath(b) ? -1 : 1));
|
||||
assert.deepStrictEqual(
|
||||
dirents.map((dirent) => {
|
||||
assert(dirent instanceof fs.Dirent);
|
||||
assert.notStrictEqual(dirent.name, undefined);
|
||||
return getDirentPath(dirent);
|
||||
}),
|
||||
expected
|
||||
);
|
||||
}
|
||||
|
||||
// readdirSync
|
||||
|
||||
// readdirSync { recursive }
|
||||
{
|
||||
const result = fs.readdirSync(readdirDir, { recursive: true });
|
||||
assert.deepStrictEqual(result.sort(), expected);
|
||||
}
|
||||
|
||||
// readdirSync { recursive, withFileTypes }
|
||||
{
|
||||
const result = fs.readdirSync(readdirDir, { recursive: true, withFileTypes: true });
|
||||
assertDirents(result);
|
||||
}
|
||||
|
||||
// readdir
|
||||
|
||||
// readdir { recursive } callback
|
||||
{
|
||||
fs.readdir(readdirDir, { recursive: true },
|
||||
common.mustSucceed((result) => {
|
||||
assert.deepStrictEqual(result.sort(), expected);
|
||||
}));
|
||||
}
|
||||
|
||||
// Readdir { recursive, withFileTypes } callback
|
||||
{
|
||||
fs.readdir(readdirDir, { recursive: true, withFileTypes: true },
|
||||
common.mustSucceed((result) => {
|
||||
assertDirents(result);
|
||||
}));
|
||||
}
|
||||
|
||||
// fs.promises.readdir
|
||||
|
||||
// fs.promises.readdir { recursive }
|
||||
{
|
||||
async function test() {
|
||||
const result = await fs.promises.readdir(readdirDir, { recursive: true });
|
||||
assert.deepStrictEqual(result.sort(), expected);
|
||||
}
|
||||
|
||||
test().then(common.mustCall());
|
||||
}
|
||||
|
||||
// fs.promises.readdir { recursive, withFileTypes }
|
||||
{
|
||||
async function test() {
|
||||
const result = await fs.promises.readdir(readdirDir, { recursive: true, withFileTypes: true });
|
||||
assertDirents(result);
|
||||
}
|
||||
|
||||
test().then(common.mustCall());
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
const assert = require('assert');
|
||||
const http = require('http');
|
||||
|
||||
const server = http.createServer(common.mustCall((req, res) => {
|
||||
if (req.url === '/first') {
|
||||
res.end('ok');
|
||||
return;
|
||||
}
|
||||
setTimeout(() => {
|
||||
res.end('ok');
|
||||
}, common.platformTimeout(500));
|
||||
}, 2));
|
||||
|
||||
server.keepAliveTimeout = common.platformTimeout(200);
|
||||
|
||||
const agent = new http.Agent({
|
||||
keepAlive: true,
|
||||
maxSockets: 1
|
||||
});
|
||||
|
||||
function request(path, callback) {
|
||||
const port = server.address().port;
|
||||
const req = http.request({ agent, path, port }, common.mustCall((res) => {
|
||||
assert.strictEqual(res.statusCode, 200);
|
||||
|
||||
res.setEncoding('utf8');
|
||||
|
||||
let result = '';
|
||||
res.on('data', (chunk) => {
|
||||
result += chunk;
|
||||
});
|
||||
|
||||
res.on('end', common.mustCall(() => {
|
||||
assert.strictEqual(result, 'ok');
|
||||
callback();
|
||||
}));
|
||||
}));
|
||||
req.end();
|
||||
}
|
||||
|
||||
server.listen(0, common.mustCall(() => {
|
||||
request('/first', () => {
|
||||
request('/second', () => {
|
||||
server.close();
|
||||
});
|
||||
});
|
||||
}));
|
||||
63
test/js/node/test/sequential/test-init.js
Normal file
63
test/js/node/test/sequential/test-init.js
Normal file
@@ -0,0 +1,63 @@
|
||||
// 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 child = require('child_process');
|
||||
const fixtures = require('../common/fixtures');
|
||||
|
||||
if (!common.isMainThread)
|
||||
common.skip('process.chdir is not available in Workers');
|
||||
|
||||
if (process.env.TEST_INIT) {
|
||||
return process.stdout.write('Loaded successfully!');
|
||||
}
|
||||
|
||||
process.env.TEST_INIT = 1;
|
||||
|
||||
function test(file, expected) {
|
||||
child.exec(...common.escapePOSIXShell`"${process.execPath}" "${file}"`, common.mustSucceed((out) => {
|
||||
assert.strictEqual(out, expected, `'node ${file}' failed!`);
|
||||
}));
|
||||
}
|
||||
|
||||
{
|
||||
// Change CWD as we do this test so it's not dependent on current CWD
|
||||
// being in the test folder
|
||||
process.chdir(__dirname);
|
||||
test('test-init', 'Loaded successfully!');
|
||||
test('test-init.js', 'Loaded successfully!');
|
||||
}
|
||||
|
||||
{
|
||||
// test-init-index is in fixtures dir as requested by ry, so go there
|
||||
process.chdir(fixtures.path());
|
||||
test('test-init-index', 'Loaded successfully!');
|
||||
}
|
||||
|
||||
{
|
||||
// Ensures that `node fs` does not mistakenly load the native 'fs' module
|
||||
// instead of the desired file and that the fs module loads as
|
||||
// expected in node
|
||||
process.chdir(fixtures.path('test-init-native'));
|
||||
test('fs', 'fs loaded successfully');
|
||||
}
|
||||
99
test/js/node/test/sequential/test-net-GH-5504.js
Normal file
99
test/js/node/test/sequential/test-net-GH-5504.js
Normal file
@@ -0,0 +1,99 @@
|
||||
// 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');
|
||||
|
||||
// Ref: https://github.com/nodejs/node-v0.x-archive/issues/5504
|
||||
//
|
||||
// This test only fails with CentOS 6.3 using kernel version 2.6.32.
|
||||
// On other Linuxes and macOS, the `read` call gets an ECONNRESET in
|
||||
// that case. On sunos, the `write` call fails with EPIPE.
|
||||
//
|
||||
// However, old CentOS will occasionally send an EOF instead of an
|
||||
// ECONNRESET or EPIPE when the client has been destroyed abruptly.
|
||||
//
|
||||
// Make sure we don't keep trying to write or read more in that case.
|
||||
|
||||
switch (process.argv[2]) {
|
||||
case 'server': return server();
|
||||
case 'client': return client();
|
||||
case undefined: return parent();
|
||||
default: throw new Error('invalid');
|
||||
}
|
||||
|
||||
function server() {
|
||||
const net = require('net');
|
||||
const content = Buffer.alloc(64 * 1024 * 1024, '#');
|
||||
net.createServer(function(socket) {
|
||||
this.close();
|
||||
socket.on('end', function() {
|
||||
console.error('end');
|
||||
});
|
||||
socket.on('_socketEnd', function() {
|
||||
console.error('_socketEnd');
|
||||
});
|
||||
socket.write(content);
|
||||
}).listen(common.PORT, common.localhostIPv4, function() {
|
||||
console.log('listening');
|
||||
});
|
||||
}
|
||||
|
||||
function client() {
|
||||
const net = require('net');
|
||||
const client = net.connect({
|
||||
host: common.localhostIPv4,
|
||||
port: common.PORT
|
||||
}, function() {
|
||||
client.destroy();
|
||||
});
|
||||
}
|
||||
|
||||
function parent() {
|
||||
const spawn = require('child_process').spawn;
|
||||
const node = process.execPath;
|
||||
|
||||
const s = spawn(node, [__filename, 'server'], {
|
||||
env: Object.assign(process.env, {
|
||||
NODE_DEBUG: 'net'
|
||||
})
|
||||
});
|
||||
|
||||
wrap(s.stderr, process.stderr, 'SERVER 2>');
|
||||
wrap(s.stdout, process.stdout, 'SERVER 1>');
|
||||
s.on('exit', common.mustCall());
|
||||
|
||||
s.stdout.once('data', common.mustCall(function() {
|
||||
const c = spawn(node, [__filename, 'client']);
|
||||
wrap(c.stderr, process.stderr, 'CLIENT 2>');
|
||||
wrap(c.stdout, process.stdout, 'CLIENT 1>');
|
||||
c.on('exit', common.mustCall());
|
||||
}));
|
||||
|
||||
function wrap(inp, out, w) {
|
||||
inp.setEncoding('utf8');
|
||||
inp.on('data', function(chunk) {
|
||||
chunk = chunk.trim();
|
||||
if (!chunk) return;
|
||||
out.write(`${w}${chunk.split('\n').join(`\n${w}`)}\n`);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
// 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';
|
||||
// Verify that connect reqs are properly cleaned up.
|
||||
|
||||
const common = require('../common');
|
||||
const assert = require('assert');
|
||||
const net = require('net');
|
||||
|
||||
const ROUNDS = 5;
|
||||
const ATTEMPTS_PER_ROUND = 50;
|
||||
let rounds = 1;
|
||||
let reqs = 0;
|
||||
|
||||
let port;
|
||||
const server = net.createServer().listen(0, common.mustCall(() => {
|
||||
port = server.address().port;
|
||||
server.close(common.mustCall(pummel));
|
||||
}));
|
||||
|
||||
function pummel() {
|
||||
let pending;
|
||||
for (pending = 0; pending < ATTEMPTS_PER_ROUND; pending++) {
|
||||
net.createConnection({ port, autoSelectFamily: false }).on('error', function(error) {
|
||||
// Family autoselection might be skipped if only a single address is returned by DNS.
|
||||
const actualError = Array.isArray(error.errors) ? error.errors[0] : error;
|
||||
|
||||
console.log('pending', pending, 'rounds', rounds);
|
||||
assert.strictEqual(actualError.code, 'ECONNREFUSED');
|
||||
if (--pending > 0) return;
|
||||
if (rounds === ROUNDS) return check();
|
||||
rounds++;
|
||||
pummel();
|
||||
});
|
||||
reqs++;
|
||||
}
|
||||
}
|
||||
|
||||
function check() {
|
||||
setTimeout(common.mustCall(function() {
|
||||
assert.strictEqual(process.getActiveResourcesInfo().filter(
|
||||
(type) => type === 'TCPWRAP').length, 0);
|
||||
}), 0);
|
||||
}
|
||||
|
||||
process.on('exit', function() {
|
||||
assert.strictEqual(rounds, ROUNDS);
|
||||
assert.strictEqual(reqs, ROUNDS * ATTEMPTS_PER_ROUND);
|
||||
});
|
||||
@@ -21,23 +21,23 @@
|
||||
|
||||
'use strict';
|
||||
const common = require('../common');
|
||||
const fixtures = require('../common/fixtures');
|
||||
|
||||
// Check that the calls to Integer::New() and Date::New() succeed and bail out
|
||||
// if they don't.
|
||||
// V8 returns an empty handle on stack overflow. Trying to set the empty handle
|
||||
// as a property on an object results in a NULL pointer dereference in release
|
||||
// builds and an assert in debug builds.
|
||||
// https://github.com/nodejs/node-v0.x-archive/issues/4015
|
||||
|
||||
const net = require('net');
|
||||
const assert = require('assert');
|
||||
const { spawn } = require('child_process');
|
||||
const N = 20;
|
||||
let disconnectCount = 0;
|
||||
|
||||
const cp = spawn(process.execPath, [fixtures.path('test-fs-stat-sync-overflow.js')]);
|
||||
const c = net.createConnection(common.PORT);
|
||||
|
||||
const stderr = [];
|
||||
cp.stderr.on('data', (chunk) => stderr.push(chunk));
|
||||
c.on('connect', common.mustNotCall('client should not have connected'));
|
||||
|
||||
cp.on('exit', common.mustCall(() => {
|
||||
assert.match(Buffer.concat(stderr).toString('utf8'), /RangeError: Maximum call stack size exceeded/);
|
||||
}));
|
||||
c.on('error', common.mustCall((error) => {
|
||||
// Family autoselection might be skipped if only a single address is returned by DNS.
|
||||
const actualError = Array.isArray(error.errors) ? error.errors[0] : error;
|
||||
|
||||
assert.strictEqual(actualError.code, 'ECONNREFUSED');
|
||||
}, N + 1));
|
||||
|
||||
c.on('close', common.mustCall(() => {
|
||||
if (disconnectCount++ < N)
|
||||
c.connect(common.PORT); // reconnect
|
||||
}, N + 1));
|
||||
75
test/js/node/test/sequential/test-net-response-size.js
Normal file
75
test/js/node/test/sequential/test-net-response-size.js
Normal file
@@ -0,0 +1,75 @@
|
||||
// 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');
|
||||
|
||||
// Make sure the net module's server doesn't throw an error when handling
|
||||
// responses that are either too long or too small (especially on Windows)
|
||||
// https://github.com/nodejs/node-v0.x-archive/issues/1697
|
||||
|
||||
const net = require('net');
|
||||
const cp = require('child_process');
|
||||
|
||||
if (process.argv[2] === 'server') {
|
||||
// Server
|
||||
|
||||
const server = net.createServer(function(conn) {
|
||||
conn.on('data', function(data) {
|
||||
console.log(`server received ${data.length} bytes`);
|
||||
});
|
||||
|
||||
conn.on('close', function() {
|
||||
server.close();
|
||||
});
|
||||
});
|
||||
|
||||
server.listen(common.PORT, '127.0.0.1', function() {
|
||||
console.log('Server running.');
|
||||
});
|
||||
|
||||
} else {
|
||||
// Client
|
||||
|
||||
const serverProcess = cp.spawn(process.execPath, [process.argv[1], 'server']);
|
||||
serverProcess.stdout.pipe(process.stdout);
|
||||
serverProcess.stderr.pipe(process.stdout);
|
||||
|
||||
serverProcess.stdout.once('data', function() {
|
||||
const client = net.createConnection(common.PORT, '127.0.0.1');
|
||||
client.on('connect', function() {
|
||||
const alot = Buffer.allocUnsafe(1024);
|
||||
const alittle = Buffer.allocUnsafe(1);
|
||||
|
||||
for (let i = 0; i < 100; i++) {
|
||||
client.write(alot);
|
||||
}
|
||||
|
||||
// Block the event loop for 1 second
|
||||
const start = (new Date()).getTime();
|
||||
while ((new Date()).getTime() < start + 1000);
|
||||
|
||||
client.write(alittle);
|
||||
|
||||
client.destroySoon();
|
||||
});
|
||||
});
|
||||
}
|
||||
113
test/js/node/test/sequential/test-net-server-address.js
Normal file
113
test/js/node/test/sequential/test-net-server-address.js
Normal file
@@ -0,0 +1,113 @@
|
||||
// Copyright Joyent, Inc. and other Node contributors.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
||||
// persons to whom the Software is furnished to do so, subject to the
|
||||
// following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
'use strict';
|
||||
const common = require('../common');
|
||||
const assert = require('assert');
|
||||
const net = require('net');
|
||||
|
||||
// Test on IPv4 Server
|
||||
{
|
||||
const family = 'IPv4';
|
||||
const server = net.createServer();
|
||||
|
||||
server.on('error', common.mustNotCall());
|
||||
|
||||
server
|
||||
.listen(common.PORT + 1, common.localhostIPv4, common.mustCall(() => {
|
||||
const address4 = server.address();
|
||||
assert.strictEqual(address4.address, common.localhostIPv4);
|
||||
assert.strictEqual(address4.port, common.PORT + 1);
|
||||
assert.strictEqual(address4.family, family);
|
||||
server.close();
|
||||
}));
|
||||
}
|
||||
|
||||
if (!common.hasIPv6) {
|
||||
common.printSkipMessage('ipv6 part of test, no IPv6 support');
|
||||
return;
|
||||
}
|
||||
|
||||
const family6 = 'IPv6';
|
||||
const anycast6 = '::';
|
||||
|
||||
// Test on IPv6 Server
|
||||
{
|
||||
const localhost = '::1';
|
||||
|
||||
const server = net.createServer();
|
||||
|
||||
server.on('error', common.mustNotCall());
|
||||
|
||||
server.listen(common.PORT + 2, localhost, common.mustCall(() => {
|
||||
const address = server.address();
|
||||
assert.strictEqual(address.address, localhost);
|
||||
assert.strictEqual(address.port, common.PORT + 2);
|
||||
assert.strictEqual(address.family, family6);
|
||||
server.close();
|
||||
}));
|
||||
}
|
||||
|
||||
// Test without hostname or ip
|
||||
{
|
||||
const server = net.createServer();
|
||||
|
||||
server.on('error', common.mustNotCall());
|
||||
|
||||
// Specify the port number
|
||||
server.listen(common.PORT + 3, common.mustCall(() => {
|
||||
const address = server.address();
|
||||
assert.strictEqual(address.address, anycast6);
|
||||
assert.strictEqual(address.port, common.PORT + 3);
|
||||
assert.strictEqual(address.family, family6);
|
||||
server.close();
|
||||
}));
|
||||
}
|
||||
|
||||
// Test without hostname or port
|
||||
{
|
||||
const server = net.createServer();
|
||||
|
||||
server.on('error', common.mustNotCall());
|
||||
|
||||
// Don't specify the port number
|
||||
server.listen(common.mustCall(() => {
|
||||
const address = server.address();
|
||||
assert.strictEqual(address.address, anycast6);
|
||||
assert.strictEqual(address.family, family6);
|
||||
server.close();
|
||||
}));
|
||||
}
|
||||
|
||||
// Test without hostname, but with a false-y port
|
||||
{
|
||||
const server = net.createServer();
|
||||
|
||||
server.on('error', common.mustNotCall());
|
||||
|
||||
// Specify a false-y port number
|
||||
server.listen(0, common.mustCall(() => {
|
||||
const address = server.address();
|
||||
assert.strictEqual(address.address, anycast6);
|
||||
assert.strictEqual(address.family, family6);
|
||||
server.close();
|
||||
}));
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
// 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';
|
||||
// We've experienced a regression where the module loader stats a bunch of
|
||||
// directories on require() even if it's been called before. The require()
|
||||
// should caching the request.
|
||||
require('../common');
|
||||
const fs = require('fs');
|
||||
const assert = require('assert');
|
||||
const { fixturesDir } = require('../common/fixtures');
|
||||
|
||||
let counter = 0;
|
||||
|
||||
// Switch out the two stat implementations so that they increase a counter
|
||||
// each time they are called.
|
||||
|
||||
const _statSync = fs.statSync;
|
||||
const _stat = fs.stat;
|
||||
|
||||
fs.statSync = function() {
|
||||
counter++;
|
||||
return _statSync.apply(this, arguments);
|
||||
};
|
||||
|
||||
fs.stat = function() {
|
||||
counter++;
|
||||
return _stat.apply(this, arguments);
|
||||
};
|
||||
|
||||
// Load the module 'a' and 'http' once. It should become cached.
|
||||
require(`${fixturesDir}/a`);
|
||||
require('../fixtures/a.js');
|
||||
require('./../fixtures/a.js');
|
||||
require('http');
|
||||
|
||||
console.log(`counterBefore = ${counter}`);
|
||||
const counterBefore = counter;
|
||||
|
||||
// Now load the module a bunch of times with equivalent paths.
|
||||
// stat should not be called.
|
||||
for (let i = 0; i < 100; i++) {
|
||||
require(`${fixturesDir}/a`);
|
||||
require('../fixtures/a.js');
|
||||
require('./../fixtures/a.js');
|
||||
}
|
||||
|
||||
// Do the same with a built-in module
|
||||
for (let i = 0; i < 100; i++) {
|
||||
require('http');
|
||||
}
|
||||
|
||||
console.log(`counterAfter = ${counter}`);
|
||||
const counterAfter = counter;
|
||||
|
||||
assert.strictEqual(counterBefore, counterAfter);
|
||||
@@ -0,0 +1,70 @@
|
||||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
|
||||
const {
|
||||
generateSEA,
|
||||
skipIfSingleExecutableIsNotSupported,
|
||||
} = require('../common/sea');
|
||||
|
||||
skipIfSingleExecutableIsNotSupported();
|
||||
|
||||
// This tests the snapshot support in single executable applications.
|
||||
const tmpdir = require('../common/tmpdir');
|
||||
|
||||
const { copyFileSync, writeFileSync, existsSync } = require('fs');
|
||||
const {
|
||||
spawnSyncAndExitWithoutError,
|
||||
} = require('../common/child_process');
|
||||
const assert = require('assert');
|
||||
const fixtures = require('../common/fixtures');
|
||||
|
||||
tmpdir.refresh();
|
||||
if (!tmpdir.hasEnoughSpace(120 * 1024 * 1024)) {
|
||||
common.skip('Not enough disk space');
|
||||
}
|
||||
|
||||
const configFile = tmpdir.resolve('sea-config.json');
|
||||
const seaPrepBlob = tmpdir.resolve('sea-prep.blob');
|
||||
const outputFile = tmpdir.resolve(process.platform === 'win32' ? 'sea.exe' : 'sea');
|
||||
|
||||
{
|
||||
tmpdir.refresh();
|
||||
copyFileSync(fixtures.path('sea', 'get-asset-raw.js'), tmpdir.resolve('sea.js'));
|
||||
copyFileSync(fixtures.path('person.jpg'), tmpdir.resolve('person.jpg'));
|
||||
writeFileSync(configFile, `
|
||||
{
|
||||
"main": "sea.js",
|
||||
"output": "sea-prep.blob",
|
||||
"assets": {
|
||||
"person.jpg": "person.jpg"
|
||||
}
|
||||
}
|
||||
`, 'utf8');
|
||||
|
||||
spawnSyncAndExitWithoutError(
|
||||
process.execPath,
|
||||
['--experimental-sea-config', 'sea-config.json'],
|
||||
{
|
||||
env: {
|
||||
NODE_DEBUG_NATIVE: 'SEA',
|
||||
...process.env,
|
||||
},
|
||||
cwd: tmpdir.path
|
||||
});
|
||||
|
||||
assert(existsSync(seaPrepBlob));
|
||||
|
||||
generateSEA(outputFile, process.execPath, seaPrepBlob);
|
||||
|
||||
spawnSyncAndExitWithoutError(
|
||||
outputFile,
|
||||
{
|
||||
env: {
|
||||
...process.env,
|
||||
NODE_DEBUG_NATIVE: 'SEA',
|
||||
__TEST_PERSON_JPG: fixtures.path('person.jpg'),
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
|
||||
const {
|
||||
generateSEA,
|
||||
skipIfSingleExecutableIsNotSupported,
|
||||
} = require('../common/sea');
|
||||
|
||||
skipIfSingleExecutableIsNotSupported();
|
||||
|
||||
// This tests the snapshot support in single executable applications.
|
||||
const tmpdir = require('../common/tmpdir');
|
||||
|
||||
const { copyFileSync, writeFileSync, existsSync } = require('fs');
|
||||
const {
|
||||
spawnSyncAndAssert,
|
||||
spawnSyncAndExit,
|
||||
spawnSyncAndExitWithoutError,
|
||||
} = require('../common/child_process');
|
||||
const assert = require('assert');
|
||||
const fixtures = require('../common/fixtures');
|
||||
|
||||
tmpdir.refresh();
|
||||
if (!tmpdir.hasEnoughSpace(120 * 1024 * 1024)) {
|
||||
common.skip('Not enough disk space');
|
||||
}
|
||||
|
||||
const configFile = tmpdir.resolve('sea-config.json');
|
||||
const seaPrepBlob = tmpdir.resolve('sea-prep.blob');
|
||||
const outputFile = tmpdir.resolve(process.platform === 'win32' ? 'sea.exe' : 'sea');
|
||||
|
||||
{
|
||||
tmpdir.refresh();
|
||||
copyFileSync(fixtures.path('sea', 'get-asset.js'), tmpdir.resolve('sea.js'));
|
||||
writeFileSync(configFile, `
|
||||
{
|
||||
"main": "sea.js",
|
||||
"output": "sea-prep.blob",
|
||||
"assets": "invalid"
|
||||
}
|
||||
`);
|
||||
|
||||
spawnSyncAndExit(
|
||||
process.execPath,
|
||||
['--experimental-sea-config', 'sea-config.json'],
|
||||
{
|
||||
cwd: tmpdir.path
|
||||
},
|
||||
{
|
||||
status: 1,
|
||||
signal: null,
|
||||
stderr: /"assets" field of sea-config\.json is not a map of strings/
|
||||
});
|
||||
}
|
||||
|
||||
{
|
||||
tmpdir.refresh();
|
||||
copyFileSync(fixtures.path('sea', 'get-asset.js'), tmpdir.resolve('sea.js'));
|
||||
writeFileSync(configFile, `
|
||||
{
|
||||
"main": "sea.js",
|
||||
"output": "sea-prep.blob",
|
||||
"assets": {
|
||||
"nonexistent": "nonexistent.txt"
|
||||
}
|
||||
}
|
||||
`);
|
||||
|
||||
spawnSyncAndExit(
|
||||
process.execPath,
|
||||
['--experimental-sea-config', 'sea-config.json'],
|
||||
{
|
||||
cwd: tmpdir.path
|
||||
},
|
||||
{
|
||||
status: 1,
|
||||
signal: null,
|
||||
stderr: /Cannot read asset nonexistent\.txt: no such file or directory/
|
||||
});
|
||||
}
|
||||
|
||||
{
|
||||
tmpdir.refresh();
|
||||
copyFileSync(fixtures.path('sea', 'get-asset.js'), tmpdir.resolve('sea.js'));
|
||||
copyFileSync(fixtures.utf8TestTextPath, tmpdir.resolve('utf8_test_text.txt'));
|
||||
copyFileSync(fixtures.path('person.jpg'), tmpdir.resolve('person.jpg'));
|
||||
writeFileSync(configFile, `
|
||||
{
|
||||
"main": "sea.js",
|
||||
"output": "sea-prep.blob",
|
||||
"assets": {
|
||||
"utf8_test_text.txt": "utf8_test_text.txt",
|
||||
"person.jpg": "person.jpg"
|
||||
}
|
||||
}
|
||||
`, 'utf8');
|
||||
|
||||
spawnSyncAndExitWithoutError(
|
||||
process.execPath,
|
||||
['--experimental-sea-config', 'sea-config.json'],
|
||||
{
|
||||
env: {
|
||||
NODE_DEBUG_NATIVE: 'SEA',
|
||||
...process.env,
|
||||
},
|
||||
cwd: tmpdir.path
|
||||
});
|
||||
|
||||
assert(existsSync(seaPrepBlob));
|
||||
|
||||
generateSEA(outputFile, process.execPath, seaPrepBlob);
|
||||
|
||||
spawnSyncAndAssert(
|
||||
outputFile,
|
||||
{
|
||||
env: {
|
||||
...process.env,
|
||||
NODE_DEBUG_NATIVE: 'SEA',
|
||||
__TEST_PERSON_JPG: fixtures.path('person.jpg'),
|
||||
__TEST_UTF8_TEXT_PATH: fixtures.path('utf8_test_text.txt'),
|
||||
}
|
||||
},
|
||||
{
|
||||
trim: true,
|
||||
stdout: fixtures.utf8TestText,
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
'use strict';
|
||||
|
||||
require('../common');
|
||||
|
||||
const {
|
||||
generateSEA,
|
||||
skipIfSingleExecutableIsNotSupported,
|
||||
} = require('../common/sea');
|
||||
|
||||
skipIfSingleExecutableIsNotSupported();
|
||||
|
||||
// This tests the creation of a single executable application which has the
|
||||
// experimental SEA warning disabled.
|
||||
|
||||
const fixtures = require('../common/fixtures');
|
||||
const tmpdir = require('../common/tmpdir');
|
||||
const { copyFileSync, writeFileSync, existsSync } = require('fs');
|
||||
const { spawnSyncAndAssert, spawnSyncAndExitWithoutError } = require('../common/child_process');
|
||||
const { join } = require('path');
|
||||
const assert = require('assert');
|
||||
|
||||
const inputFile = fixtures.path('sea.js');
|
||||
const requirableFile = tmpdir.resolve('requirable.js');
|
||||
const configFile = tmpdir.resolve('sea-config.json');
|
||||
const seaPrepBlob = tmpdir.resolve('sea-prep.blob');
|
||||
const outputFile = tmpdir.resolve(process.platform === 'win32' ? 'sea.exe' : 'sea');
|
||||
|
||||
tmpdir.refresh();
|
||||
|
||||
writeFileSync(requirableFile, `
|
||||
module.exports = {
|
||||
hello: 'world',
|
||||
};
|
||||
`);
|
||||
|
||||
writeFileSync(configFile, `
|
||||
{
|
||||
"main": "sea.js",
|
||||
"output": "sea-prep.blob",
|
||||
"disableExperimentalSEAWarning": true
|
||||
}
|
||||
`);
|
||||
|
||||
// Copy input to working directory
|
||||
copyFileSync(inputFile, tmpdir.resolve('sea.js'));
|
||||
spawnSyncAndExitWithoutError(
|
||||
process.execPath,
|
||||
['--experimental-sea-config', 'sea-config.json'],
|
||||
{ cwd: tmpdir.path });
|
||||
|
||||
assert(existsSync(seaPrepBlob));
|
||||
|
||||
generateSEA(outputFile, process.execPath, seaPrepBlob);
|
||||
|
||||
spawnSyncAndAssert(
|
||||
outputFile,
|
||||
[ '-a', '--b=c', 'd' ],
|
||||
{
|
||||
env: {
|
||||
COMMON_DIRECTORY: join(__dirname, '..', 'common'),
|
||||
NODE_DEBUG_NATIVE: 'SEA',
|
||||
...process.env,
|
||||
}
|
||||
},
|
||||
{
|
||||
stdout: 'Hello, world! 😊\n'
|
||||
});
|
||||
@@ -0,0 +1,63 @@
|
||||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
|
||||
const {
|
||||
generateSEA,
|
||||
skipIfSingleExecutableIsNotSupported,
|
||||
} = require('../common/sea');
|
||||
|
||||
skipIfSingleExecutableIsNotSupported();
|
||||
|
||||
// This tests the creation of a single executable application with an empty
|
||||
// script.
|
||||
|
||||
const tmpdir = require('../common/tmpdir');
|
||||
const { writeFileSync, existsSync } = require('fs');
|
||||
const { spawnSyncAndExitWithoutError } = require('../common/child_process');
|
||||
const assert = require('assert');
|
||||
|
||||
const configFile = tmpdir.resolve('sea-config.json');
|
||||
const seaPrepBlob = tmpdir.resolve('sea-prep.blob');
|
||||
const outputFile = tmpdir.resolve(process.platform === 'win32' ? 'sea.exe' : 'sea');
|
||||
|
||||
tmpdir.refresh();
|
||||
|
||||
writeFileSync(tmpdir.resolve('empty.js'), '', 'utf-8');
|
||||
writeFileSync(configFile, `
|
||||
{
|
||||
"main": "empty.js",
|
||||
"output": "sea-prep.blob"
|
||||
}
|
||||
`);
|
||||
|
||||
spawnSyncAndExitWithoutError(
|
||||
process.execPath,
|
||||
['--experimental-sea-config', 'sea-config.json'],
|
||||
{ cwd: tmpdir.path });
|
||||
|
||||
assert(existsSync(seaPrepBlob));
|
||||
|
||||
// Verify the workflow.
|
||||
try {
|
||||
generateSEA(outputFile, process.execPath, seaPrepBlob, true);
|
||||
} catch (e) {
|
||||
if (/Cannot copy/.test(e.message)) {
|
||||
common.skip(e.message);
|
||||
} else if (common.isWindows) {
|
||||
if (/Cannot sign/.test(e.message) || /Cannot find signtool/.test(e.message)) {
|
||||
common.skip(e.message);
|
||||
}
|
||||
}
|
||||
|
||||
throw e;
|
||||
}
|
||||
|
||||
spawnSyncAndExitWithoutError(
|
||||
outputFile,
|
||||
{
|
||||
env: {
|
||||
NODE_DEBUG_NATIVE: 'SEA',
|
||||
...process.env,
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,78 @@
|
||||
'use strict';
|
||||
|
||||
require('../common');
|
||||
|
||||
const {
|
||||
generateSEA,
|
||||
skipIfSingleExecutableIsNotSupported,
|
||||
} = require('../common/sea');
|
||||
|
||||
skipIfSingleExecutableIsNotSupported();
|
||||
|
||||
// This tests "useCodeCache" is ignored when "useSnapshot" is true.
|
||||
|
||||
const tmpdir = require('../common/tmpdir');
|
||||
const { writeFileSync, existsSync } = require('fs');
|
||||
const {
|
||||
spawnSyncAndAssert,
|
||||
} = require('../common/child_process');
|
||||
const { join } = require('path');
|
||||
const assert = require('assert');
|
||||
|
||||
const configFile = join(tmpdir.path, 'sea-config.json');
|
||||
const seaPrepBlob = join(tmpdir.path, 'sea-prep.blob');
|
||||
const outputFile = join(tmpdir.path, process.platform === 'win32' ? 'sea.exe' : 'sea');
|
||||
|
||||
{
|
||||
tmpdir.refresh();
|
||||
const code = `
|
||||
const {
|
||||
setDeserializeMainFunction,
|
||||
} = require('v8').startupSnapshot;
|
||||
|
||||
setDeserializeMainFunction(() => {
|
||||
console.log('Hello from snapshot');
|
||||
});
|
||||
`;
|
||||
|
||||
writeFileSync(join(tmpdir.path, 'snapshot.js'), code, 'utf-8');
|
||||
writeFileSync(configFile, `
|
||||
{
|
||||
"main": "snapshot.js",
|
||||
"output": "sea-prep.blob",
|
||||
"useSnapshot": true,
|
||||
"useCodeCache": true
|
||||
}
|
||||
`);
|
||||
|
||||
spawnSyncAndAssert(
|
||||
process.execPath,
|
||||
['--experimental-sea-config', 'sea-config.json'],
|
||||
{
|
||||
cwd: tmpdir.path,
|
||||
env: {
|
||||
NODE_DEBUG_NATIVE: 'SEA',
|
||||
...process.env,
|
||||
},
|
||||
},
|
||||
{
|
||||
stderr: /"useCodeCache" is redundant when "useSnapshot" is true/
|
||||
}
|
||||
);
|
||||
|
||||
assert(existsSync(seaPrepBlob));
|
||||
|
||||
generateSEA(outputFile, process.execPath, seaPrepBlob);
|
||||
|
||||
spawnSyncAndAssert(
|
||||
outputFile,
|
||||
{
|
||||
env: {
|
||||
NODE_DEBUG_NATIVE: 'SEA,MKSNAPSHOT',
|
||||
...process.env,
|
||||
}
|
||||
}, {
|
||||
stdout: 'Hello from snapshot',
|
||||
trim: true,
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
'use strict';
|
||||
|
||||
require('../common');
|
||||
|
||||
const {
|
||||
generateSEA,
|
||||
skipIfSingleExecutableIsNotSupported,
|
||||
} = require('../common/sea');
|
||||
|
||||
skipIfSingleExecutableIsNotSupported();
|
||||
|
||||
// This tests the snapshot support in single executable applications.
|
||||
|
||||
const tmpdir = require('../common/tmpdir');
|
||||
const { writeFileSync, existsSync } = require('fs');
|
||||
const {
|
||||
spawnSyncAndAssert, spawnSyncAndExitWithoutError,
|
||||
} = require('../common/child_process');
|
||||
const assert = require('assert');
|
||||
|
||||
const configFile = tmpdir.resolve('sea-config.json');
|
||||
const seaPrepBlob = tmpdir.resolve('sea-prep.blob');
|
||||
const outputFile = tmpdir.resolve(process.platform === 'win32' ? 'sea.exe' : 'sea');
|
||||
|
||||
{
|
||||
tmpdir.refresh();
|
||||
|
||||
// FIXME(joyeecheung): currently `worker_threads` cannot be loaded during the
|
||||
// snapshot building process because internal/worker.js is accessing isMainThread at
|
||||
// the top level (and there are maybe more code that access these at the top-level),
|
||||
// and have to be loaded in the deserialized snapshot main function.
|
||||
// Change these states to be accessed on-demand.
|
||||
const code = `
|
||||
const {
|
||||
setDeserializeMainFunction,
|
||||
} = require('v8').startupSnapshot;
|
||||
setDeserializeMainFunction(() => {
|
||||
const { Worker } = require('worker_threads');
|
||||
new Worker("console.log('Hello from Worker')", { eval: true });
|
||||
});
|
||||
`;
|
||||
|
||||
writeFileSync(tmpdir.resolve('snapshot.js'), code, 'utf-8');
|
||||
writeFileSync(configFile, `
|
||||
{
|
||||
"main": "snapshot.js",
|
||||
"output": "sea-prep.blob",
|
||||
"useSnapshot": true
|
||||
}
|
||||
`);
|
||||
|
||||
spawnSyncAndExitWithoutError(
|
||||
process.execPath,
|
||||
['--experimental-sea-config', 'sea-config.json'],
|
||||
{
|
||||
cwd: tmpdir.path,
|
||||
env: {
|
||||
NODE_DEBUG_NATIVE: 'SEA',
|
||||
...process.env,
|
||||
},
|
||||
});
|
||||
|
||||
assert(existsSync(seaPrepBlob));
|
||||
|
||||
generateSEA(outputFile, process.execPath, seaPrepBlob);
|
||||
|
||||
spawnSyncAndAssert(
|
||||
outputFile,
|
||||
{
|
||||
env: {
|
||||
NODE_DEBUG_NATIVE: 'SEA',
|
||||
...process.env,
|
||||
}
|
||||
},
|
||||
{
|
||||
trim: true,
|
||||
stdout: 'Hello from Worker'
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
'use strict';
|
||||
|
||||
require('../common');
|
||||
|
||||
const {
|
||||
generateSEA,
|
||||
skipIfSingleExecutableIsNotSupported,
|
||||
} = require('../common/sea');
|
||||
|
||||
skipIfSingleExecutableIsNotSupported();
|
||||
|
||||
// This tests the snapshot support in single executable applications.
|
||||
|
||||
const tmpdir = require('../common/tmpdir');
|
||||
const { writeFileSync, existsSync } = require('fs');
|
||||
const {
|
||||
spawnSyncAndAssert,
|
||||
spawnSyncAndExit,
|
||||
} = require('../common/child_process');
|
||||
const assert = require('assert');
|
||||
|
||||
const configFile = tmpdir.resolve('sea-config.json');
|
||||
const seaPrepBlob = tmpdir.resolve('sea-prep.blob');
|
||||
const outputFile = tmpdir.resolve(process.platform === 'win32' ? 'sea.exe' : 'sea');
|
||||
|
||||
{
|
||||
tmpdir.refresh();
|
||||
|
||||
writeFileSync(tmpdir.resolve('snapshot.js'), '', 'utf-8');
|
||||
writeFileSync(configFile, `
|
||||
{
|
||||
"main": "snapshot.js",
|
||||
"output": "sea-prep.blob",
|
||||
"useSnapshot": true
|
||||
}
|
||||
`);
|
||||
|
||||
spawnSyncAndExit(
|
||||
process.execPath,
|
||||
['--experimental-sea-config', 'sea-config.json'],
|
||||
{
|
||||
cwd: tmpdir.path
|
||||
},
|
||||
{
|
||||
status: 1,
|
||||
signal: null,
|
||||
stderr: /snapshot\.js does not invoke v8\.startupSnapshot\.setDeserializeMainFunction\(\)/
|
||||
});
|
||||
}
|
||||
|
||||
{
|
||||
tmpdir.refresh();
|
||||
const code = `
|
||||
const {
|
||||
setDeserializeMainFunction,
|
||||
} = require('v8').startupSnapshot;
|
||||
|
||||
setDeserializeMainFunction(() => {
|
||||
console.log('Hello from snapshot');
|
||||
});
|
||||
`;
|
||||
|
||||
writeFileSync(tmpdir.resolve('snapshot.js'), code, 'utf-8');
|
||||
writeFileSync(configFile, `
|
||||
{
|
||||
"main": "snapshot.js",
|
||||
"output": "sea-prep.blob",
|
||||
"useSnapshot": true
|
||||
}
|
||||
`);
|
||||
|
||||
spawnSyncAndAssert(
|
||||
process.execPath,
|
||||
['--experimental-sea-config', 'sea-config.json'],
|
||||
{
|
||||
cwd: tmpdir.path,
|
||||
env: {
|
||||
NODE_DEBUG_NATIVE: 'SEA',
|
||||
...process.env,
|
||||
},
|
||||
},
|
||||
{
|
||||
stderr: /Single executable application is an experimental feature/
|
||||
});
|
||||
|
||||
assert(existsSync(seaPrepBlob));
|
||||
|
||||
generateSEA(outputFile, process.execPath, seaPrepBlob);
|
||||
|
||||
spawnSyncAndAssert(
|
||||
outputFile,
|
||||
{
|
||||
env: {
|
||||
NODE_DEBUG_NATIVE: 'SEA,MKSNAPSHOT',
|
||||
...process.env,
|
||||
}
|
||||
},
|
||||
{
|
||||
trim: true,
|
||||
stdout: 'Hello from snapshot',
|
||||
stderr(output) {
|
||||
assert.doesNotMatch(
|
||||
output,
|
||||
/Single executable application is an experimental feature/);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
'use strict';
|
||||
|
||||
require('../common');
|
||||
|
||||
const {
|
||||
generateSEA,
|
||||
skipIfSingleExecutableIsNotSupported,
|
||||
} = require('../common/sea');
|
||||
|
||||
skipIfSingleExecutableIsNotSupported();
|
||||
|
||||
// This tests the creation of a single executable application which uses the
|
||||
// V8 code cache.
|
||||
|
||||
const fixtures = require('../common/fixtures');
|
||||
const tmpdir = require('../common/tmpdir');
|
||||
const { copyFileSync, writeFileSync, existsSync } = require('fs');
|
||||
const { spawnSyncAndAssert, spawnSyncAndExitWithoutError } = require('../common/child_process');
|
||||
const { join } = require('path');
|
||||
const assert = require('assert');
|
||||
|
||||
const inputFile = fixtures.path('sea.js');
|
||||
const requirableFile = tmpdir.resolve('requirable.js');
|
||||
const configFile = tmpdir.resolve('sea-config.json');
|
||||
const seaPrepBlob = tmpdir.resolve('sea-prep.blob');
|
||||
const outputFile = tmpdir.resolve(process.platform === 'win32' ? 'sea.exe' : 'sea');
|
||||
|
||||
tmpdir.refresh();
|
||||
|
||||
writeFileSync(requirableFile, `
|
||||
module.exports = {
|
||||
hello: 'world',
|
||||
};
|
||||
`);
|
||||
|
||||
writeFileSync(configFile, `
|
||||
{
|
||||
"main": "sea.js",
|
||||
"output": "sea-prep.blob",
|
||||
"useCodeCache": true
|
||||
}
|
||||
`);
|
||||
|
||||
// Copy input to working directory
|
||||
copyFileSync(inputFile, tmpdir.resolve('sea.js'));
|
||||
spawnSyncAndExitWithoutError(
|
||||
process.execPath,
|
||||
['--experimental-sea-config', 'sea-config.json'],
|
||||
{
|
||||
cwd: tmpdir.path,
|
||||
env: {
|
||||
NODE_DEBUG_NATIVE: 'SEA',
|
||||
...process.env,
|
||||
},
|
||||
});
|
||||
|
||||
assert(existsSync(seaPrepBlob));
|
||||
|
||||
generateSEA(outputFile, process.execPath, seaPrepBlob);
|
||||
|
||||
spawnSyncAndAssert(
|
||||
outputFile,
|
||||
[ '-a', '--b=c', 'd' ],
|
||||
{
|
||||
env: {
|
||||
COMMON_DIRECTORY: join(__dirname, '..', 'common'),
|
||||
NODE_DEBUG_NATIVE: 'SEA',
|
||||
...process.env,
|
||||
}
|
||||
},
|
||||
{
|
||||
stdout: 'Hello, world! 😊\n'
|
||||
});
|
||||
@@ -0,0 +1,66 @@
|
||||
'use strict';
|
||||
|
||||
require('../common');
|
||||
|
||||
const {
|
||||
generateSEA,
|
||||
skipIfSingleExecutableIsNotSupported,
|
||||
} = require('../common/sea');
|
||||
|
||||
skipIfSingleExecutableIsNotSupported();
|
||||
|
||||
// This tests the creation of a single executable application.
|
||||
|
||||
const fixtures = require('../common/fixtures');
|
||||
const tmpdir = require('../common/tmpdir');
|
||||
const { copyFileSync, writeFileSync, existsSync } = require('fs');
|
||||
const { spawnSyncAndAssert, spawnSyncAndExitWithoutError } = require('../common/child_process');
|
||||
const { join } = require('path');
|
||||
const assert = require('assert');
|
||||
|
||||
const inputFile = fixtures.path('sea.js');
|
||||
const requirableFile = tmpdir.resolve('requirable.js');
|
||||
const configFile = tmpdir.resolve('sea-config.json');
|
||||
const seaPrepBlob = tmpdir.resolve('sea-prep.blob');
|
||||
const outputFile = tmpdir.resolve(process.platform === 'win32' ? 'sea.exe' : 'sea');
|
||||
|
||||
tmpdir.refresh();
|
||||
|
||||
writeFileSync(requirableFile, `
|
||||
module.exports = {
|
||||
hello: 'world',
|
||||
};
|
||||
`);
|
||||
|
||||
writeFileSync(configFile, `
|
||||
{
|
||||
"main": "sea.js",
|
||||
"output": "sea-prep.blob",
|
||||
"disableExperimentalSEAWarning": false
|
||||
}
|
||||
`);
|
||||
|
||||
// Copy input to working directory
|
||||
copyFileSync(inputFile, tmpdir.resolve('sea.js'));
|
||||
spawnSyncAndExitWithoutError(
|
||||
process.execPath,
|
||||
['--experimental-sea-config', 'sea-config.json'],
|
||||
{ cwd: tmpdir.path });
|
||||
|
||||
assert(existsSync(seaPrepBlob));
|
||||
|
||||
generateSEA(outputFile, process.execPath, seaPrepBlob);
|
||||
|
||||
spawnSyncAndAssert(
|
||||
outputFile,
|
||||
[ '-a', '--b=c', 'd' ],
|
||||
{
|
||||
env: {
|
||||
COMMON_DIRECTORY: join(__dirname, '..', 'common'),
|
||||
NODE_DEBUG_NATIVE: 'SEA',
|
||||
...process.env,
|
||||
}
|
||||
},
|
||||
{
|
||||
stdout: 'Hello, world! 😊\n'
|
||||
});
|
||||
110
test/js/node/test/sequential/test-tls-psk-client.js
Normal file
110
test/js/node/test/sequential/test-tls-psk-client.js
Normal file
@@ -0,0 +1,110 @@
|
||||
'use strict';
|
||||
const common = require('../common');
|
||||
|
||||
if (!common.hasCrypto)
|
||||
common.skip('missing crypto');
|
||||
if (!common.opensslCli)
|
||||
common.skip('missing openssl cli');
|
||||
|
||||
const assert = require('assert');
|
||||
const tls = require('tls');
|
||||
const net = require('net');
|
||||
const { spawn } = require('child_process');
|
||||
|
||||
const CIPHERS = 'PSK+HIGH';
|
||||
const KEY = 'd731ef57be09e5204f0b205b60627028';
|
||||
const IDENTITY = 'Client_identity'; // Hardcoded by `openssl s_server`
|
||||
const useIPv4 = !common.hasIPv6;
|
||||
|
||||
const server = spawn(common.opensslCli, [
|
||||
's_server',
|
||||
'-accept', common.PORT,
|
||||
'-cipher', CIPHERS,
|
||||
'-psk', KEY,
|
||||
'-psk_hint', IDENTITY,
|
||||
'-nocert',
|
||||
'-rev',
|
||||
...(useIPv4 ? ['-4'] : []),
|
||||
], { encoding: 'utf8' });
|
||||
let serverErr = '';
|
||||
let serverOut = '';
|
||||
server.stderr.on('data', (data) => serverErr += data);
|
||||
server.stdout.on('data', (data) => serverOut += data);
|
||||
server.on('error', common.mustNotCall());
|
||||
server.on('exit', (code, signal) => {
|
||||
// Server is expected to be terminated by cleanUp().
|
||||
assert.strictEqual(code, null,
|
||||
`'${server.spawnfile} ${server.spawnargs.join(' ')}' unexpected exited with output:\n${serverOut}\n${serverErr}`);
|
||||
assert.strictEqual(signal, 'SIGTERM');
|
||||
});
|
||||
|
||||
const cleanUp = (err) => {
|
||||
clearTimeout(timeout);
|
||||
if (err)
|
||||
console.log('Failed:', err);
|
||||
server.kill();
|
||||
process.exitCode = err ? 1 : 0;
|
||||
};
|
||||
|
||||
const timeout = setTimeout(() => cleanUp('Timed out'), 5000);
|
||||
|
||||
function waitForPort(port, cb) {
|
||||
const socket = net.connect(common.PORT, () => {
|
||||
socket.on('data', () => {});
|
||||
socket.end();
|
||||
socket.on('end', cb);
|
||||
});
|
||||
socket.on('error', (e) => {
|
||||
if (e.code === 'ENOENT' || e.code === 'ECONNREFUSED') {
|
||||
setTimeout(() => waitForPort(port, cb), 1000);
|
||||
} else {
|
||||
cb(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
waitForPort(common.PORT, common.mustCall((err) => {
|
||||
if (err) {
|
||||
cleanUp(err);
|
||||
return;
|
||||
}
|
||||
|
||||
const message = 'hello';
|
||||
const reverse = message.split('').reverse().join('');
|
||||
runClient(message, common.mustCall((err, data) => {
|
||||
try {
|
||||
if (!err) assert.strictEqual(data.trim(), reverse);
|
||||
} finally {
|
||||
cleanUp(err);
|
||||
}
|
||||
}));
|
||||
}));
|
||||
|
||||
function runClient(message, cb) {
|
||||
const s = tls.connect(common.PORT, {
|
||||
ciphers: CIPHERS,
|
||||
checkServerIdentity: () => {},
|
||||
pskCallback(hint) {
|
||||
// 'hint' will be null in TLS1.3.
|
||||
if (hint === null || hint === IDENTITY) {
|
||||
return {
|
||||
identity: IDENTITY,
|
||||
psk: Buffer.from(KEY, 'hex')
|
||||
};
|
||||
}
|
||||
}
|
||||
});
|
||||
s.on('secureConnect', common.mustCall(() => {
|
||||
let data = '';
|
||||
s.on('data', common.mustCallAtLeast((d) => {
|
||||
data += d;
|
||||
}));
|
||||
s.on('end', common.mustCall(() => {
|
||||
cb(null, data);
|
||||
}));
|
||||
s.end(message);
|
||||
}));
|
||||
s.on('error', (e) => {
|
||||
cb(e);
|
||||
});
|
||||
}
|
||||
186
test/js/node/test/sequential/test-tls-securepair-client.js
Normal file
186
test/js/node/test/sequential/test-tls-securepair-client.js
Normal file
@@ -0,0 +1,186 @@
|
||||
// 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');
|
||||
|
||||
if (!common.opensslCli)
|
||||
common.skip('node compiled without OpenSSL CLI.');
|
||||
|
||||
if (!common.hasCrypto)
|
||||
common.skip('missing crypto');
|
||||
|
||||
if (common.isWindows)
|
||||
common.skip('test does not work on Windows'); // ...but it should!
|
||||
|
||||
const net = require('net');
|
||||
const assert = require('assert');
|
||||
const fixtures = require('../common/fixtures');
|
||||
const tls = require('tls');
|
||||
const spawn = require('child_process').spawn;
|
||||
|
||||
const useIPv4 = !common.hasIPv6;
|
||||
|
||||
test1();
|
||||
|
||||
// simple/test-tls-securepair-client
|
||||
function test1() {
|
||||
test('keys/rsa_private.pem', 'keys/rsa_cert.crt', null, test2);
|
||||
}
|
||||
|
||||
// simple/test-tls-ext-key-usage
|
||||
function test2() {
|
||||
function check(pair) {
|
||||
// "TLS Web Client Authentication"
|
||||
assert.strictEqual(pair.cleartext.getPeerCertificate().ext_key_usage.length,
|
||||
1);
|
||||
assert.strictEqual(pair.cleartext.getPeerCertificate().ext_key_usage[0],
|
||||
'1.3.6.1.5.5.7.3.2');
|
||||
}
|
||||
test('keys/agent4-key.pem', 'keys/agent4-cert.pem', check);
|
||||
}
|
||||
|
||||
function test(keyPath, certPath, check, next) {
|
||||
const key = fixtures.readSync(keyPath).toString();
|
||||
const cert = fixtures.readSync(certPath).toString();
|
||||
|
||||
const server = spawn(common.opensslCli, ['s_server',
|
||||
'-accept', 0,
|
||||
'-cert', fixtures.path(certPath),
|
||||
'-key', fixtures.path(keyPath),
|
||||
...(useIPv4 ? ['-4'] : []),
|
||||
]);
|
||||
server.stdout.pipe(process.stdout);
|
||||
server.stderr.pipe(process.stdout);
|
||||
|
||||
|
||||
let state = 'WAIT-ACCEPT';
|
||||
|
||||
let serverStdoutBuffer = '';
|
||||
server.stdout.setEncoding('utf8');
|
||||
server.stdout.on('data', function(s) {
|
||||
serverStdoutBuffer += s;
|
||||
console.log(state);
|
||||
switch (state) {
|
||||
case 'WAIT-ACCEPT': {
|
||||
const matches = serverStdoutBuffer.match(/ACCEPT .*?:(\d+)/);
|
||||
if (matches) {
|
||||
const port = matches[1];
|
||||
state = 'WAIT-HELLO';
|
||||
startClient(port);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'WAIT-HELLO':
|
||||
if (/hello/.test(serverStdoutBuffer)) {
|
||||
|
||||
// End the current SSL connection and exit.
|
||||
// See s_server(1ssl).
|
||||
server.stdin.write('Q');
|
||||
|
||||
state = 'WAIT-SERVER-CLOSE';
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
const timeout = setTimeout(function() {
|
||||
server.kill();
|
||||
process.exit(1);
|
||||
}, 5000);
|
||||
|
||||
let gotWriteCallback = false;
|
||||
let serverExitCode = -1;
|
||||
|
||||
server.on('exit', function(code) {
|
||||
serverExitCode = code;
|
||||
clearTimeout(timeout);
|
||||
if (next) next();
|
||||
});
|
||||
|
||||
|
||||
function startClient(port) {
|
||||
const s = new net.Stream();
|
||||
|
||||
const sslcontext = tls.createSecureContext({ key, cert });
|
||||
sslcontext.context.setCiphers('RC4-SHA:AES128-SHA:AES256-SHA');
|
||||
|
||||
const pair = tls.createSecurePair(sslcontext, false);
|
||||
|
||||
assert.ok(pair.encrypted.writable);
|
||||
assert.ok(pair.cleartext.writable);
|
||||
|
||||
pair.encrypted.pipe(s);
|
||||
s.pipe(pair.encrypted);
|
||||
|
||||
s.connect(port);
|
||||
|
||||
s.on('connect', function() {
|
||||
console.log('client connected');
|
||||
setTimeout(function() {
|
||||
pair.cleartext.write('hello\r\n', function() {
|
||||
gotWriteCallback = true;
|
||||
});
|
||||
}, 500);
|
||||
});
|
||||
|
||||
pair.on('secure', function() {
|
||||
console.log('client: connected+secure!');
|
||||
console.log('client pair.cleartext.getPeerCertificate(): %j',
|
||||
pair.cleartext.getPeerCertificate());
|
||||
console.log('client pair.cleartext.getCipher(): %j',
|
||||
pair.cleartext.getCipher());
|
||||
if (check) check(pair);
|
||||
});
|
||||
|
||||
pair.cleartext.on('data', function(d) {
|
||||
console.log('cleartext: %s', d.toString());
|
||||
});
|
||||
|
||||
s.on('close', function() {
|
||||
console.log('client close');
|
||||
});
|
||||
|
||||
pair.encrypted.on('error', function(err) {
|
||||
console.log(`encrypted error: ${err}`);
|
||||
});
|
||||
|
||||
s.on('error', function(err) {
|
||||
console.log(`socket error: ${err}`);
|
||||
});
|
||||
|
||||
pair.on('error', function(err) {
|
||||
console.log(`secure error: ${err}`);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
process.on('exit', function() {
|
||||
assert.strictEqual(serverExitCode, 0);
|
||||
assert.strictEqual(state, 'WAIT-SERVER-CLOSE');
|
||||
assert.ok(gotWriteCallback);
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user