Upload Kmake

This commit is contained in:
Gorochu
2026-05-26 23:36:42 -07:00
parent ba051b2f74
commit 555ec72358
41615 changed files with 13344630 additions and 1 deletions

25
test/pummel/pummel.status Normal file
View File

@ -0,0 +1,25 @@
prefix pummel
# To mark a test as flaky, list the test name in the appropriate section
# below, without ".js", followed by ": PASS,FLAKY". Example:
# sample-test : PASS,FLAKY
[true] # This section applies to all platforms
[$system==win32]
[$system==macos]
[$arch==arm || $arch==arm64]
[$system==solaris] # Also applies to SmartOS
# https://github.com/nodejs/node/issues/43457
test-heapsnapshot-near-heap-limit: PASS,FLAKY
[$system==freebsd]
[$system==aix]
[$system==ibmi]
# https://github.com/nodejs/node/issues/39683
test-regress-GH-892: PASS, FLAKY

View File

@ -0,0 +1,27 @@
'use strict';
// This tests that Blob.prototype.slice() works correctly when the size of the
// Blob is outside the range of 32-bit signed integers.
const common = require('../common');
// Buffer with size > INT32_MAX
common.skipIf32Bits();
const assert = require('assert');
const size = 2 ** 31;
try {
const buf = Buffer.allocUnsafe(size);
const blob = new Blob([buf]);
const slicedBlob = blob.slice(size - 1, size);
assert.strictEqual(slicedBlob.size, 1);
} catch (e) {
if (e.code === 'ERR_MEMORY_ALLOCATION_FAILED') {
common.skip('insufficient space for Buffer.allocUnsafe');
}
if (/Array buffer allocation failed/.test(e.message)) {
common.skip('insufficient space for Blob.prototype.slice()');
}
throw e;
}

View File

@ -0,0 +1,18 @@
'use strict';
const common = require('../common');
// Buffer with size > INT32_MAX
common.skipIf32Bits();
const assert = require('node:assert');
const size = 2 ** 31;
// Test Buffer.allocUnsafe with size larger than integer range
try {
assert.throws(() => Buffer.allocUnsafeSlow(size).toString('utf8'), { code: 'ERR_STRING_TOO_LONG' });
} catch (e) {
if (e.code !== 'ERR_MEMORY_ALLOCATION_FAILED') {
throw e;
}
common.skip('insufficient space for Buffer.allocUnsafeSlow');
}

View File

@ -0,0 +1,18 @@
'use strict';
const common = require('../common');
// Buffer with size > INT32_MAX
common.skipIf32Bits();
const assert = require('node:assert');
const size = 2 ** 31;
try {
// Test Buffer.allocUnsafe with size larger than integer range
assert.throws(() => Buffer.allocUnsafe(size).toString('utf8'), { code: 'ERR_STRING_TOO_LONG' });
} catch (e) {
if (e.code !== 'ERR_MEMORY_ALLOCATION_FAILED') {
throw e;
}
common.skip('insufficient space for Buffer.allocUnsafe');
}

View File

@ -0,0 +1,18 @@
'use strict';
const common = require('../common');
// Buffer with size > INT32_MAX
common.skipIf32Bits();
const assert = require('node:assert');
const size = 2 ** 31;
// Test Buffer.alloc with size larger than integer range
try {
assert.throws(() => Buffer.alloc(size).toString('utf8'), { code: 'ERR_STRING_TOO_LONG' });
} catch (e) {
if (e.code !== 'ERR_MEMORY_ALLOCATION_FAILED') {
throw e;
}
common.skip('insufficient space for Buffer.alloc');
}

View File

@ -0,0 +1,22 @@
'use strict';
const common = require('../common');
// Buffer with size > INT32_MAX
common.skipIf32Bits();
const assert = require('node:assert');
const kStringMaxLength = require('buffer').constants.MAX_STRING_LENGTH;
const size = 2 ** 31;
// Test Buffer.write with size larger than integer range
try {
const buf = Buffer.alloc(size);
assert.strictEqual(buf.write('a', 2, kStringMaxLength), 1);
assert.strictEqual(buf.write('a', 2, size), 1);
} catch (e) {
if (e.code !== 'ERR_MEMORY_ALLOCATION_FAILED') {
throw e;
}
common.skip('insufficient space for Buffer.alloc');
}

View File

@ -0,0 +1,22 @@
'use strict';
const common = require('../common');
// Buffer with size > INT32_MAX
common.skipIf32Bits();
const assert = require('node:assert');
const {
SlowBuffer,
} = require('node:buffer');
const size = 2 ** 31;
// Test SlowBuffer with size larger than integer range
try {
assert.throws(() => SlowBuffer(size).toString('utf8'), { code: 'ERR_STRING_TOO_LONG' });
} catch (e) {
if (e.code !== 'ERR_MEMORY_ALLOCATION_FAILED') {
throw e;
}
common.skip('insufficient space for SlowBuffer');
}

View File

@ -0,0 +1,61 @@
// 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 spawn = require('child_process').spawn;
const python = process.env.PYTHON || (common.isWindows ? 'python' : 'python3');
const SIZE = 1000 * 1024;
const N = 40;
let finished = false;
function doSpawn(i) {
const child = spawn(python, ['-c', `print(${SIZE} * "C")`]);
let count = 0;
child.stdout.setEncoding('ascii');
child.stdout.on('data', (chunk) => {
count += chunk.length;
});
child.stderr.on('data', (chunk) => {
console.log(`stderr: ${chunk}`);
});
child.on('close', () => {
// + 1 for \n or + 2 for \r\n on Windows
assert.strictEqual(count, SIZE + (common.isWindows ? 2 : 1));
if (i < N) {
doSpawn(i + 1);
} else {
finished = true;
}
});
}
doSpawn(0);
process.on('exit', () => {
assert.ok(finished);
});

View File

@ -0,0 +1,61 @@
// 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.hasCrypto) {
common.skip('node compiled without OpenSSL.');
}
if (common.isPi()) {
common.skip('Too slow for Raspberry Pi devices');
}
const { hasOpenSSL3 } = require('../common/crypto');
if (!hasOpenSSL3) {
common.skip('Too slow when dynamically linked against OpenSSL 1.1.1');
}
const assert = require('assert');
const crypto = require('crypto');
const hashes = {
modp1: '630e9acd2cc63f7e80d8507624ba60ac0757201a',
modp2: '18f7aa964484137f57bca64b21917a385b6a0b60',
modp5: 'c0a8eec0c2c8a5ec2f9c26f9661eb339a010ec61',
modp14: 'af5455606fe74cec49782bb374e4c63c9b1d132c',
modp15: '7bdd39e5cdbb9748113933e5c2623b559c534e74',
modp16: 'daea5277a7ad0116e734a8e0d2f297ef759d1161',
modp17: '3b62aaf0142c2720f0bf26a9589b0432c00eadc1',
modp18: 'a870b491bbbec9b131ae9878d07449d32e54f160',
};
for (const name in hashes) {
const group = crypto.getDiffieHellman(name);
const prime = group.getPrime('hex');
const hash1 = hashes[name];
const hash2 = crypto.createHash('sha1')
.update(prime.toUpperCase()).digest('hex');
assert.strictEqual(hash1, hash2);
assert.strictEqual(group.getGenerator('hex'), '02');
}

View File

@ -0,0 +1,49 @@
// 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.hasCrypto) {
common.skip('node compiled without OpenSSL.');
}
if (common.isPi()) {
common.skip('Too slow for Raspberry Pi devices');
}
const assert = require('assert');
const crypto = require('crypto');
[ 'modp1', 'modp2', 'modp5', 'modp14', 'modp15', 'modp16', 'modp17' ]
.forEach((name) => {
// modp1 is 768 bits, FIPS requires >= 1024
if (name === 'modp1' && crypto.getFips()) {
return;
}
const group1 = crypto.getDiffieHellman(name);
const group2 = crypto.getDiffieHellman(name);
group1.generateKeys();
group2.generateKeys();
const key1 = group1.computeSecret(group2.getPublicKey());
const key2 = group2.computeSecret(group1.getPublicKey());
assert.deepStrictEqual(key1, key2);
});

View File

@ -0,0 +1,60 @@
// 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.hasCrypto) {
common.skip('missing crypto');
}
if (common.isPi()) {
common.skip('Too slow for Raspberry Pi devices');
}
const assert = require('assert');
const crypto = require('crypto');
const { hasOpenSSL3 } = require('../common/crypto');
// FIPS requires length >= 1024 but we use 512/256 in this test to keep it from
// taking too long and timing out in CI.
const length = crypto.getFips() ? 1024 : hasOpenSSL3 ? 512 : 256;
const p = crypto.createDiffieHellman(length).getPrime();
for (let i = 0; i < 2000; i++) {
const a = crypto.createDiffieHellman(p);
const b = crypto.createDiffieHellman(p);
a.generateKeys();
b.generateKeys();
const aSecret = a.computeSecret(b.getPublicKey());
const bSecret = b.computeSecret(a.getPublicKey());
assert.deepStrictEqual(
aSecret,
bSecret,
'Secrets should be equal.\n' +
`aSecret: ${aSecret.toString('base64')}\n` +
`bSecret: ${bSecret.toString('base64')}`,
);
}

View File

@ -0,0 +1,56 @@
// 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');
tmpdir.refresh();
try {
const filepath = tmpdir.resolve('large.txt');
const fd = fs.openSync(filepath, 'w+');
const offset = 5 * 1024 * 1024 * 1024; // 5GB
const message = 'Large File';
fs.ftruncateSync(fd, offset);
assert.strictEqual(fs.statSync(filepath).size, offset);
const writeBuf = Buffer.from(message);
fs.writeSync(fd, writeBuf, 0, writeBuf.length, offset);
const readBuf = Buffer.allocUnsafe(writeBuf.length);
fs.readSync(fd, readBuf, 0, readBuf.length, offset);
assert.strictEqual(readBuf.toString(), message);
fs.readSync(fd, readBuf, 0, 1, 0);
assert.strictEqual(readBuf[0], 0);
// Verify that floating point positions do not throw.
fs.writeSync(fd, writeBuf, 0, writeBuf.length, 42.000001);
fs.close(fd, common.mustCall());
} catch (e) {
if (e.code !== 'ENOSPC') {
throw e;
}
common.skip('insufficient disk space');
}

View File

@ -0,0 +1,54 @@
'use strict';
const common = require('../common');
if (common.isIBMi)
common.skip('On IBMi, the rss memory always returns zero');
// This test verifies that readFileSync does not leak memory when reading
// UTF8 files. See: https://github.com/nodejs/node/issues/57800 for details.
const assert = require('node:assert');
const fs = require('node:fs');
const util = require('node:util');
const tmpdir = require('../common/tmpdir');
// The memory leak being tested here was from a buffer with the absolute URI to
// a file. For each file read, 2-4 bytes were (usually) leaked per character in
// the URI. The length of the file path can be used to estimate the approximate
// amount of memory that will be leaked if this issue is reintroduced. A longer
// total path length will make the issue easier to test for. Some operating
// systems like Windows have shorter default path length limits. If the path
// is approaching that limit, the length of the path should be long enough to
// effectively test for this memory leak.
tmpdir.refresh();
let testFile = tmpdir.resolve(
'a-file-with-a-longer-than-usual-file-name-for-testing-a-memory-leak-related-to-path-length.txt',
);
if (testFile.length > process.env.MAX_PATH) {
testFile = tmpdir.resolve('reasonable-length.txt');
}
// The buffer being checked is WCHAR buffer. The size is going to be at least 2
// bytes per character but can be more. Windows: 2; Mac: 2; Linux: 4 (usually);
const iterations = 100_000;
const minExpectedMemoryLeak = (testFile.length * 2) * iterations;
// This memory leak was exclusive to UTF8 encoded files.
// Create our test file. The contents of the file don't matter.
const options = { encoding: 'utf8' };
fs.writeFileSync(testFile, '', options);
// Doing an initial big batch of file reads gives a more stable baseline memory
// usage. Doing the same total iterations as the actual test isn't necessary.
for (let i = 0; i < 100; i++) {
fs.readFileSync(testFile, options);
}
const startMemory = process.memoryUsage();
for (let i = 0; i < iterations; i++) {
fs.readFileSync(testFile, options);
}
const endMemory = process.memoryUsage();
// Use 90% of the expected memory leak as the threshold just to be safe.
const memoryDifference = endMemory.rss - startMemory.rss;
assert.ok(memoryDifference < (minExpectedMemoryLeak * 0.9),
`Unexpected memory overhead: ${util.inspect([startMemory, endMemory])}`);

View File

@ -0,0 +1,78 @@
'use strict';
const common = require('../common');
if (!common.enoughTestMem)
common.skip('intensive toString tests due to memory confinements');
const assert = require('assert');
const fs = require('fs');
const cp = require('child_process');
const kStringMaxLength = require('buffer').constants.MAX_STRING_LENGTH;
const size = Math.floor(kStringMaxLength / 200);
if (common.isAIX && (Number(cp.execSync('ulimit -f')) * 512) < kStringMaxLength)
common.skip('intensive toString tests due to file size confinements');
const tmpdir = require('../common/tmpdir');
tmpdir.refresh();
if (!tmpdir.hasEnoughSpace(kStringMaxLength + size)) {
common.skip(`Not enough space in ${tmpdir.path}`);
}
const file = tmpdir.resolve('toobig.txt');
const stream = fs.createWriteStream(file, {
flags: 'a',
});
stream.on('error', (err) => { throw err; });
const a = Buffer.alloc(size, 'a');
let expectedSize = 0;
for (let i = 0; i < 201; i++) {
stream.write(a, (err) => { assert.ifError(err); });
expectedSize += a.length;
}
stream.end();
stream.on('finish', common.mustCall(function() {
assert.strictEqual(stream.bytesWritten, expectedSize,
`${stream.bytesWritten} bytes written (expected ${expectedSize} bytes).`);
fs.readFile(file, 'utf8', common.mustCall(function(err, buf) {
assert.ok(err instanceof Error);
if (err.message !== 'Array buffer allocation failed') {
const stringLengthHex = kStringMaxLength.toString(16);
common.expectsError({
message: 'Cannot create a string longer than ' +
`0x${stringLengthHex} characters`,
code: 'ERR_STRING_TOO_LONG',
name: 'Error',
})(err);
}
assert.strictEqual(buf, undefined);
}));
}));
function destroy() {
try {
fs.unlinkSync(file);
} catch {
// it may not exist
}
}
process.on('exit', destroy);
process.on('SIGINT', function() {
destroy();
process.exit();
});
// To make sure we don't leave a very large file
// on test machines in the event this test fails.
process.on('uncaughtException', function(err) {
destroy();
throw err;
});

View File

@ -0,0 +1,81 @@
// 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 fs = require('fs');
const tmpdir = require('../common/tmpdir');
tmpdir.refresh();
const FILENAME = tmpdir.resolve('watch-me');
const TIMEOUT = 1300;
let nevents = 0;
try {
fs.unlinkSync(FILENAME);
} catch {
// swallow
}
fs.watchFile(FILENAME, { interval: TIMEOUT - 250 }, function(curr, prev) {
console.log([curr, prev]);
switch (++nevents) {
case 1:
assert.strictEqual(fs.existsSync(FILENAME), false);
break;
case 2:
case 3:
assert.strictEqual(fs.existsSync(FILENAME), true);
break;
case 4:
assert.strictEqual(fs.existsSync(FILENAME), false);
fs.unwatchFile(FILENAME);
break;
default:
assert(0);
}
});
process.on('exit', function() {
assert.strictEqual(nevents, 4);
});
setTimeout(createFile, TIMEOUT);
function createFile() {
console.log('creating file');
fs.writeFileSync(FILENAME, 'test');
setTimeout(touchFile, TIMEOUT);
}
function touchFile() {
console.log('touch file');
fs.writeFileSync(FILENAME, 'test');
setTimeout(removeFile, TIMEOUT);
}
function removeFile() {
console.log('remove file');
fs.unlinkSync(FILENAME);
}

View File

@ -0,0 +1,132 @@
// 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 path = require('path');
const fs = require('fs');
const tmpdir = require('../common/tmpdir');
let watchSeenOne = 0;
let watchSeenTwo = 0;
let watchSeenThree = 0;
let watchSeenFour = 0;
const testDir = tmpdir.path;
const filenameOne = 'watch.txt';
const filepathOne = path.join(testDir, filenameOne);
const filenameTwo = 'hasOwnProperty';
const filepathTwo = filenameTwo;
const filepathTwoAbs = path.join(testDir, filenameTwo);
const filenameThree = 'charm'; // Because the third time is
const filenameFour = 'get';
process.on('exit', function() {
assert.strictEqual(watchSeenOne, 1);
assert.strictEqual(watchSeenTwo, 2);
assert.strictEqual(watchSeenThree, 1);
assert.strictEqual(watchSeenFour, 1);
});
tmpdir.refresh();
fs.writeFileSync(filepathOne, 'hello');
assert.throws(
() => { fs.watchFile(filepathOne); },
{ code: 'ERR_INVALID_ARG_TYPE' },
);
// Does not throw.
fs.watchFile(filepathOne, function() {
fs.unwatchFile(filepathOne);
++watchSeenOne;
});
setTimeout(function() {
fs.writeFileSync(filepathOne, 'world');
}, 1000);
process.chdir(testDir);
fs.writeFileSync(filepathTwoAbs, 'howdy');
assert.throws(
() => { fs.watchFile(filepathTwo); },
{ code: 'ERR_INVALID_ARG_TYPE' },
);
{ // Does not throw.
function a() {
fs.unwatchFile(filepathTwo, a);
++watchSeenTwo;
}
function b() {
fs.unwatchFile(filepathTwo, b);
++watchSeenTwo;
}
fs.watchFile(filepathTwo, a);
fs.watchFile(filepathTwo, b);
}
setTimeout(function() {
fs.writeFileSync(filepathTwoAbs, 'pardner');
}, 1000);
{ // Does not throw.
function b() {
fs.unwatchFile(filenameThree, b);
++watchSeenThree;
}
const uncalledListener = common.mustNotCall();
fs.watchFile(filenameThree, uncalledListener);
fs.watchFile(filenameThree, b);
fs.unwatchFile(filenameThree, uncalledListener);
}
setTimeout(function() {
fs.writeFileSync(filenameThree, 'pardner');
}, 1000);
setTimeout(function() {
fs.writeFileSync(filenameFour, 'hey');
}, 200);
setTimeout(function() {
fs.writeFileSync(filenameFour, 'hey');
}, 500);
{ // Does not throw.
function a() {
++watchSeenFour;
assert.strictEqual(watchSeenFour, 1);
fs.unwatchFile(`.${path.sep}${filenameFour}`, a);
}
fs.watchFile(filenameFour, a);
}

View File

@ -0,0 +1,61 @@
// 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.isIBMi) {
common.skip('IBMi does not support fs.watch()');
}
const path = require('path');
const fs = require('fs');
const assert = require('assert');
const tmpdir = require('../common/tmpdir');
tmpdir.refresh();
const testDir = tmpdir.path;
const testsubdir = path.join(testDir, 'testsubdir');
const filepath = path.join(testsubdir, 'watch.txt');
fs.mkdirSync(testsubdir, 0o700);
function doWatch() {
const watcher = fs.watch(testDir, { persistent: true }, (event, filename) => {
// This function may be called with the directory depending on timing but
// must not be called with the file..
assert.strictEqual(filename, 'testsubdir');
});
setTimeout(() => {
fs.writeFileSync(filepath, 'test');
}, 100);
setTimeout(() => {
watcher.close();
}, 500);
}
if (common.isMacOS) {
// On macOS delay watcher start to avoid leaking previous events.
// Refs: https://github.com/libuv/libuv/pull/4503
setTimeout(doWatch, common.platformTimeout(100));
} else {
doWatch();
}

View File

@ -0,0 +1,70 @@
'use strict';
const common = require('../common');
const assert = require('assert');
const child_process = require('child_process');
const fs = require('fs');
const stream = require('stream');
if (!common.isLinux) {
common.skip('The fs watch limit is OS-dependent');
}
if (common.isPi()) {
common.skip('Too slow for Raspberry Pi devices');
}
try {
// Ensure inotify limit is low enough for the test to actually exercise the
// limit with small enough resources.
const limit = Number(
fs.readFileSync('/proc/sys/fs/inotify/max_user_watches', 'utf8'));
if (limit > 16384)
common.skip('inotify limit is quite large');
} catch (e) {
if (e.code === 'ENOENT')
common.skip('the inotify /proc subsystem does not exist');
// Fail on other errors.
throw e;
}
const processes = [];
const gatherStderr = new stream.PassThrough();
gatherStderr.setEncoding('utf8');
gatherStderr.setMaxListeners(Infinity);
let finished = false;
function spawnProcesses() {
for (let i = 0; i < 10; ++i) {
const proc = child_process.spawn(
process.execPath,
[ '-e',
`process.chdir(${JSON.stringify(__dirname)});
for (const file of fs.readdirSync('.'))
fs.watch(file, () => {});`,
], { stdio: ['inherit', 'inherit', 'pipe'] });
proc.stderr.pipe(gatherStderr);
processes.push(proc);
}
setTimeout(() => {
if (!finished && processes.length < 200)
spawnProcesses();
}, 100);
}
spawnProcesses();
let accumulated = '';
gatherStderr.on('data', common.mustCallAtLeast((chunk) => {
accumulated += chunk;
if (accumulated.includes('Error:') && !finished) {
assert(
accumulated.includes('ENOSPC: System limit for number ' +
'of file watchers reached') ||
accumulated.includes('EMFILE: '),
accumulated);
console.log(`done after ${processes.length} processes, cleaning up`);
finished = true;
processes.forEach((proc) => proc.kill());
}
}, 1));

View File

@ -0,0 +1,31 @@
'use strict';
// This tests heap snapshot integration of dns ChannelWrap.
require('../common');
const { validateByRetainingPath } = require('../common/heap');
const assert = require('assert');
// Before dns is loaded, no ChannelWrap should be created.
{
const nodes = validateByRetainingPath('Node / ChannelWrap', []);
assert.strictEqual(nodes.length, 0);
}
const dns = require('dns');
// Right after dns is loaded, a ChannelWrap should be created for the default
// resolver, but it has no task list.
{
validateByRetainingPath('Node / ChannelWrap', [
{ node_name: 'ChannelWrap', edge_name: 'native_to_javascript' },
]);
}
dns.resolve('localhost', () => {});
// After dns resolution, the ChannelWrap of the default resolver has the task list.
{
validateByRetainingPath('Node / ChannelWrap', [
{ node_name: 'Node / NodeAresTask::List', edge_name: 'task_list' },
]);
}

View File

@ -0,0 +1,28 @@
'use strict';
// This tests that Environment is tracked in heap snapshots.
// Tests for BaseObject and cppgc-managed objects are done in other
// test-heapdump-*.js files.
require('../common');
const { createJSHeapSnapshot, validateByRetainingPathFromNodes } = require('../common/heap');
const nodes = createJSHeapSnapshot();
const envs = validateByRetainingPathFromNodes(nodes, 'Node / Environment', []);
validateByRetainingPathFromNodes(envs, 'Node / Environment', [
{ node_name: 'Node / CleanupQueue', edge_name: 'cleanup_queue' },
]);
validateByRetainingPathFromNodes(envs, 'Node / Environment', [
{ node_name: 'Node / IsolateData', edge_name: 'isolate_data' },
]);
const realms = validateByRetainingPathFromNodes(envs, 'Node / Environment', [
{ node_name: 'Node / PrincipalRealm', edge_name: 'principal_realm' },
]);
validateByRetainingPathFromNodes(realms, 'Node / PrincipalRealm', [
{ node_name: 'process', edge_name: 'process_object' },
]);
validateByRetainingPathFromNodes(realms, 'Node / PrincipalRealm', [
{ node_name: 'Node / BaseObjectList', edge_name: 'base_object_list' },
]);

View File

@ -0,0 +1,26 @@
'use strict';
// This tests heap snapshot integration of fs promise.
require('../common');
const { validateByRetainingPath, validateByRetainingPathFromNodes } = require('../common/heap');
const fs = require('fs').promises;
const assert = require('assert');
// Before fs promise is used, no FSReqPromise should be created.
{
const nodes = validateByRetainingPath('Node / FSReqPromise', []);
assert.strictEqual(nodes.length, 0);
}
fs.stat(__filename);
{
const nodes = validateByRetainingPath('Node / FSReqPromise', []);
validateByRetainingPathFromNodes(nodes, 'Node / FSReqPromise', [
{ node_name: 'FSReqPromise', edge_name: 'native_to_javascript' },
]);
validateByRetainingPathFromNodes(nodes, 'Node / FSReqPromise', [
{ node_name: 'Node / AliasedFloat64Array', edge_name: 'stats_field_array' },
]);
}

View File

@ -0,0 +1,76 @@
'use strict';
// This tests heap snapshot integration of http2.
const common = require('../common');
const { createJSHeapSnapshot, validateByRetainingPath, validateByRetainingPathFromNodes } = require('../common/heap');
const assert = require('assert');
if (!common.hasCrypto)
common.skip('missing crypto');
const http2 = require('http2');
// Before http2 is used, no Http2Session or Http2Streamshould be created.
{
const sessions = validateByRetainingPath('Node / Http2Session', []);
assert.strictEqual(sessions.length, 0);
const streams = validateByRetainingPath('Node / Http2Stream', []);
assert.strictEqual(streams.length, 0);
}
const server = http2.createServer();
server.on('stream', (stream) => {
stream.respondWithFile(process.execPath);
});
server.listen(0, () => {
const client = http2.connect(`http://localhost:${server.address().port}`);
const req = client.request();
req.on('response', common.mustCall(() => {
const nodes = createJSHeapSnapshot();
// `Node / Http2Stream` (C++) -> Http2Stream (JS)
validateByRetainingPathFromNodes(nodes, 'Node / Http2Stream', [
// current_headers and/or queue could be empty
{ node_name: 'Http2Stream', edge_name: 'native_to_javascript' },
]);
// `Node / FileHandle` (C++) -> FileHandle (JS)
validateByRetainingPathFromNodes(nodes, 'Node / FileHandle', [
{ node_name: 'FileHandle', edge_name: 'native_to_javascript' },
// current_headers could be empty
]);
validateByRetainingPathFromNodes(nodes, 'Node / TCPSocketWrap', [
{ node_name: 'TCP', edge_name: 'native_to_javascript' },
]);
validateByRetainingPathFromNodes(nodes, 'Node / TCPServerWrap', [
{ node_name: 'TCP', edge_name: 'native_to_javascript' },
]);
// We don't necessarily have Node / StreamPipe here because by the time the
// response event is emitted, the file may have already been fully piped here
// and the stream pipe may have been destroyed.
// `Node / Http2Session` (C++) -> Http2Session (JS)
const sessions = validateByRetainingPathFromNodes(nodes, 'Node / Http2Session', []);
validateByRetainingPathFromNodes(sessions, 'Node / Http2Session', [
{ node_name: 'Http2Session', edge_name: 'native_to_javascript' },
]);
validateByRetainingPathFromNodes(sessions, 'Node / Http2Session', [
{ node_name: 'Node / nghttp2_memory', edge_name: 'nghttp2_memory' },
]);
validateByRetainingPathFromNodes(sessions, 'Node / Http2Session', [
{ node_name: 'Node / streams', edge_name: 'streams' },
]);
// outstanding_pings, outgoing_buffers, outgoing_storage,
// pending_rst_streams could be empty
}));
req.resume();
req.on('end', common.mustCall(() => {
client.close();
server.close();
}));
req.end();
});

View File

@ -0,0 +1,29 @@
'use strict';
// This tests heap snapshot integration of inspector.
const common = require('../common');
const assert = require('assert');
common.skipIfInspectorDisabled();
const { validateByRetainingPath, validateByRetainingPathFromNodes } = require('../common/heap');
const inspector = require('inspector');
// Starts with no JSBindingsConnection.
{
const nodes = validateByRetainingPath('Node / JSBindingsConnection', []);
assert.strictEqual(nodes.length, 0);
}
// JSBindingsConnection should be added once inspector session is created.
{
const session = new inspector.Session();
session.connect();
const nodes = validateByRetainingPath('Node / JSBindingsConnection', []);
validateByRetainingPathFromNodes(nodes, 'Node / JSBindingsConnection', [
{ node_name: 'Node / InspectorSession', edge_name: 'session' },
]);
validateByRetainingPathFromNodes(nodes, 'Node / JSBindingsConnection', [
{ node_name: 'Connection', edge_name: 'native_to_javascript' },
]);
}

View File

@ -0,0 +1,39 @@
// Flags: --experimental-shadow-realm
// This tests heap snapshot integration of ShadowRealm
'use strict';
require('../common');
const { validateByRetainingPath } = require('../common/heap');
const assert = require('assert');
// Before shadow realm is created, no ShadowRealm should be captured.
{
const nodes = validateByRetainingPath('Node / ShadowRealm', []);
assert.strictEqual(nodes.length, 0);
}
let realm;
let counter = 0;
// Create a bunch of un-referenced ShadowRealms to make sure the heap
// snapshot can handle it.
function createRealms() {
// Use setImmediate to give GC some time to kick in to avoid OOM.
if (counter++ < 10) {
realm = new ShadowRealm();
realm.evaluate('undefined');
setImmediate(createRealms);
} else {
validateHeap();
// Keep the realm alive.
realm.evaluate('undefined');
}
}
function validateHeap() {
validateByRetainingPath('Node / Environment', [
{ node_name: 'Node / shadow_realms', edge_name: 'shadow_realms' },
{ node_name: 'Node / ShadowRealm' },
]);
}
createRealms();

View File

@ -0,0 +1,41 @@
'use strict';
// This tests heap snapshot integration of tls sockets.
const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');
const { validateByRetainingPath, validateByRetainingPathFromNodes } = require('../common/heap');
const assert = require('assert');
const net = require('net');
const tls = require('tls');
// Before tls is used, no TLSWrap should be created.
{
const nodes = validateByRetainingPath('Node / TLSWrap', []);
assert.strictEqual(nodes.length, 0);
}
const server = net.createServer(common.mustCall((c) => {
c.end();
})).listen(0, common.mustCall(() => {
const c = tls.connect({ port: server.address().port });
c.on('error', common.mustCall(() => {
server.close();
}));
c.write('hello');
const nodes = validateByRetainingPath('Node / TLSWrap', []);
validateByRetainingPathFromNodes(nodes, 'Node / TLSWrap', [
{ node_name: 'Node / NodeBIO', edge_name: 'enc_out' },
]);
validateByRetainingPathFromNodes(nodes, 'Node / TLSWrap', [
{ node_name: 'Node / NodeBIO', edge_name: 'enc_in' },
]);
validateByRetainingPathFromNodes(nodes, 'Node / TLSWrap', [
// `Node / TLSWrap` (C++) -> `TLSWrap` (JS)
{ node_name: 'TLSWrap', edge_name: 'native_to_javascript' },
// pending_cleartext_input could be empty
]);
}));

View File

@ -0,0 +1,24 @@
'use strict';
// This tests heap snapshot integration of URLPattern.
require('../common');
const { validateByRetainingPath } = require('../common/heap');
const { URLPattern } = require('node:url');
const assert = require('assert');
// Before url pattern is used, no URLPattern should be created.
{
const nodes = validateByRetainingPath('Node / URLPattern', []);
assert.strictEqual(nodes.length, 0);
}
const urlPattern = new URLPattern('https://example.com/:id');
// After url pattern is used, a URLPattern should be created.
validateByRetainingPath('Node / URLPattern', [
{ node_name: 'Node / ada::url_pattern', edge_name: 'url_pattern' },
// ada::url_pattern references ada::url_pattern_component.
{ node_name: 'Node / ada::url_pattern_component', edge_name: 'protocol_component' },
]);
// Use `urlPattern`.
console.log(urlPattern);

View File

@ -0,0 +1,13 @@
'use strict';
require('../common');
const { validateByRetainingPath } = require('../common/heap');
const source = 'const foo = 123';
const script = require('vm').createScript(source);
validateByRetainingPath('Node / ContextifyScript', [
{ node_name: '(shared function info)' }, // This is the UnboundScript referenced by ContextifyScript.
{ edge_name: 'script' },
{ edge_name: 'source', node_type: 'string', node_name: source },
]);
console.log(script); // Keep the script alive.

View File

@ -0,0 +1,27 @@
'use strict';
// This tests heap snapshot integration of worker.
require('../common');
const { validateByRetainingPath } = require('../common/heap');
const { Worker } = require('worker_threads');
const assert = require('assert');
// Before worker is used, no MessagePort should be created.
{
const nodes = validateByRetainingPath('Node / Worker', []);
assert.strictEqual(nodes.length, 0);
}
const worker = new Worker('setInterval(() => {}, 100);', { eval: true });
// When a worker is alive, a Worker instance and its message port should be captured.
{
validateByRetainingPath('Node / Worker', [
{ node_name: 'Worker', edge_name: 'native_to_javascript' },
{ node_name: 'MessagePort', edge_name: 'messagePort' },
{ node_name: 'Node / MessagePort', edge_name: 'javascript_to_native' },
{ node_name: 'Node / MessagePortData', edge_name: 'data' },
]);
}
worker.terminate();

View File

@ -0,0 +1,35 @@
'use strict';
// This tests heap snapshot integration of zlib stream.
const common = require('../common');
const assert = require('assert');
const { validateByRetainingPath, validateByRetainingPathFromNodes } = require('../common/heap');
const zlib = require('zlib');
// Before zlib stream is created, no ZlibStream should be created.
{
const nodes = validateByRetainingPath('Node / ZlibStream', []);
assert.strictEqual(nodes.length, 0);
}
const gzip = zlib.createGzip();
// After zlib stream is created, a ZlibStream should be created.
{
const streams = validateByRetainingPath('Node / ZlibStream', []);
validateByRetainingPathFromNodes(streams, 'Node / ZlibStream', [
{ node_name: 'Zlib', edge_name: 'native_to_javascript' },
]);
// No entry for memory because zlib memory is initialized lazily.
const withMemory = validateByRetainingPathFromNodes(streams, 'Node / ZlibStream', [
{ node_name: 'Node / zlib_memory', edge_name: 'zlib_memory' },
], true);
assert.strictEqual(withMemory.length, 0);
}
// After zlib stream is written, zlib_memory should be created.
gzip.write('hello world', common.mustCall(() => {
validateByRetainingPath('Node / ZlibStream', [
{ node_name: 'Node / zlib_memory', edge_name: 'zlib_memory' },
]);
}));

View File

@ -0,0 +1,42 @@
'use strict';
const common = require('../common');
const tmpdir = require('../common/tmpdir');
const assert = require('assert');
const { spawnSync } = require('child_process');
const fixtures = require('../common/fixtures');
const fs = require('fs');
const env = {
...process.env,
NODE_DEBUG_NATIVE: 'diagnostics',
};
if (!common.enoughTestMem)
common.skip('Insufficient memory for snapshot test');
{
console.log('\nTesting limit = 3');
tmpdir.refresh();
const child = spawnSync(process.execPath, [
'--heapsnapshot-near-heap-limit=3',
'--max-old-space-size=512',
fixtures.path('workload', 'grow.js'),
], {
cwd: tmpdir.path,
env: {
...env,
TEST_CHUNK: 2000,
},
});
const stderr = child.stderr.toString();
console.log(stderr);
assert(common.nodeProcessAborted(child.status, child.signal),
'process should have aborted, but did not');
const list = fs.readdirSync(tmpdir.path)
.filter((file) => file.endsWith('.heapsnapshot'));
const risky = [...stderr.matchAll(
/Not generating snapshots because it's too risky/g)].length;
assert(list.length + risky > 0 && list.length <= 3,
`Generated ${list.length} snapshots ` +
`and ${risky} was too risky`);
}

View File

@ -0,0 +1,41 @@
'use strict';
const common = require('../common');
if (common.isPi()) {
common.skip('Too slow for Raspberry Pi devices');
}
const tmpdir = require('../common/tmpdir');
const assert = require('assert');
const { spawnSync } = require('child_process');
const fixtures = require('../common/fixtures');
const fs = require('fs');
const env = {
...process.env,
TEST_ALLOCATION: 50000,
TEST_CHUNK: 1000,
TEST_CLEAN_INTERVAL: 500,
NODE_DEBUG_NATIVE: 'diagnostics',
};
{
console.log('\nTesting limit = 1');
tmpdir.refresh();
const child = spawnSync(process.execPath, [
'--trace-gc',
'--heapsnapshot-near-heap-limit=1',
'--max-old-space-size=50',
fixtures.path('workload', 'bounded.js'),
], {
cwd: tmpdir.path,
env,
});
console.log(child.stdout.toString());
console.log(child.stderr.toString());
assert.strictEqual(child.signal, null);
assert.strictEqual(child.status, 0);
const list = fs.readdirSync(tmpdir.path)
.filter((file) => file.endsWith('.heapsnapshot'));
assert.strictEqual(list.length, 0);
}

View File

@ -0,0 +1,144 @@
// Copy from test-heapsnapshot-near-heap-limit.js
'use strict';
const common = require('../common');
if (common.isPi()) {
common.skip('Too slow for Raspberry Pi devices');
}
const tmpdir = require('../common/tmpdir');
const assert = require('assert');
const { spawnSync } = require('child_process');
const fixtures = require('../common/fixtures');
const fs = require('fs');
const v8 = require('v8');
const invalidValues = [-1, '', {}, NaN, undefined];
for (let i = 0; i < invalidValues.length; i++) {
assert.throws(() => v8.setHeapSnapshotNearHeapLimit(invalidValues[i]),
/ERR_INVALID_ARG_TYPE|ERR_OUT_OF_RANGE/);
}
// Set twice
v8.setHeapSnapshotNearHeapLimit(1);
v8.setHeapSnapshotNearHeapLimit(2);
const env = {
...process.env,
NODE_DEBUG_NATIVE: 'diagnostics',
};
{
console.log('\nTesting set by cmd option and api');
tmpdir.refresh();
const child = spawnSync(process.execPath, [
'--trace-gc',
'--heapsnapshot-near-heap-limit=1',
'--max-old-space-size=50',
fixtures.path('workload', 'grow-and-set-near-heap-limit.js'),
], {
cwd: tmpdir.path,
env: {
...env,
limit: 2,
},
});
console.log(child.stdout.toString());
const stderr = child.stderr.toString();
console.log(stderr);
assert(common.nodeProcessAborted(child.status, child.signal),
'process should have aborted, but did not');
const list = fs.readdirSync(tmpdir.path)
.filter((file) => file.endsWith('.heapsnapshot'));
const risky = [...stderr.matchAll(
/Not generating snapshots because it's too risky/g)].length;
assert(list.length + risky > 0 && list.length <= 1,
`Generated ${list.length} snapshots ` +
`and ${risky} was too risky`);
}
{
console.log('\nTesting limit = 1');
tmpdir.refresh();
const child = spawnSync(process.execPath, [
'--trace-gc',
'--max-old-space-size=50',
fixtures.path('workload', 'grow-and-set-near-heap-limit.js'),
], {
cwd: tmpdir.path,
env: {
...env,
limit: 1,
},
});
console.log(child.stdout.toString());
const stderr = child.stderr.toString();
console.log(stderr);
assert(common.nodeProcessAborted(child.status, child.signal),
'process should have aborted, but did not');
const list = fs.readdirSync(tmpdir.path)
.filter((file) => file.endsWith('.heapsnapshot'));
const risky = [...stderr.matchAll(
/Not generating snapshots because it's too risky/g)].length;
assert(list.length + risky > 0 && list.length <= 1,
`Generated ${list.length} snapshots ` +
`and ${risky} was too risky`);
}
{
console.log('\nTesting set limit twice');
tmpdir.refresh();
const child = spawnSync(process.execPath, [
'--trace-gc',
'--max-old-space-size=50',
fixtures.path('workload', 'grow-and-set-near-heap-limit.js'),
], {
cwd: tmpdir.path,
env: {
...env,
limit: 1,
limit2: 2,
},
});
console.log(child.stdout.toString());
const stderr = child.stderr.toString();
console.log(stderr);
assert(common.nodeProcessAborted(child.status, child.signal),
'process should have aborted, but did not');
const list = fs.readdirSync(tmpdir.path)
.filter((file) => file.endsWith('.heapsnapshot'));
const risky = [...stderr.matchAll(
/Not generating snapshots because it's too risky/g)].length;
assert(list.length + risky > 0 && list.length <= 1,
`Generated ${list.length} snapshots ` +
`and ${risky} was too risky`);
}
{
console.log('\nTesting limit = 3');
tmpdir.refresh();
const child = spawnSync(process.execPath, [
'--trace-gc',
'--max-old-space-size=50',
fixtures.path('workload', 'grow-and-set-near-heap-limit.js'),
], {
cwd: tmpdir.path,
env: {
...env,
limit: 3,
},
});
console.log(child.stdout.toString());
const stderr = child.stderr.toString();
console.log(stderr);
assert(common.nodeProcessAborted(child.status, child.signal),
'process should have aborted, but did not');
const list = fs.readdirSync(tmpdir.path)
.filter((file) => file.endsWith('.heapsnapshot'));
const risky = [...stderr.matchAll(
/Not generating snapshots because it's too risky/g)].length;
assert(list.length + risky > 0 && list.length <= 3,
`Generated ${list.length} snapshots ` +
`and ${risky} was too risky`);
}

View File

@ -0,0 +1,103 @@
'use strict';
const common = require('../common');
if (common.isPi()) {
common.skip('Too slow for Raspberry Pi devices');
}
const tmpdir = require('../common/tmpdir');
const assert = require('assert');
const { spawnSync } = require('child_process');
const fixtures = require('../common/fixtures');
const fs = require('fs');
const env = {
...process.env,
NODE_DEBUG_NATIVE: 'diagnostics',
};
{
tmpdir.refresh();
const child = spawnSync(process.execPath, [
'--heapsnapshot-near-heap-limit=-15',
'--max-old-space-size=50',
fixtures.path('workload', 'grow.js'),
], {
cwd: tmpdir.path,
env,
});
assert.strictEqual(child.status, 9);
}
{
console.log('\nTesting limit = 0');
tmpdir.refresh();
const child = spawnSync(process.execPath, [
'--trace-gc',
'--heapsnapshot-near-heap-limit=0',
'--max-old-space-size=50',
fixtures.path('workload', 'grow.js'),
], {
cwd: tmpdir.path,
env,
});
console.log(child.stdout.toString());
console.log(child.stderr.toString());
assert(common.nodeProcessAborted(child.status, child.signal),
'process should have aborted, but did not');
const list = fs.readdirSync(tmpdir.path)
.filter((file) => file.endsWith('.heapsnapshot'));
assert.strictEqual(list.length, 0);
}
{
console.log('\nTesting limit = 1');
tmpdir.refresh();
const child = spawnSync(process.execPath, [
'--trace-gc',
'--heapsnapshot-near-heap-limit=1',
'--max-old-space-size=50',
fixtures.path('workload', 'grow.js'),
], {
cwd: tmpdir.path,
env,
});
console.log(child.stdout.toString());
const stderr = child.stderr.toString();
console.log(stderr);
assert(common.nodeProcessAborted(child.status, child.signal),
'process should have aborted, but did not');
const list = fs.readdirSync(tmpdir.path)
.filter((file) => file.endsWith('.heapsnapshot'));
const risky = [...stderr.matchAll(
/Not generating snapshots because it's too risky/g)].length;
assert(list.length + risky > 0 && list.length <= 1,
`Generated ${list.length} snapshots ` +
`and ${risky} was too risky`);
}
{
console.log('\nTesting limit = 3');
tmpdir.refresh();
const child = spawnSync(process.execPath, [
'--trace-gc',
'--heapsnapshot-near-heap-limit=3',
'--max-old-space-size=50',
fixtures.path('workload', 'grow.js'),
], {
cwd: tmpdir.path,
env,
});
console.log(child.stdout.toString());
const stderr = child.stderr.toString();
console.log(stderr);
assert(common.nodeProcessAborted(child.status, child.signal),
'process should have aborted, but did not');
const list = fs.readdirSync(tmpdir.path)
.filter((file) => file.endsWith('.heapsnapshot'));
const risky = [...stderr.matchAll(
/Not generating snapshots because it's too risky/g)].length;
assert(list.length + risky > 0 && list.length <= 3,
`Generated ${list.length} snapshots ` +
`and ${risky} was too risky`);
}

View File

@ -0,0 +1,69 @@
// 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 http = require('http');
const expected = 10000;
let responses = 0;
let requests = 0;
let connection;
const server = http.Server(function(req, res) {
requests++;
assert.strictEqual(req.connection, connection);
res.writeHead(200);
res.end('hello world\n');
});
server.once('connection', function(c) {
connection = c;
});
server.listen(0, function connect() {
const request = http.get({
port: server.address().port,
path: '/',
headers: {
'Connection': 'Keep-alive',
},
}, function(res) {
res.on('end', function() {
if (++responses < expected) {
connect();
} else {
server.close();
}
});
res.resume();
}).on('error', function(e) {
console.log(e.message);
process.exit(1);
});
request.agent.maxSockets = 1;
});
process.on('exit', function() {
assert.strictEqual(responses, expected);
assert.strictEqual(requests, expected);
});

View File

@ -0,0 +1,70 @@
// 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';
// This tests setTimeout() by having multiple clients connecting and sending
// data in random intervals. Clients are also randomly disconnecting until there
// are no more clients left. If no false timeout occurs, this test has passed.
const common = require('../common');
const http = require('http');
const server = http.createServer();
let connections = 0;
const ontimeout = common.mustNotCall('Unexpected timeout');
server.on('request', function(req, res) {
req.socket.setTimeout(1000);
req.socket.on('timeout', ontimeout);
req.on('end', function() {
connections--;
res.writeHead(200);
req.socket.off('timeout', ontimeout);
res.end('done\n');
if (connections === 0) {
server.close();
}
});
req.resume();
});
server.listen(0, function() {
for (let i = 0; i < 10; i++) {
connections++;
let count = 0;
setTimeout(function() {
const request = http.request({
port: server.address().port,
method: 'POST',
path: '/',
});
function ping() {
if (++count === 10) {
request.end();
return;
}
request.write('ping');
setTimeout(ping, 300);
}
ping();
}, i * 50);
}
});

View File

@ -0,0 +1,72 @@
// 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.hasCrypto)
common.skip('missing crypto');
const assert = require('assert');
const fixtures = require('../common/fixtures');
const https = require('https');
const options = {
key: fixtures.readKey('agent1-key.pem'),
cert: fixtures.readKey('agent1-cert.pem'),
};
process.stdout.write('build body...');
const body = 'hello world\n'.repeat(1024 * 1024);
process.stdout.write('done\n');
const server = https.createServer(options, common.mustCall(function(req, res) {
console.log('got request');
res.writeHead(200, { 'content-type': 'text/plain' });
res.end(body);
}));
server.listen(0, common.mustCall(function() {
https.get({
port: server.address().port,
rejectUnauthorized: false,
}, common.mustCall(function(res) {
console.log('response!');
let count = 0;
res.on('data', function(d) {
process.stdout.write('.');
count += d.length;
res.pause();
process.nextTick(function() {
res.resume();
});
});
res.on('end', common.mustCall(function(d) {
process.stdout.write('\n');
console.log('expected: ', body.length);
console.log(' got: ', count);
server.close();
assert.strictEqual(count, body.length);
}));
}));
}));

View File

@ -0,0 +1,62 @@
// 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.hasCrypto)
common.skip('missing crypto');
const assert = require('assert');
const https = require('https');
const fixtures = require('../common/fixtures');
const options = {
key: fixtures.readKey('rsa_private.pem'),
cert: fixtures.readKey('rsa_cert.crt'),
};
const buf = Buffer.allocUnsafe(1024 * 1024);
const server = https.createServer(options, function(req, res) {
res.writeHead(200);
for (let i = 0; i < 50; i++) {
res.write(buf);
}
res.end();
});
server.listen(0, function() {
const req = https.request({
method: 'POST',
port: server.address().port,
rejectUnauthorized: false,
}, function(res) {
res.read(0);
setTimeout(function() {
// Read buffer should be somewhere near high watermark
// (i.e. should not leak)
assert(res.readableLength < 100 * 1024);
process.exit(0);
}, 2000);
});
req.end();
});

View File

@ -0,0 +1,124 @@
// 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';
// This test requires the program 'wrk'.
const common = require('../common');
const child_process = require('child_process');
const result = child_process.spawnSync('wrk', ['-h']);
if (result.error && result.error.code === 'ENOENT')
common.skip('test requires `wrk` to be installed first');
const assert = require('assert');
const http = require('http');
const url = require('url');
const body = 'hello world\n';
const server = http.createServer((req, res) => {
res.writeHead(200, {
'Content-Length': body.length,
'Content-Type': 'text/plain',
});
res.write(body);
res.end();
});
let keepAliveReqSec = 0;
let normalReqSec = 0;
const runAb = (opts, callback) => {
const args = [
'-c', opts.concurrent || 50,
'-t', opts.threads || 2,
'-d', opts.duration || '5s',
];
if (!opts.keepalive) {
args.push('-H');
args.push('Connection: close');
}
args.push(url.format({ hostname: '127.0.0.1',
port: opts.port, protocol: 'http' }));
const child = child_process.spawn('wrk', args);
child.stderr.pipe(process.stderr);
child.stdout.setEncoding('utf8');
let stdout;
child.stdout.on('data', (data) => stdout += data);
child.on('close', (code, signal) => {
if (code) {
console.error(code, signal);
process.exit(code);
return;
}
let matches = /Requests\/sec:\s*(\d+)\./i.exec(stdout);
const reqSec = parseInt(matches[1]);
matches = /Keep-Alive requests:\s*(\d+)/i.exec(stdout);
let keepAliveRequests;
if (matches) {
keepAliveRequests = parseInt(matches[1]);
} else {
keepAliveRequests = 0;
}
callback(reqSec, keepAliveRequests);
});
};
server.listen(0, () => {
const port = server.address().port;
runAb({ keepalive: true, port: port }, (reqSec) => {
keepAliveReqSec = reqSec;
runAb({ keepalive: false, port: port }, (reqSec) => {
normalReqSec = reqSec;
server.close();
});
});
});
process.on('exit', () => {
assert.strictEqual(
normalReqSec > 50,
true,
`normalReqSec should be greater than 50, but got ${normalReqSec}`,
);
assert.strictEqual(
keepAliveReqSec > 50,
true,
`keepAliveReqSec should be greater than 50, but got ${keepAliveReqSec}`,
);
assert.strictEqual(
normalReqSec < keepAliveReqSec,
true,
'normalReqSec should be less than keepAliveReqSec, ' +
`but ${normalReqSec} is greater than ${keepAliveReqSec}`,
);
});

View File

@ -0,0 +1,100 @@
// 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 net = require('net');
// settings
const bytes = 1024 * 40;
const concurrency = 50;
const connections_per_client = 3;
// measured
let total_connections = 0;
const body = 'C'.repeat(bytes);
const server = net.createServer(function(c) {
total_connections++;
console.log('connected', total_connections);
c.write(body);
c.end();
});
function runClient(port, callback) {
const client = net.createConnection(port);
client.connections = 0;
client.setEncoding('utf8');
client.on('connect', function() {
console.log('c');
client.recved = '';
client.connections += 1;
});
client.on('data', function(chunk) {
this.recved += chunk;
});
client.on('end', function() {
client.end();
});
client.on('error', function(e) {
console.log('\n\nERROOOOOr');
throw e;
});
client.on('close', function(had_error) {
console.log('.');
assert.strictEqual(had_error, false);
assert.strictEqual(client.recved.length, bytes);
if (client.fd) {
console.log(client.fd);
}
assert.ok(!client.fd);
if (this.connections < connections_per_client) {
this.connect(port);
} else {
callback();
}
});
}
server.listen(0, function() {
let finished_clients = 0;
for (let i = 0; i < concurrency; i++) {
runClient(server.address().port, function() {
if (++finished_clients === concurrency) server.close();
});
}
});
process.on('exit', function() {
assert.strictEqual(total_connections, connections_per_client * concurrency);
console.log('\nokay!');
});

View File

@ -0,0 +1,91 @@
// 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 net = require('net');
const N = 200;
let recv = '';
let chars_recved = 0;
const server = net.createServer((connection) => {
function write(j) {
if (j >= N) {
connection.end();
return;
}
setTimeout(() => {
connection.write('C');
write(j + 1);
}, 10);
}
write(0);
});
server.on('listening', () => {
const client = net.createConnection(server.address().port);
client.setEncoding('ascii');
client.on('data', (d) => {
console.log(d);
recv += d;
});
setTimeout(() => {
chars_recved = recv.length;
console.log(`pause at: ${chars_recved}`);
assert.strictEqual(chars_recved > 1, true);
client.pause();
setTimeout(() => {
console.log(`resume at: ${chars_recved}`);
assert.strictEqual(chars_recved, recv.length);
client.resume();
setTimeout(() => {
chars_recved = recv.length;
console.log(`pause at: ${chars_recved}`);
client.pause();
setTimeout(() => {
console.log(`resume at: ${chars_recved}`);
assert.strictEqual(chars_recved, recv.length);
client.resume();
}, 500);
}, 500);
}, 500);
}, 500);
client.on('end', () => {
server.close();
client.end();
});
});
server.listen(0);
process.on('exit', () => {
assert.strictEqual(recv.length, N);
console.error('Exit');
});

View File

@ -0,0 +1,107 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
'use strict';
const common = require('../common');
const assert = require('assert');
const net = require('net');
function pingPongTest(host, on_complete) {
const N = 100;
const DELAY = 1;
let count = 0;
let client_ended = false;
const server = net.createServer({ allowHalfOpen: true }, function(socket) {
socket.setEncoding('utf8');
socket.on('data', function(data) {
console.log(data);
assert.strictEqual(data, 'PING');
assert.strictEqual(socket.readyState, 'open');
assert.strictEqual(count <= N, true);
setTimeout(function() {
assert.strictEqual(socket.readyState, 'open');
socket.write('PONG');
}, DELAY);
});
socket.on('timeout', function() {
console.error('server-side timeout!!');
assert.strictEqual(false, true);
});
socket.on('end', function() {
console.log('server-side socket EOF');
assert.strictEqual(socket.readyState, 'writeOnly');
socket.end();
});
socket.on('close', function(had_error) {
console.log('server-side socket.end');
assert.strictEqual(had_error, false);
assert.strictEqual(socket.readyState, 'closed');
socket.server.close();
});
});
server.listen(0, host, common.mustCall(function() {
const client = net.createConnection(server.address().port, host);
client.setEncoding('utf8');
client.on('connect', function() {
assert.strictEqual(client.readyState, 'open');
client.write('PING');
});
client.on('data', function(data) {
console.log(data);
assert.strictEqual(data, 'PONG');
assert.strictEqual(client.readyState, 'open');
setTimeout(function() {
assert.strictEqual(client.readyState, 'open');
if (count++ < N) {
client.write('PING');
} else {
console.log('closing client');
client.end();
client_ended = true;
}
}, DELAY);
});
client.on('timeout', function() {
console.error('client-side timeout!!');
assert.strictEqual(false, true);
});
client.on('close', common.mustCall(function() {
console.log('client.end');
assert.strictEqual(count, N + 1);
assert.ok(client_ended);
if (on_complete) on_complete();
}));
}));
}
pingPongTest();

View File

@ -0,0 +1,120 @@
// 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');
let tests_run = 0;
function pingPongTest(host, on_complete) {
const N = 1000;
let count = 0;
let sent_final_ping = false;
const server = net.createServer({ allowHalfOpen: true }, function(socket) {
assert.strictEqual(socket.remoteAddress !== null, true);
assert.strictEqual(socket.remoteAddress !== undefined, true);
const address = socket.remoteAddress;
if (host === '127.0.0.1') {
assert.strictEqual(address, '127.0.0.1');
} else if (host == null || host === 'localhost') {
assert(address === '127.0.0.1' || address === '::ffff:127.0.0.1' ||
address === '::1');
} else {
console.log(`host = ${host}, remoteAddress = ${address}`);
assert.strictEqual(address, '::1');
}
socket.setEncoding('utf8');
socket.setNoDelay();
socket.timeout = 0;
socket.on('data', function(data) {
console.log(`server got: ${JSON.stringify(data)}`);
assert.strictEqual(socket.readyState, 'open');
assert.strictEqual(count <= N, true);
if (/PING/.test(data)) {
socket.write('PONG');
}
});
socket.on('end', function() {
assert.strictEqual(socket.readyState, 'writeOnly');
socket.end();
});
socket.on('close', function(had_error) {
assert.strictEqual(had_error, false);
assert.strictEqual(socket.readyState, 'closed');
socket.server.close();
});
});
server.listen(0, host, function() {
const client = net.createConnection(server.address().port, host);
client.setEncoding('utf8');
client.on('connect', function() {
assert.strictEqual(client.readyState, 'open');
client.write('PING');
});
client.on('data', function(data) {
console.log(`client got: ${data}`);
assert.strictEqual(data, 'PONG');
count += 1;
if (sent_final_ping) {
assert.strictEqual(client.readyState, 'readOnly');
return;
}
assert.strictEqual(client.readyState, 'open');
if (count < N) {
client.write('PING');
} else {
sent_final_ping = true;
client.write('PING');
client.end();
}
});
client.on('close', function() {
assert.strictEqual(count, N + 1);
assert.strictEqual(sent_final_ping, true);
if (on_complete) on_complete();
tests_run += 1;
});
});
}
// All are run at once and will run on different ports.
pingPongTest(null);
pingPongTest('127.0.0.1');
if (common.hasIPv6) pingPongTest('::1');
process.on('exit', function() {
assert.strictEqual(tests_run, common.hasIPv6 ? 3 : 2);
});

View File

@ -0,0 +1,107 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
'use strict';
require('../common');
const assert = require('assert');
const net = require('net');
let exchanges = 0;
let starttime = null;
let timeouttime = null;
const timeout = 1000;
const echo_server = net.createServer((socket) => {
socket.setTimeout(timeout);
socket.on('timeout', () => {
console.log('server timeout');
timeouttime = new Date();
console.dir(timeouttime);
socket.destroy();
});
socket.on('error', (e) => {
throw new Error(
'Server side socket should not get error. We disconnect willingly.');
});
socket.on('data', (d) => {
socket.write(d);
});
socket.on('end', () => {
socket.end();
});
});
echo_server.listen(0, () => {
const port = echo_server.address().port;
console.log(`server listening at ${port}`);
const client = net.createConnection(port);
client.setEncoding('UTF8');
client.setTimeout(0); // Disable the timeout for client
client.on('connect', () => {
console.log('client connected.');
client.write('hello\r\n');
});
client.on('data', (chunk) => {
assert.strictEqual(chunk, 'hello\r\n');
if (exchanges++ < 5) {
setTimeout(() => {
console.log('client write "hello"');
client.write('hello\r\n');
}, 500);
if (exchanges === 5) {
console.log(`wait for timeout - should come in ${timeout} ms`);
starttime = new Date();
console.dir(starttime);
}
}
});
client.on('timeout', () => {
throw new Error("client timeout - this shouldn't happen");
});
client.on('end', () => {
console.log('client end');
client.end();
});
client.on('close', () => {
console.log('client disconnect');
echo_server.close();
});
});
process.on('exit', () => {
assert.ok(starttime != null);
assert.ok(timeouttime != null);
const diff = timeouttime - starttime;
console.log(`diff = ${diff}`);
assert.ok(timeout < diff);
});

View File

@ -0,0 +1,54 @@
// 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';
// socket.write was not resetting the timeout timer. See
// https://github.com/joyent/node/issues/2002
const common = require('../common');
const net = require('net');
const seconds = 5;
let counter = 0;
const server = net.createServer(function(socket) {
socket.setTimeout((seconds / 2) * 1000, common.mustNotCall());
const interval = setInterval(function() {
counter++;
if (counter === seconds) {
clearInterval(interval);
server.close();
socket.destroy();
}
if (socket.writable) {
socket.write(`${Date.now()}\n`);
}
}, 1000);
});
server.listen(0, function() {
const s = net.connect(server.address().port);
s.pipe(process.stdout);
});

View File

@ -0,0 +1,71 @@
// 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 net = require('net');
const assert = require('assert');
let cbcount = 0;
const N = 500000;
const server = net.Server(function(socket) {
socket.on('data', function(d) {
console.error(`got ${d.length} bytes`);
});
socket.on('end', function() {
console.error('end');
socket.destroy();
server.close();
});
});
let lastCalled = -1;
function makeCallback(c) {
let called = false;
return function() {
if (called)
throw new Error(`called callback #${c} more than once`);
called = true;
if (c < lastCalled) {
throw new Error(
`callbacks out of order. last=${lastCalled} current=${c}`);
}
lastCalled = c;
cbcount++;
};
}
server.listen(0, function() {
const client = net.createConnection(server.address().port);
client.on('connect', function() {
for (let i = 0; i < N; i++) {
client.write('hello world', makeCallback(i));
}
client.end();
});
});
process.on('exit', function() {
assert.strictEqual(cbcount, N);
});

View File

@ -0,0 +1,41 @@
// 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.isPi()) {
common.skip('Too slow for Raspberry Pi devices');
}
let complete = 0;
// This will fail with:
// FATAL ERROR: JS Allocation failed - process out of memory
// if the depth counter doesn't clear the nextTickQueue properly.
(function runner() {
if (++complete < 1e8)
process.nextTick(runner);
}());
setImmediate(function() {
console.log('ok');
});

View File

@ -0,0 +1,30 @@
'use strict';
require('../common');
const assert = require('assert');
const start = process.cpuUsage();
// Run a busy-loop for specified # of milliseconds.
const RUN_FOR_MS = 500;
// Define slop factor for checking maximum expected diff values.
const SLOP_FACTOR = 2;
// Run a busy loop.
const now = Date.now();
while (Date.now() - now < RUN_FOR_MS);
// Get a diff reading from when we started.
const diff = process.cpuUsage(start);
const MICROSECONDS_PER_MILLISECOND = 1000;
// Diff usages should be >= 0, <= ~RUN_FOR_MS millis.
// Let's be generous with the slop factor, defined above, in case other things
// are happening on this CPU. The <= check may be invalid if the node process
// is making use of multiple CPUs, in which case, just remove it.
assert(diff.user >= 0);
assert(diff.user <= SLOP_FACTOR * RUN_FOR_MS * MICROSECONDS_PER_MILLISECOND);
assert(diff.system >= 0);
assert(diff.system <= SLOP_FACTOR * RUN_FOR_MS * MICROSECONDS_PER_MILLISECOND);

View File

@ -0,0 +1,41 @@
// 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 start = process.hrtime();
// process.hrtime() should return an Array
assert(Array.isArray(start));
// busy-loop for 2 seconds
const now = Date.now();
while (Date.now() - now < 2000);
// get a diff reading
const diff = process.hrtime(start);
// Should be at least 1 second, at most 2 seconds later
// (the while loop will usually exit a few nanoseconds before 2)
assert(diff[0] >= 1);
assert(diff[0] <= 2);

View File

@ -0,0 +1,112 @@
// 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';
// Uploading a big file via HTTPS causes node to drop out of the event loop.
// https://github.com/joyent/node/issues/892
// In this test we set up an HTTPS in this process and launch a subprocess
// to POST a 32mb file to us. A bug in the pause/resume functionality of the
// TLS server causes the child process to exit cleanly before having sent
// the entire buffer.
const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');
const assert = require('assert');
const spawn = require('child_process').spawn;
const https = require('https');
const fixtures = require('../common/fixtures');
const bytesExpected = 1024 * 1024 * 32;
let started = false;
const childScript = fixtures.path('GH-892-request.js');
function makeRequest() {
if (started) return;
started = true;
let stderrBuffer = '';
// Pass along --trace-deprecation/--throw-deprecation in
// process.execArgv to track down nextTick recursion errors
// more easily. Also, this is handy when using this test to
// view V8 opt/deopt behavior.
const args = process.execArgv.concat([ childScript,
server.address().port,
bytesExpected ]);
const child = spawn(process.execPath, args);
child.on('exit', function(code) {
assert.match(stderrBuffer, /DONE/);
assert.strictEqual(code, 0);
});
// The following two lines forward the stdio from the child
// to parent process for debugging.
child.stderr.pipe(process.stderr);
child.stdout.pipe(process.stdout);
// Buffer the stderr so that we can check that it got 'DONE'
child.stderr.setEncoding('ascii');
child.stderr.on('data', function(d) {
stderrBuffer += d;
});
}
const serverOptions = {
key: fixtures.readKey('agent1-key.pem'),
cert: fixtures.readKey('agent1-cert.pem'),
};
let uploadCount = 0;
const server = https.Server(serverOptions, function(req, res) {
// Close the server immediately. This test is only doing a single upload.
// We need to make sure the server isn't keeping the event loop alive
// while the upload is in progress.
server.close();
req.on('data', function(d) {
process.stderr.write('.');
uploadCount += d.length;
});
req.on('end', function() {
assert.strictEqual(uploadCount, bytesExpected);
res.writeHead(200, { 'content-type': 'text/plain' });
res.end('successful upload\n');
});
});
server.listen(0, function() {
console.log(`expecting ${bytesExpected} bytes`);
makeRequest();
});
process.on('exit', function() {
console.error(`got ${uploadCount} bytes`);
assert.strictEqual(uploadCount, bytesExpected);
});

View File

@ -0,0 +1,122 @@
// 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';
// Test that having a bunch of streams piping in parallel
// doesn't break anything.
require('../common');
const assert = require('assert');
const Stream = require('stream').Stream;
const rr = [];
const ww = [];
const cnt = 100;
const chunks = 1000;
const chunkSize = 250;
const data = Buffer.allocUnsafe(chunkSize);
let wclosed = 0;
let rclosed = 0;
function FakeStream() {
Stream.apply(this);
this.wait = false;
this.writable = true;
this.readable = true;
}
FakeStream.prototype = { __proto__: Stream.prototype };
FakeStream.prototype.write = function(chunk) {
console.error(this.ID, 'write', this.wait);
if (this.wait) {
process.nextTick(this.emit.bind(this, 'drain'));
}
this.wait = !this.wait;
return this.wait;
};
FakeStream.prototype.end = function() {
this.emit('end');
process.nextTick(this.close.bind(this));
};
// noop - closes happen automatically on end.
FakeStream.prototype.close = function() {
this.emit('close');
};
// Expect all streams to close properly.
process.on('exit', function() {
assert.strictEqual(wclosed, cnt);
assert.strictEqual(rclosed, cnt);
});
for (let i = 0; i < chunkSize; i++) {
data[i] = i;
}
for (let i = 0; i < cnt; i++) {
const r = new FakeStream();
r.on('close', function() {
console.error(this.ID, 'read close');
rclosed++;
});
rr.push(r);
const w = new FakeStream();
w.on('close', function() {
console.error(this.ID, 'write close');
wclosed++;
});
ww.push(w);
r.ID = w.ID = i;
r.pipe(w);
}
// Now start passing through data.
// Simulate a relatively fast async stream.
rr.forEach(function(r) {
let cnt = chunks;
let paused = false;
r.on('pause', function() {
paused = true;
});
r.on('resume', function() {
paused = false;
step();
});
function step() {
r.emit('data', data);
if (--cnt === 0) {
r.end();
return;
}
if (paused) return;
process.nextTick(step);
}
process.nextTick(step);
});

View File

@ -0,0 +1,29 @@
'use strict';
const common = require('../common');
// Buffer with size > INT32_MAX
common.skipIf32Bits();
const assert = require('assert');
const { StringDecoder } = require('node:string_decoder');
const kStringMaxLength = require('buffer').constants.MAX_STRING_LENGTH;
const size = 2 ** 31;
const stringTooLongError = {
message: `Cannot create a string longer than 0x${kStringMaxLength.toString(16)}` +
' characters',
code: 'ERR_STRING_TOO_LONG',
name: 'Error',
};
try {
const buf = Buffer.allocUnsafe(size);
const decoder = new StringDecoder('utf8');
assert.throws(() => decoder.write(buf), stringTooLongError);
} catch (e) {
if (e.code !== 'ERR_MEMORY_ALLOCATION_FAILED') {
throw e;
}
common.skip('insufficient space for Buffer.alloc');
}

View File

@ -0,0 +1,8 @@
// Flags: --max-old-space-size=10
'use strict';
require('../common');
const { createHistogram } = require('perf_hooks');
for (let i = 0; i < 1e4; i++) {
structuredClone(createHistogram());
}

131
test/pummel/test-timers.js Normal file
View File

@ -0,0 +1,131 @@
// 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 WINDOW = 200; // Why does this need to be so big?
{
const starttime = Date.now();
setTimeout(common.mustCall(function() {
const endtime = Date.now();
const diff = endtime - starttime;
assert.ok(diff > 0);
console.error(`diff: ${diff}`);
assert.ok(Math.abs(diff - 1000) < WINDOW);
}), 1000);
}
// This timer shouldn't execute
{
const id = setTimeout(common.mustNotCall(), 500);
clearTimeout(id);
}
{
const starttime = Date.now();
let interval_count = 0;
setInterval(common.mustCall(function() {
interval_count += 1;
const endtime = Date.now();
const diff = endtime - starttime;
assert.ok(diff > 0);
console.error(`diff: ${diff}`);
const t = interval_count * 1000;
assert.ok(Math.abs(diff - t) < WINDOW * interval_count);
assert.ok(interval_count <= 3, `interval_count: ${interval_count}`);
if (interval_count === 3)
clearInterval(this);
}, 3), 1000);
}
// Single param:
{
setTimeout(function(param) {
assert.strictEqual(param, 'test param');
}, 1000, 'test param');
}
{
let interval_count = 0;
setInterval(function(param) {
++interval_count;
assert.strictEqual(param, 'test param');
if (interval_count === 3)
clearInterval(this);
}, 1000, 'test param');
}
// Multiple param
{
setTimeout(function(param1, param2) {
assert.strictEqual(param1, 'param1');
assert.strictEqual(param2, 'param2');
}, 1000, 'param1', 'param2');
}
{
let interval_count = 0;
setInterval(function(param1, param2) {
++interval_count;
assert.strictEqual(param1, 'param1');
assert.strictEqual(param2, 'param2');
if (interval_count === 3)
clearInterval(this);
}, 1000, 'param1', 'param2');
}
// setInterval(cb, 0) should be called multiple times.
{
let count = 0;
const interval = setInterval(common.mustCall(function() {
if (++count > 10) clearInterval(interval);
}, 11), 0);
}
// We should be able to clearTimeout multiple times without breakage.
{
const t = common.mustCall(3);
setTimeout(t, 200);
setTimeout(t, 200);
const y = setTimeout(t, 200);
clearTimeout(y);
setTimeout(t, 200);
clearTimeout(y);
}

View File

@ -0,0 +1,69 @@
// 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.hasCrypto)
common.skip('missing crypto');
const assert = require('assert');
const tls = require('tls');
const fixtures = require('../common/fixtures');
const stream = require('stream');
const request = Buffer.from('ABCD'.repeat(1024 * 256 - 1)); // 1mb
const options = {
key: fixtures.readKey('agent1-key.pem'),
cert: fixtures.readKey('agent1-cert.pem'),
};
class Mediator extends stream.Writable {
constructor() {
super();
this.buf = '';
}
_write(data, enc, cb) {
this.buf += data;
setTimeout(cb, 0);
if (this.buf.length >= request.length) {
assert.strictEqual(this.buf, request.toString());
server.close();
}
}
}
const mediator = new Mediator();
const server = tls.Server(options, common.mustCall(function(socket) {
socket.pipe(mediator);
}));
server.listen(0, common.mustCall(() => {
const client1 = tls.connect({
port: server.address().port,
rejectUnauthorized: false,
}, common.mustCall(function() {
client1.end(request);
}));
}));

View File

@ -0,0 +1,86 @@
// 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';
// Server sends a large string. Client counts bytes and pauses every few
// seconds. Makes sure that pause and resume work properly.
const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');
const assert = require('assert');
const tls = require('tls');
const fixtures = require('../common/fixtures');
process.stdout.write('build body...');
const body = 'hello world\n'.repeat(1024 * 1024);
process.stdout.write('done\n');
const options = {
key: fixtures.readKey('agent2-key.pem'),
cert: fixtures.readKey('agent2-cert.pem'),
};
const server = tls.Server(options, common.mustCall(function(socket) {
socket.end(body);
}));
let recvCount = 0;
server.listen(0, function() {
const client = tls.connect({
port: server.address().port,
rejectUnauthorized: false,
});
client.on('data', function(d) {
process.stdout.write('.');
recvCount += d.length;
client.pause();
process.nextTick(function() {
client.resume();
});
});
client.on('close', function() {
console.error('close');
server.close();
clearTimeout(timeout);
});
});
function displayCounts() {
console.log(`body.length: ${body.length}`);
console.log(` recvCount: ${recvCount}`);
}
const timeout = setTimeout(displayCounts, 10 * 1000);
process.on('exit', function() {
displayCounts();
assert.strictEqual(body.length, recvCount);
});

View 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';
// Flags: --max_old_space_size=32 --expose_gc
const common = require('../common');
if (common.isASan) {
common.skip('ASan messes with memory measurements');
}
const assert = require('assert');
const vm = require('vm');
const baselineRss = process.memoryUsage.rss();
const start = Date.now();
const interval = setInterval(function() {
try {
vm.runInNewContext('throw 1;');
} catch {
// Continue regardless of error.
}
global.gc();
const rss = process.memoryUsage.rss();
assert.ok(rss < baselineRss + 32 * 1024 * 1024,
`memory usage: ${rss} baseline: ${baselineRss}`);
// Stop after 5 seconds.
if (Date.now() - start > 5 * 1000) {
clearInterval(interval);
testContextLeak();
}
}, 1);
function testContextLeak() {
// TODO: This needs a comment explaining what it's doing. Will it crash the
// test if there is a memory leak? Or what?
for (let i = 0; i < 1000; i++)
vm.createContext({});
}

View File

@ -0,0 +1,33 @@
'use strict';
require('../common');
const vm = require('vm');
// We're testing a race condition so we just have to spin this in a loop
// for a little while and see if it breaks. The condition being tested
// is an `isolate->TerminateExecution()` reaching the main JS stack from
// the timeout watchdog.
const sandbox = { timeout: 5 };
const context = vm.createContext(sandbox);
const script = new vm.Script(
'var d = Date.now() + timeout;while (d > Date.now());',
);
const immediate = setImmediate(function() {
throw new Error('Detected vm race condition!');
});
// When this condition was first discovered this test would fail in 50ms
// or so. A better, but still incorrect implementation would fail after
// 100 seconds or so. If you're messing with vm timeouts you might
// consider increasing this timeout to hammer out races.
const giveUp = Date.now() + 5000;
do {
// The loop adjusts the timeout up or down trying to hit the race
try {
script.runInContext(context, { timeout: 5 });
++sandbox.timeout;
} catch {
--sandbox.timeout;
}
} while (Date.now() < giveUp);
clearImmediate(immediate);

View 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';
require('../common');
const assert = require('assert');
const fs = require('fs');
const tmpdir = require('../common/tmpdir');
tmpdir.refresh();
const f = tmpdir.resolve('x.txt');
fs.closeSync(fs.openSync(f, 'w'));
let changes = 0;
function watchFile() {
fs.watchFile(f, (curr, prev) => {
// Make sure there is at least one watch event that shows a changed mtime.
if (curr.mtime <= prev.mtime) {
return;
}
changes++;
fs.unwatchFile(f);
watchFile();
fs.unwatchFile(f);
});
}
watchFile();
function changeFile() {
const fd = fs.openSync(f, 'w+');
fs.writeSync(fd, 'xyz\n');
fs.closeSync(fd);
}
changeFile();
const interval = setInterval(changeFile, 1000);
// Use unref() here so fs.watchFile() watcher is the only thing keeping the
// event loop open.
interval.unref();
process.on('exit', function() {
assert.ok(changes > 0);
});

View File

@ -0,0 +1,706 @@
'use strict';
const common = require('../common');
if (!common.hasCrypto) {
common.skip('missing crypto');
}
if (common.isPi()) {
common.skip('Too slow for Raspberry Pi devices');
}
const assert = require('assert');
const { subtle } = globalThis.crypto;
function getDeriveKeyInfo(name, length, hash, ...usages) {
return [{ name, length, hash }, usages];
}
const kDerivedKeyTypes = [
['AES-CBC', 128, undefined, 'encrypt', 'decrypt'],
['AES-CBC', 256, undefined, 'encrypt', 'decrypt'],
['AES-CTR', 128, undefined, 'encrypt', 'decrypt'],
['AES-CTR', 256, undefined, 'encrypt', 'decrypt'],
['AES-GCM', 128, undefined, 'encrypt', 'decrypt'],
['AES-GCM', 256, undefined, 'encrypt', 'decrypt'],
['AES-KW', 128, undefined, 'wrapKey', 'unwrapKey'],
['AES-KW', 256, undefined, 'wrapKey', 'unwrapKey'],
['HMAC', 256, 'SHA-1', 'sign', 'verify'],
['HMAC', 256, 'SHA-256', 'sign', 'verify'],
['HMAC', 256, 'SHA-384', 'sign', 'verify'],
['HMAC', 256, 'SHA-512', 'sign', 'verify'],
];
const kPasswords = {
short: '5040737377307264',
long: '55736572732073686f756c64207069636b206c6f6' +
'e6720706173737068726173657320286e6f742075' +
'73652073686f72742070617373776f7264732921',
empty: '',
};
const kSalts = {
short: '4e61436c',
long: '536f6469756d2043686c6f7269646520636f6d706f756e64',
empty: '',
};
const kDerivations = {
short: {
short: {
'SHA-384': {
'1': '80cd0f15364366a72551c37975f7b637ba89' +
'c29b4639ec720f69a70dbbed515c',
'1000': 'aaec5a976d4d35cb2024486fc9f9bb9aa' +
'3eae7cef2bce62664b5b3751cf50ff1',
'100000': '6f5ea3c6c6f5e4833467b47c3a671e6' +
'5714e87071bd1e36d716f846b5cd28980',
},
'SHA-512': {
'1': '69f4d5cef5c7d8ba938e880388c8f63b6b2' +
'448b2626d1343fc5cb68bbd7f27b2',
'1000': '865c5945e11f5bf3ddf002e7cb1748f6' +
'224d2671e806dad4aaf090a04367da29',
'100000': '483ba7f2e2fe382cf61d20b29812e2' +
'd49610a60041ae40ecf9fc7ef138e93876',
},
'SHA-1': {
'1': '4624dbd21373ee5659c125b184eedaa26a3' +
'3b77ca11314b9f0c9dae1e44e9b04',
'1000': '5388ea5e62e1b557981abe5ce4132127' +
'58aa6a9d2c5bf08c019d459dba666b90',
'100000': 'f58f435fbc5c05865c914fd972108a' +
'09457d5f9a48f14e75e4cc02d98983038a',
},
'SHA-256': {
'1': 'c6bc55a404adcea36a1ab56798085e0aaf6' +
'97f6bb2c16a5072f838f17dfe6cb6',
'1000': '4e6ca57957439be3a75370424225e221' +
'1d55f05af00561df3f3efee9116bc34c',
'100000': 'ab25796598e74b29c324f5ba4d90ea' +
'7dc89fc6891041b4d56c94156505f722c0',
},
},
long: {
'SHA-384': {
'1': '6807346cc53eded1cb964a72628589a6bd4' +
'8355990bfdfe7465109710207059d',
'1000': 'a310ef3c6b3a95e6d8ca6644e3dcfd88' +
'222a59fe8e00c52d6a12631d82c1d24b',
'100000': '2c8c6674c879cf1850bc9b7fbdcc6e' +
'a7abb0a1522196a866875305dea57486f3',
},
'SHA-512': {
'1': '5777027aff4051fb9b43c1f1ef0463bd677' +
'51175d428a13da3da845a591332cd',
'1000': '9c17fe96895eadbfd1cc095fc1bb834f' +
'28e5ccc9ec96ca814cff941a4bf40727',
'100000': 'b479c9715c421638dce0a705fc0b7b' +
'a7d56fa3063188063580e070dff1db497c',
},
'SHA-1': {
'1': '576f7c165825bef9ef14b4bc2c82469d1e4' +
'08ff8e7ba306694797f9e45b766ed',
'1000': '89d3b27b5f6e8af015f2f87cf368a143' +
'8a206c4ecf5fe681fc3bf94c56213ef6',
'100000': '1e39e8bf6676fcd3156655457afa14' +
'bee771dbcbfcd07241c7cee209a7cb1fe9',
},
'SHA-256': {
'1': '12b90f594f0908cf912d655c948f9c2a1ea' +
'b855765bc12785ef18aa02b8e7edc',
'1000': 'b1a7b7dc20df174a4a0e410dbfaf03b4' +
'c375c450a89d7a9ed349b4e52e64dfd8',
'100000': 'd4594d8a1b59520a48878922a65d66' +
'3d28f6a5fa49e931d300d8f9baf93d0aeb',
},
},
empty: {
'SHA-384': {
'1': '4f1089c01e438bde649a379fa418fbc3b85' +
'6258772dfe911806f9bd0809fbc7e',
'1000': 'aeb5f97d6627eebcde6b139a00895500' +
'30f7401c67e01c057a3338175e3f3a17',
'100000': 'd7687df6c781dc88d64ef9cbaf95d3' +
'd5d1155f66b230239e6e81c1550c8840cf',
},
'SHA-512': {
'1': '8f7b7d459c752f64bf12be625b65d496ac2' +
'4ea36516b168e16fb026845b4e82e',
'1000': 'b5ac720b7abe0832fc51a31b1ec5673b' +
'eb1e41840adfd3d606e8638f4006eb48',
'100000': 'ba1a0f36bad771526564051eb9ca20' +
'7da19b62e53762349976a9a3d1b0ef7e20',
},
'SHA-1': {
'1': 'c0cffb0ce5db351faa24dad5902583cfc30' +
'a9f54d9aa6991fe821d03122127e9',
'1000': '736f3c3d6ebcc2a7b970403e2696c0eb' +
'4cd1770f55f196fc7089e666c11f77da',
'100000': '1c5095ac9a7bd410ef0f72c993eca9' +
'1bb0e571e9b2fbab704f8c131191fad16c',
},
'SHA-256': {
'1': '019e54ab42f00485d3aa1b26fcde21ae5f5' +
'2cb0f0960ffc9767f25c65e2db2f9',
'1000': 'b9d2f2217b4ee5a8bf0345f36b2c9887' +
'33f503a975dfeac7b7135f54a5f29971',
'100000': 'a7a2869829797807b3e576c17878b4' +
'66449e89e60447d541775a96eb7c1a5ded',
},
},
},
long: {
short: {
'SHA-384': {
'1': '5ede8836fdabeec5d3733b434abac443d41' +
'5193b599e0926193b000f406a5a7d',
'1000': 'faa442fbabf4058cc65368b53d7ec511' +
'3c09ea7e5e3743312f4bebedd980ba37',
'100000': 'f62ae6c7871b181aa71232f5eb8837' +
'2498ef32ac0a7d715119e8f052eb102d29',
},
'SHA-512': {
'1': '3e9c12b3f6dfb6441594ec7063fca962ffd' +
'a10b6cf30b898a31ef9f1306b1119',
'1000': 'f0928f50a155f26a8c9c1bc7f3b5cb53' +
'1c53a8f51040c9ce5fc79d430ff0c0f4',
'100000': '974acfbb0f0f20c81ec92829f38c3d' +
'af086a7df58b912b856d1f5ecc9355ef1b',
},
'SHA-1': {
'1': '8ae72f94e6fcd54fcbfca66200a211a51b2' +
'f846787d20b6808bedf156ce46ca0',
'1000': '53b42161134e15c871abd71aba1390d0' +
'1f4c6a940caaf5c179258d8f1b1d680b',
'100000': 'a7fda4c79dd3ba1a875f65e9248b21' +
'0899ca0814ae38995d8ce5a53560cbac31',
},
'SHA-256': {
'1': 'ffa1e9a727a92c27ae6f74b1c7978f9e1af' +
'860e106376340ac43d969d136405b',
'1000': 'eeeb7714420a00b18acec2b5979d1da6' +
'1373202b7f8ba71b086293aab859e0a0',
'100000': 'deac70cbe3f1720e353b4e8016ddb5' +
'9475efb70b6a2385e735d2d6ea6d624a4d',
},
},
long: {
'SHA-384': {
'1': 'cf55422cef6e1bc49e6d082b2273d480e8f' +
'2e8822dadd1469c2a32d9657d12f1',
'1000': '35658551f0ec13398a7b45e0261cfd65' +
'4c1e52411e6e457dee68f4aeabe925a7',
'100000': '1abab5f1e461df378b88c0a22be76e' +
'f2f1627df74ac7cbfb84bdccb354bc8889',
},
'SHA-512': {
'1': 'de4afbc0add3e4d32f4bc6e122a88ae44a2' +
'b3ccf0148e7762bac05c43e94ef7f',
'1000': '43e12024c4d354727f7e58842ccb6033' +
'a161d60dc5ae516f076e4a58a1880d38',
'100000': 'f9a92384a4eadfc3560649b37fb676' +
'e83c453cbbd99f80bba6f0a10ebd150b52',
},
'SHA-1': {
'1': '1d104ea5d235006a12a80f71b80ee528048' +
'b64cc1a7a0f30f7df4ba26b8320c7',
'1000': '6e90c86ee07b873e965071025673ff05' +
'429f678c30f91b37e1e2da512036d320',
'100000': '141030763bf983c8564d5d4c935fe3' +
'ca3549608159ac1934c1599040668c2363',
},
'SHA-256': {
'1': 'fd5caeb8b3abe589bc159c4e51f800570e7' +
'4f64397a6c5ee131dfed93f0511aa',
'1000': '3fd587c94ba946b8b9dccddd2a5b74f6' +
'778d4f61e691f83ac47a2fa9580bfdf8',
'100000': '11992d8b813311244c544b62292945' +
'e208d403cebd6b9552a1a562065d9958ea',
},
},
empty: {
'SHA-384': {
'1': '49ab3f9f882fdb9e528b4d9f1b3e8c71d26' +
'39abf1701d56eb99bd51201e420ff',
'1000': 'f9ca148b0c041890bff8831db6174719' +
'7e94ce68f190edf269694b4d644861ca',
'100000': '1749dfcd77e5258519ea2231ba2cd6' +
'543b073339ac9b1545bb643153faf6d17b',
},
'SHA-512': {
'1': 'd1bfa1a6b8a977839f8c3f9d52dd02104e2' +
'029c0eb2a6208cc408816e7768a8c',
'1000': '457a7955ebecec71a51efb6237e5b1d6' +
'2f4deab5c93d7b3d11d1e70faffa417e',
'100000': 'e805ac9cc1d8412c42446d237d1b50' +
'4f9540b362bd1b75e451531e853e24753d',
},
'SHA-1': {
'1': 'a46a62986d9c3909f41014dd72cfe34a261' +
'247854d7312cf4fbead60b9b69edd',
'1000': 'e7375de5036766c40cb85f43b53fce4f' +
'fa402ab6be3571007ef5d55453fd7f0a',
'100000': '7a403d9a13aed8164e9c072c545462' +
'251fd942f1736a6bf03ce1c88330048e04',
},
'SHA-256': {
'1': '4f510c5181ac5c2c5fd4bd141f9712495be' +
'ca279624742b4d6d30d08b96c0a69',
'1000': '7e66c84bea888f92c348d9145585186c' +
'ae472b12fba7f0ad28179575c1aa815a',
'100000': '5f1a6ac4a56d9796a7309a78daaaf9' +
'18badaf5ed1eecc3f0b8a3a44c3d38d654',
},
},
},
empty: {
short: {
'SHA-384': {
'1': 'e9f0da1e97dfa455f858ce6b9af1ecc0299' +
'f125ff1a847eb5d4955866f43e604',
'1000': '7ff7954aeddf41795fc8300666786d49' +
'74269aa91cc7e93811c953331d56d609',
'100000': '1c73132b6a55e9d9de2cdbfe1f55bf' +
'0ab59fd91f78f109c50096038b8557b147',
},
'SHA-512': {
'1': 'e7e2b41f4887421bcb764eb4a56f63d2502' +
'e33c764fbdf60626ad42ed9672342',
'1000': 'd561c4c84e9c60ba4752a2d383bf55ef' +
'f643fc9e452252d6821e39449350cf72',
'100000': 'efd00752bc9ffafb5a399dd1d5834e' +
'8d2c2b676ecd4b2063fb1fe581d0f1380b',
},
'SHA-1': {
'1': 'a667da47b8f857b7c65f70a6c8e7a06ce0d' +
'25211a2b6ebaf58dcaaf268b46b1d',
'1000': '72c92bbd3ddab4789e88e42ad1cda83c' +
'c0729e6cb5106a577e50d5cf61782481',
'100000': '06e19e1b83e6480b1554df2b31a2c9' +
'2d1bfcf9bc1bdbc8751ff8685bdeef7dc9',
},
'SHA-256': {
'1': '2ddb49243eb3b5912cb260cdd87fb04ef0d' +
'111bfa44d40a45e02a8a5c3c1518d',
'1000': '2835f3ed53565420c90951509b0c1173' +
'b645174f1546ab3ac3e6c85cb471b53b',
'100000': '80aed905ca32ae0bb2a9d8f532f048' +
'a0e672463eef9f83dfa7d88bca726553ea',
},
},
long: {
'SHA-384': {
'1': '7b0bcca81dd637a3b3398666619716c5f2b1' +
'f4a5c24e85c18a9955559e4d7692',
'1000': '8bb89cf71972fe5acc16fdc5f8cffd2c2' +
'e7178c086b3bbe61cc1314619135958',
'100000': '26c6a8ae4bd1fbe715ae478efff3eca' +
'e83afa617ed35bd4a3f63c3da76a42d22',
},
'SHA-512': {
'1': 'bb73f8168a8f391d3d54ca892fb72b8e603' +
'5e37f891e5a70491b94dc05510bc4',
'1000': '5cacc16cdfbe052cfd73a9891b8c0e78' +
'b19b2e07eae2423d48fed5e08aa8494b',
'100000': '87fdfc293392cbf33ecc9b5141a2fe' +
'fa74d150499756863c484c0a78b6274d7f',
},
'SHA-1': {
'1': '1f46b40cf2fb3dc41a3d9ced8897b861050' +
'36810e2bfac7040814bd65d428d67',
'1000': 'cc5748ecc41288a0e13368543aaa2ef6' +
'2c97ba7518fa88f6e11c35763fc930b4',
'100000': '33e2993bf4729dc993fff66e69cc55' +
'777135ebfabce533575bce4a96645a742c',
},
'SHA-256': {
'1': '61c935c462c3321c89663545d13a4f6b52b' +
'5191cfb7479e58dcfe6444d43106c',
'1000': '1353f7458237ab332ee052e29f829a2a' +
'b90e72630ea10493b4eecffb9ff89e1d',
'100000': '79baf80ec582920538801e9d929ce0' +
'7084277987488d733a026852c452f06fb4',
},
},
empty: {
'SHA-384': {
'1': '4bb042a5c28cee6f66f991c717fd7702677' +
'87e2bb3031eae270d87d63ad99534',
'1000': '9cbfe72d194da34e17c821dd1569ef50' +
'a86eb4d893591776adc6a5c21e0031cf',
'100000': 'ed6bd7282567abe48d542d067d09f4' +
'04bd044ae2cefe11dacc531c4764cd35cd',
},
'SHA-512': {
'1': '6d2ecbbbfb2e6dcd7056faf9af6aa06eae5' +
'94391db983279a6bf27e0eb228614',
'1000': 'cb93096c3a02beeb1c5fac36765c9011' +
'fe99f8d8ea62366048fc98cb98dfea8f',
'100000': '89e16254ebad5cba72e0aebe1614c7' +
'f9b795a7505f2637206ce10a3449a2b8bb',
},
'SHA-1': {
'1': '1e437a1c79d75be61e91141dae20affc489' +
'2cc99abcc3fe753887bccc8920176',
'1000': '6e40910ac02ec89cebb9d898b13a09d1' +
'cd7adf6f8cc08cc473302c8973aa2e19',
'100000': 'a9e1bebb36bc26d7c997d5483cbc8d' +
'e4a419d1e706571342632586ec330a7290',
},
'SHA-256': {
'1': 'f7ce0b653d2d72a4108cf5abe912ffdd777' +
'616dbbb27a70e8204f3ae2d0f6fad',
'1000': '4fc58a21c100ce1835b8f9991d738b56' +
'965d14b24e1761fbdffc69ac5e0b667a',
'100000': '64a868d4b23af696d3734d0b814d04' +
'cdd1ac280128e97653a05f32b49c13a29a',
},
},
},
};
async function setupBaseKeys() {
const promises = [];
const baseKeys = {};
const noBits = {};
const noKey = {};
let wrongKey = null;
Object.keys(kPasswords).forEach((size) => {
promises.push(
subtle.importKey(
'raw',
Buffer.from(kPasswords[size], 'hex'),
{ name: 'PBKDF2' },
false,
['deriveKey', 'deriveBits'])
.then((key) => baseKeys[size] = key));
promises.push(
subtle.importKey(
'raw',
Buffer.from(kPasswords[size], 'hex'),
{ name: 'PBKDF2' },
false,
['deriveBits'])
.then((key) => noKey[size] = key));
promises.push(
subtle.importKey(
'raw',
Buffer.from(kPasswords[size], 'hex'),
{ name: 'PBKDF2' },
false,
['deriveKey'])
.then((key) => noBits[size] = key));
});
promises.push(
subtle.generateKey(
{ name: 'ECDH', namedCurve: 'P-521' },
false,
['deriveKey', 'deriveBits'])
.then((key) => wrongKey = key.privateKey));
await Promise.all(promises);
return { baseKeys, noBits, noKey, wrongKey };
}
async function testDeriveBits(
baseKeys,
size,
saltSize,
hash,
iterations) {
const algorithm = {
name: 'PBKDF2',
salt: Buffer.from(kSalts[saltSize], 'hex'),
hash,
iterations,
};
const bits = await subtle.deriveBits(algorithm, baseKeys[size], 256);
assert(bits instanceof ArrayBuffer);
assert.strictEqual(
Buffer.from(bits).toString('hex'),
kDerivations[size][saltSize][hash][iterations]);
}
async function testDeriveBitsBadLengths(
baseKeys,
size,
saltSize,
hash,
iterations) {
const algorithm = {
name: 'PBKDF2',
salt: Buffer.from(kSalts[saltSize], 'hex'),
iterations,
hash,
};
return Promise.all([
assert.rejects(
subtle.deriveBits(algorithm, baseKeys[size], undefined), {
name: 'OperationError',
}),
assert.rejects(
subtle.deriveBits(algorithm, baseKeys[size], null), {
message: 'length cannot be null',
name: 'OperationError',
}),
assert.rejects(
subtle.deriveBits(algorithm, baseKeys[size]), {
message: 'length cannot be null',
name: 'OperationError',
}),
assert.rejects(
subtle.deriveBits(algorithm, baseKeys[size], 15), {
message: /length must be a multiple of 8/,
name: 'OperationError',
}),
]);
}
async function testDeriveBitsBadHash(
baseKeys,
size,
saltSize,
hash,
iterations) {
const salt = Buffer.from(kSalts[saltSize], 'hex');
const algorithm = { name: 'PBKDF2', salt, iterations };
return Promise.all([
assert.rejects(
subtle.deriveBits(
{
...algorithm,
hash: hash.substring(0, 3) + hash.substring(4),
}, baseKeys[size], 256), {
message: /Unrecognized algorithm name/,
name: 'NotSupportedError',
}),
assert.rejects(
subtle.deriveBits(
{
...algorithm,
hash: 'HKDF',
},
baseKeys[size], 256), {
message: /Unrecognized algorithm name/,
name: 'NotSupportedError',
}),
]);
}
async function testDeriveBitsBadUsage(
noBits,
size,
saltSize,
hash,
iterations) {
const algorithm = {
name: 'PBKDF2',
salt: Buffer.from(kSalts[saltSize], 'hex'),
iterations,
hash,
};
return assert.rejects(
subtle.deriveBits(algorithm, noBits[size], 256), {
message: /baseKey does not have deriveBits usage/,
});
}
async function testDeriveKey(
baseKeys,
size,
saltSize,
hash,
iterations,
keyType,
usages) {
const algorithm = {
name: 'PBKDF2',
salt: Buffer.from(kSalts[saltSize], 'hex'),
hash,
iterations,
};
const key = await subtle.deriveKey(
algorithm,
baseKeys[size],
keyType,
true,
usages);
const bits = await subtle.exportKey('raw', key);
assert.strictEqual(
Buffer.from(bits).toString('hex'),
kDerivations[size][saltSize][hash][iterations]
.slice(0, keyType.length / 4));
}
async function testDeriveKeyBadHash(
baseKeys,
size,
saltSize,
hash,
iterations,
keyType,
usages) {
const salt = Buffer.from(kSalts[saltSize], 'hex');
const algorithm = { name: 'PBKDF2', salt, iterations };
return Promise.all([
assert.rejects(
subtle.deriveKey(
{
...algorithm,
hash: hash.substring(0, 3) + hash.substring(4),
},
baseKeys[size],
keyType,
true,
usages),
{
message: /Unrecognized algorithm name/,
name: 'NotSupportedError',
}),
assert.rejects(
subtle.deriveKey(
{
...algorithm,
hash: 'HKDF',
},
baseKeys[size],
keyType,
true,
usages),
{
message: /Unrecognized algorithm name/,
name: 'NotSupportedError',
}),
]);
}
async function testDeriveKeyBadUsage(
noKey,
size,
saltSize,
hash,
iterations,
keyType,
usages) {
const algorithm = {
name: 'PBKDF2',
salt: Buffer.from(kSalts[saltSize], 'hex'),
iterations,
hash,
};
return assert.rejects(
subtle.deriveKey(algorithm, noKey[size], keyType, true, usages), {
message: /baseKey does not have deriveKey usage/,
});
}
async function testWrongKeyType(
wrongKey,
saltSize,
hash,
iterations,
keyType,
usages,
) {
const algorithm = {
name: 'PBKDF2',
salt: Buffer.from(kSalts[saltSize], 'hex'),
iterations,
hash,
};
return assert.rejects(
subtle.deriveKey(algorithm, wrongKey, keyType, true, usages), {
message: /Key algorithm mismatch/,
});
}
(async function() {
const {
baseKeys,
noBits,
noKey,
wrongKey,
} = await setupBaseKeys();
const variations = [];
Object.keys(kDerivations).forEach((size) => {
Object.keys(kDerivations[size]).forEach((saltSize) => {
Object.keys(kDerivations[size][saltSize]).forEach((hash) => {
Object.keys(kDerivations[size][saltSize][hash])
.forEach((iterations) => {
const args = [baseKeys, size, saltSize, hash, iterations | 0];
variations.push(testDeriveBits(...args));
variations.push(testDeriveBitsBadLengths(...args));
variations.push(testDeriveBitsBadHash(...args));
variations.push(
testDeriveBitsBadUsage(
noBits,
size,
saltSize,
hash,
iterations | 0));
kDerivedKeyTypes.forEach((keyType) => {
const keyArgs = getDeriveKeyInfo(...keyType);
variations.push(testDeriveKey(...args, ...keyArgs));
variations.push(testDeriveKeyBadHash(...args, ...keyArgs));
variations.push(
testDeriveKeyBadUsage(
noKey,
size,
saltSize,
hash,
iterations | 0,
...keyArgs));
variations.push(
testWrongKeyType(
wrongKey,
saltSize,
hash,
iterations,
...keyArgs));
});
});
});
});
});
await Promise.all(variations);
})().then(common.mustCall());
// https://github.com/w3c/webcrypto/pull/380
{
crypto.subtle.importKey('raw', new Uint8Array(0), 'PBKDF2', false, ['deriveBits']).then((key) => {
return crypto.subtle.deriveBits({
name: 'PBKDF2',
hash: { name: 'SHA-256' },
iterations: 10,
salt: new Uint8Array(0),
}, key, 0);
}).then((bits) => {
assert.deepStrictEqual(bits, new ArrayBuffer(0));
})
.then(common.mustCall());
}

View File

@ -0,0 +1,22 @@
// Flags: --expose-internals
'use strict';
const common = require('../common');
const { recordState } = require('../common/heap');
const { Worker } = require('worker_threads');
const { once } = require('events');
(async function() {
const w = new Worker('setInterval(() => {}, 100)', { eval: true });
await once(w, 'online');
const stream = await w.getHeapSnapshot();
const snapshot = recordState(stream);
snapshot.validateSnapshot('Node / MessagePort', [
{
children: [
{ node_name: 'Node / MessagePortData', edge_name: 'data' },
],
},
], { loose: true });
await w.terminate();
})().then(common.mustCall());

6
test/pummel/testcfg.py Normal file
View File

@ -0,0 +1,6 @@
import sys, os
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
import testpy
def GetConfiguration(context, root):
return testpy.SimpleTestConfiguration(context, root, 'pummel')