mirror of
https://github.com/nodejs/node.git
synced 2025-04-28 13:40:37 +00:00
test: use validateByRetainingPath in heapdump tests
This makes sure that the tests are run on actual heap snapshots and prints out missing paths when it cannot be found, which makes failures easier to debug, and removes the unnecessary requirement for BaseObjects to be root - which would make the heap snapshot containment view rather noisy and is not conceptually correct, since they are actually held by the BaseObjectList held by the realms. PR-URL: https://github.com/nodejs/node/pull/57417 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
This commit is contained in:
parent
c1b15a49be
commit
e86adad759
@ -221,6 +221,7 @@ function validateSnapshotNodes(...args) {
|
|||||||
* A alternative heap snapshot validator that can be used to verify cppgc-managed nodes.
|
* A alternative heap snapshot validator that can be used to verify cppgc-managed nodes.
|
||||||
* Modified from
|
* Modified from
|
||||||
* https://chromium.googlesource.com/v8/v8/+/b00e995fb212737802810384ba2b868d0d92f7e5/test/unittests/heap/cppgc-js/unified-heap-snapshot-unittest.cc#134
|
* https://chromium.googlesource.com/v8/v8/+/b00e995fb212737802810384ba2b868d0d92f7e5/test/unittests/heap/cppgc-js/unified-heap-snapshot-unittest.cc#134
|
||||||
|
* @param {object[]} nodes Snapshot nodes returned by createJSHeapSnapshot() or a subset filtered from it.
|
||||||
* @param {string} rootName Name of the root node. Typically a class name used to filter all native nodes with
|
* @param {string} rootName Name of the root node. Typically a class name used to filter all native nodes with
|
||||||
* this name. For cppgc-managed objects, this is typically the name configured by
|
* this name. For cppgc-managed objects, this is typically the name configured by
|
||||||
* SET_CPPGC_NAME() prefixed with an additional "Node /" prefix e.g.
|
* SET_CPPGC_NAME() prefixed with an additional "Node /" prefix e.g.
|
||||||
@ -231,12 +232,12 @@ function validateSnapshotNodes(...args) {
|
|||||||
* node_type?: string,
|
* node_type?: string,
|
||||||
* edge_type?: string,
|
* edge_type?: string,
|
||||||
* }]} retainingPath The retaining path specification to search from the root nodes.
|
* }]} retainingPath The retaining path specification to search from the root nodes.
|
||||||
|
* @param {boolean} allowEmpty Whether the function should fail if no matching nodes can be found.
|
||||||
* @returns {[object]} All the leaf nodes matching the retaining path specification. If none can be found,
|
* @returns {[object]} All the leaf nodes matching the retaining path specification. If none can be found,
|
||||||
* logs the nodes found in the last matching step of the path (if any), and throws an
|
* logs the nodes found in the last matching step of the path (if any), and throws an
|
||||||
* assertion error.
|
* assertion error.
|
||||||
*/
|
*/
|
||||||
function findByRetainingPath(rootName, retainingPath) {
|
function validateByRetainingPathFromNodes(nodes, rootName, retainingPath, allowEmpty = false) {
|
||||||
const nodes = createJSHeapSnapshot();
|
|
||||||
let haystack = nodes.filter((n) => n.name === rootName && n.type !== 'string');
|
let haystack = nodes.filter((n) => n.name === rootName && n.type !== 'string');
|
||||||
|
|
||||||
for (let i = 0; i < retainingPath.length; ++i) {
|
for (let i = 0; i < retainingPath.length; ++i) {
|
||||||
@ -269,6 +270,9 @@ function findByRetainingPath(rootName, retainingPath) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (newHaystack.length === 0) {
|
if (newHaystack.length === 0) {
|
||||||
|
if (allowEmpty) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
const format = (val) => util.inspect(val, { breakLength: 128, depth: 3 });
|
const format = (val) => util.inspect(val, { breakLength: 128, depth: 3 });
|
||||||
console.error('#');
|
console.error('#');
|
||||||
console.error('# Retaining path to search for:');
|
console.error('# Retaining path to search for:');
|
||||||
@ -282,6 +286,7 @@ function findByRetainingPath(rootName, retainingPath) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
assert.fail(`Could not find target edge ${format(expected)} in the heap snapshot.`);
|
assert.fail(`Could not find target edge ${format(expected)} in the heap snapshot.`);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
haystack = newHaystack;
|
haystack = newHaystack;
|
||||||
@ -321,9 +326,19 @@ function getHeapSnapshotOptionTests() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Similar to @see {validateByRetainingPathFromNodes} but creates the snapshot from scratch.
|
||||||
|
*/
|
||||||
|
function validateByRetainingPath(...args) {
|
||||||
|
const nodes = createJSHeapSnapshot();
|
||||||
|
return validateByRetainingPathFromNodes(nodes, ...args);
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
recordState,
|
recordState,
|
||||||
validateSnapshotNodes,
|
validateSnapshotNodes,
|
||||||
findByRetainingPath,
|
validateByRetainingPath,
|
||||||
|
validateByRetainingPathFromNodes,
|
||||||
getHeapSnapshotOptionTests,
|
getHeapSnapshotOptionTests,
|
||||||
|
createJSHeapSnapshot,
|
||||||
};
|
};
|
||||||
|
@ -1,19 +1,31 @@
|
|||||||
// Flags: --expose-internals
|
|
||||||
'use strict';
|
'use strict';
|
||||||
require('../common');
|
// This tests heap snapshot integration of dns ChannelWrap.
|
||||||
const { validateSnapshotNodes } = require('../common/heap');
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
validateSnapshotNodes('Node / ChannelWrap', []);
|
|
||||||
const dns = require('dns');
|
const dns = require('dns');
|
||||||
validateSnapshotNodes('Node / ChannelWrap', [{}]);
|
|
||||||
|
// 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', () => {});
|
dns.resolve('localhost', () => {});
|
||||||
validateSnapshotNodes('Node / ChannelWrap', [
|
|
||||||
{
|
// After dns resolution, the ChannelWrap of the default resolver has the task list.
|
||||||
children: [
|
{
|
||||||
{ node_name: 'Node / NodeAresTask::List', edge_name: 'task_list' },
|
validateByRetainingPath('Node / ChannelWrap', [
|
||||||
// `Node / ChannelWrap` (C++) -> `ChannelWrap` (JS)
|
{ node_name: 'Node / NodeAresTask::List', edge_name: 'task_list' },
|
||||||
{ node_name: 'ChannelWrap', edge_name: 'native_to_javascript' },
|
]);
|
||||||
],
|
}
|
||||||
detachedness: 2,
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
// Flags: --expose-internals
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
// This tests that Environment is tracked in heap snapshots.
|
// This tests that Environment is tracked in heap snapshots.
|
||||||
@ -6,19 +5,24 @@
|
|||||||
// test-heapdump-*.js files.
|
// test-heapdump-*.js files.
|
||||||
|
|
||||||
require('../common');
|
require('../common');
|
||||||
const { validateSnapshotNodes } = require('../common/heap');
|
const { createJSHeapSnapshot, validateByRetainingPathFromNodes } = require('../common/heap');
|
||||||
|
|
||||||
validateSnapshotNodes('Node / Environment', [{
|
const nodes = createJSHeapSnapshot();
|
||||||
children: [
|
|
||||||
{ node_name: 'Node / CleanupQueue', edge_name: 'cleanup_queue' },
|
|
||||||
{ node_name: 'Node / IsolateData', edge_name: 'isolate_data' },
|
|
||||||
{ node_name: 'Node / PrincipalRealm', edge_name: 'principal_realm' },
|
|
||||||
],
|
|
||||||
}]);
|
|
||||||
|
|
||||||
validateSnapshotNodes('Node / PrincipalRealm', [{
|
const envs = validateByRetainingPathFromNodes(nodes, 'Node / Environment', []);
|
||||||
children: [
|
validateByRetainingPathFromNodes(envs, 'Node / Environment', [
|
||||||
{ node_name: 'process', edge_name: 'process_object' },
|
{ node_name: 'Node / CleanupQueue', edge_name: 'cleanup_queue' },
|
||||||
{ node_name: 'Node / BaseObjectList', edge_name: 'base_object_list' },
|
]);
|
||||||
],
|
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' },
|
||||||
|
]);
|
||||||
|
@ -1,16 +1,26 @@
|
|||||||
// Flags: --expose-internals
|
|
||||||
'use strict';
|
'use strict';
|
||||||
require('../common');
|
|
||||||
const { validateSnapshotNodes } = require('../common/heap');
|
|
||||||
const fs = require('fs').promises;
|
|
||||||
|
|
||||||
validateSnapshotNodes('Node / FSReqPromise', []);
|
// 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);
|
fs.stat(__filename);
|
||||||
validateSnapshotNodes('Node / FSReqPromise', [
|
|
||||||
{
|
{
|
||||||
children: [
|
const nodes = validateByRetainingPath('Node / FSReqPromise', []);
|
||||||
{ node_name: 'FSReqPromise', edge_name: 'native_to_javascript' },
|
validateByRetainingPathFromNodes(nodes, 'Node / FSReqPromise', [
|
||||||
{ node_name: 'Node / AliasedFloat64Array', edge_name: 'stats_field_array' },
|
{ node_name: 'FSReqPromise', edge_name: 'native_to_javascript' },
|
||||||
],
|
]);
|
||||||
},
|
validateByRetainingPathFromNodes(nodes, 'Node / FSReqPromise', [
|
||||||
]);
|
{ node_name: 'Node / AliasedFloat64Array', edge_name: 'stats_field_array' },
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
@ -1,15 +1,21 @@
|
|||||||
// Flags: --expose-internals
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
// This tests heap snapshot integration of http2.
|
||||||
|
|
||||||
const common = require('../common');
|
const common = require('../common');
|
||||||
const { recordState } = require('../common/heap');
|
const { createJSHeapSnapshot, validateByRetainingPath, validateByRetainingPathFromNodes } = require('../common/heap');
|
||||||
|
const assert = require('assert');
|
||||||
|
|
||||||
if (!common.hasCrypto)
|
if (!common.hasCrypto)
|
||||||
common.skip('missing crypto');
|
common.skip('missing crypto');
|
||||||
const http2 = require('http2');
|
const http2 = require('http2');
|
||||||
|
|
||||||
|
// Before http2 is used, no Http2Session or Http2Streamshould be created.
|
||||||
{
|
{
|
||||||
const state = recordState();
|
const sessions = validateByRetainingPath('Node / Http2Session', []);
|
||||||
state.validateSnapshotNodes('Node / Http2Session', []);
|
assert.strictEqual(sessions.length, 0);
|
||||||
state.validateSnapshotNodes('Node / Http2Stream', []);
|
const streams = validateByRetainingPath('Node / Http2Stream', []);
|
||||||
|
assert.strictEqual(streams.length, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
const server = http2.createServer();
|
const server = http2.createServer();
|
||||||
@ -21,63 +27,45 @@ server.listen(0, () => {
|
|||||||
const req = client.request();
|
const req = client.request();
|
||||||
|
|
||||||
req.on('response', common.mustCall(() => {
|
req.on('response', common.mustCall(() => {
|
||||||
const state = recordState();
|
const nodes = createJSHeapSnapshot();
|
||||||
|
|
||||||
// `Node / Http2Stream` (C++) -> Http2Stream (JS)
|
// `Node / Http2Stream` (C++) -> Http2Stream (JS)
|
||||||
state.validateSnapshotNodes('Node / Http2Stream', [
|
validateByRetainingPathFromNodes(nodes, 'Node / Http2Stream', [
|
||||||
{
|
// current_headers and/or queue could be empty
|
||||||
children: [
|
{ node_name: 'Http2Stream', edge_name: 'native_to_javascript' },
|
||||||
// current_headers and/or queue could be empty
|
]);
|
||||||
{ node_name: 'Http2Stream', edge_name: 'native_to_javascript' },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
], { loose: true });
|
|
||||||
|
|
||||||
// `Node / FileHandle` (C++) -> FileHandle (JS)
|
// `Node / FileHandle` (C++) -> FileHandle (JS)
|
||||||
state.validateSnapshotNodes('Node / FileHandle', [
|
validateByRetainingPathFromNodes(nodes, 'Node / FileHandle', [
|
||||||
{
|
{ node_name: 'FileHandle', edge_name: 'native_to_javascript' },
|
||||||
children: [
|
// current_headers could be empty
|
||||||
{ node_name: 'FileHandle', edge_name: 'native_to_javascript' },
|
|
||||||
// current_headers could be empty
|
|
||||||
],
|
|
||||||
},
|
|
||||||
], { loose: true });
|
|
||||||
state.validateSnapshotNodes('Node / TCPSocketWrap', [
|
|
||||||
{
|
|
||||||
children: [
|
|
||||||
{ node_name: 'TCP', edge_name: 'native_to_javascript' },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
], { loose: true });
|
|
||||||
state.validateSnapshotNodes('Node / TCPServerWrap', [
|
|
||||||
{
|
|
||||||
children: [
|
|
||||||
{ node_name: 'TCP', edge_name: 'native_to_javascript' },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
], { loose: true });
|
|
||||||
// `Node / StreamPipe` (C++) -> StreamPipe (JS)
|
|
||||||
state.validateSnapshotNodes('Node / StreamPipe', [
|
|
||||||
{
|
|
||||||
children: [
|
|
||||||
{ node_name: 'StreamPipe', edge_name: 'native_to_javascript' },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
]);
|
]);
|
||||||
|
validateByRetainingPathFromNodes(nodes, 'Node / TCPSocketWrap', [
|
||||||
|
{ node_name: 'TCP', edge_name: 'native_to_javascript' },
|
||||||
|
]);
|
||||||
|
|
||||||
|
validateByRetainingPathFromNodes(nodes, 'Node / TCPServerWrap', [
|
||||||
|
{ node_name: 'TCP', edge_name: 'native_to_javascript' },
|
||||||
|
]);
|
||||||
|
|
||||||
|
// `Node / StreamPipe` (C++) -> StreamPipe (JS)
|
||||||
|
validateByRetainingPathFromNodes(nodes, 'Node / StreamPipe', [
|
||||||
|
{ node_name: 'StreamPipe', edge_name: 'native_to_javascript' },
|
||||||
|
]);
|
||||||
|
|
||||||
// `Node / Http2Session` (C++) -> Http2Session (JS)
|
// `Node / Http2Session` (C++) -> Http2Session (JS)
|
||||||
state.validateSnapshotNodes('Node / Http2Session', [
|
const sessions = validateByRetainingPathFromNodes(nodes, 'Node / Http2Session', []);
|
||||||
{
|
validateByRetainingPathFromNodes(sessions, 'Node / Http2Session', [
|
||||||
children: [
|
{ node_name: 'Http2Session', edge_name: 'native_to_javascript' },
|
||||||
{ node_name: 'Http2Session', edge_name: 'native_to_javascript' },
|
]);
|
||||||
{ node_name: 'Node / nghttp2_memory', edge_name: 'nghttp2_memory' },
|
validateByRetainingPathFromNodes(sessions, 'Node / Http2Session', [
|
||||||
{
|
{ node_name: 'Node / nghttp2_memory', edge_name: 'nghttp2_memory' },
|
||||||
node_name: 'Node / streams', edge_name: 'streams',
|
]);
|
||||||
},
|
validateByRetainingPathFromNodes(sessions, 'Node / Http2Session', [
|
||||||
// outstanding_pings, outgoing_buffers, outgoing_storage,
|
{ node_name: 'Node / streams', edge_name: 'streams' },
|
||||||
// pending_rst_streams could be empty
|
]);
|
||||||
],
|
// outstanding_pings, outgoing_buffers, outgoing_storage,
|
||||||
},
|
// pending_rst_streams could be empty
|
||||||
], { loose: true });
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
req.resume();
|
req.resume();
|
||||||
|
@ -1,44 +1,29 @@
|
|||||||
// Flags: --expose-internals
|
|
||||||
'use strict';
|
'use strict';
|
||||||
const common = require('../common');
|
// This tests heap snapshot integration of inspector.
|
||||||
|
|
||||||
|
const common = require('../common');
|
||||||
|
const assert = require('assert');
|
||||||
common.skipIfInspectorDisabled();
|
common.skipIfInspectorDisabled();
|
||||||
|
|
||||||
const { validateSnapshotNodes } = require('../common/heap');
|
const { validateByRetainingPath, validateByRetainingPathFromNodes } = require('../common/heap');
|
||||||
const inspector = require('inspector');
|
const inspector = require('inspector');
|
||||||
|
|
||||||
const snapshotNode = {
|
// Starts with no JSBindingsConnection.
|
||||||
children: [
|
|
||||||
{ node_name: 'Node / InspectorSession', edge_name: 'session' },
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
// Starts with no JSBindingsConnection (or 1 if coverage enabled).
|
|
||||||
{
|
{
|
||||||
const expected = [];
|
const nodes = validateByRetainingPath('Node / JSBindingsConnection', []);
|
||||||
if (process.env.NODE_V8_COVERAGE) {
|
assert.strictEqual(nodes.length, 0);
|
||||||
expected.push(snapshotNode);
|
|
||||||
}
|
|
||||||
validateSnapshotNodes('Node / JSBindingsConnection', expected);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// JSBindingsConnection should be added.
|
// JSBindingsConnection should be added once inspector session is created.
|
||||||
{
|
{
|
||||||
const session = new inspector.Session();
|
const session = new inspector.Session();
|
||||||
session.connect();
|
session.connect();
|
||||||
const expected = [
|
|
||||||
{
|
const nodes = validateByRetainingPath('Node / JSBindingsConnection', []);
|
||||||
children: [
|
validateByRetainingPathFromNodes(nodes, 'Node / JSBindingsConnection', [
|
||||||
{ node_name: 'Node / InspectorSession', edge_name: 'session' },
|
{ node_name: 'Node / InspectorSession', edge_name: 'session' },
|
||||||
{ node_name: 'Connection', edge_name: 'native_to_javascript' },
|
]);
|
||||||
(edge) => edge.name === 'callback' &&
|
validateByRetainingPathFromNodes(nodes, 'Node / JSBindingsConnection', [
|
||||||
(edge.to.type === undefined || // embedded graph
|
{ node_name: 'Connection', edge_name: 'native_to_javascript' },
|
||||||
edge.to.type === 'closure'), // snapshot
|
]);
|
||||||
],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
if (process.env.NODE_V8_COVERAGE) {
|
|
||||||
expected.push(snapshotNode);
|
|
||||||
}
|
|
||||||
validateSnapshotNodes('Node / JSBindingsConnection', expected);
|
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,16 @@
|
|||||||
// Flags: --experimental-shadow-realm --expose-internals
|
// Flags: --experimental-shadow-realm
|
||||||
|
// This tests heap snapshot integration of ShadowRealm
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
require('../common');
|
require('../common');
|
||||||
const { validateSnapshotNodes } = require('../common/heap');
|
const { validateByRetainingPath } = require('../common/heap');
|
||||||
|
const assert = require('assert');
|
||||||
|
|
||||||
validateSnapshotNodes('Node / ShadowRealm', []);
|
// Before shadow realm is created, no ShadowRealm should be captured.
|
||||||
|
{
|
||||||
|
const nodes = validateByRetainingPath('Node / ShadowRealm', []);
|
||||||
|
assert.strictEqual(nodes.length, 0);
|
||||||
|
}
|
||||||
|
|
||||||
let realm;
|
let realm;
|
||||||
let counter = 0;
|
let counter = 0;
|
||||||
@ -23,19 +30,9 @@ function createRealms() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function validateHeap() {
|
function validateHeap() {
|
||||||
validateSnapshotNodes('Node / Environment', [
|
validateByRetainingPath('Node / Environment', [
|
||||||
{
|
{ node_name: 'Node / shadow_realms', edge_name: 'shadow_realms' },
|
||||||
children: [
|
{ node_name: 'Node / ShadowRealm' },
|
||||||
{ node_name: 'Node / shadow_realms', edge_name: 'shadow_realms' },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
validateSnapshotNodes('Node / shadow_realms', [
|
|
||||||
{
|
|
||||||
children: [
|
|
||||||
{ node_name: 'Node / ShadowRealm' },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,15 +1,20 @@
|
|||||||
// Flags: --expose-internals
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
// This tests heap snapshot integration of tls sockets.
|
||||||
const common = require('../common');
|
const common = require('../common');
|
||||||
|
|
||||||
if (!common.hasCrypto)
|
if (!common.hasCrypto)
|
||||||
common.skip('missing crypto');
|
common.skip('missing crypto');
|
||||||
|
|
||||||
const { validateSnapshotNodes } = require('../common/heap');
|
const { validateByRetainingPath, validateByRetainingPathFromNodes } = require('../common/heap');
|
||||||
|
const assert = require('assert');
|
||||||
const net = require('net');
|
const net = require('net');
|
||||||
const tls = require('tls');
|
const tls = require('tls');
|
||||||
|
|
||||||
validateSnapshotNodes('Node / TLSWrap', []);
|
// 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) => {
|
const server = net.createServer(common.mustCall((c) => {
|
||||||
c.end();
|
c.end();
|
||||||
@ -21,15 +26,16 @@ const server = net.createServer(common.mustCall((c) => {
|
|||||||
}));
|
}));
|
||||||
c.write('hello');
|
c.write('hello');
|
||||||
|
|
||||||
validateSnapshotNodes('Node / TLSWrap', [
|
const nodes = validateByRetainingPath('Node / TLSWrap', []);
|
||||||
{
|
validateByRetainingPathFromNodes(nodes, 'Node / TLSWrap', [
|
||||||
children: [
|
{ node_name: 'Node / NodeBIO', edge_name: 'enc_out' },
|
||||||
{ node_name: 'Node / NodeBIO', edge_name: 'enc_out' },
|
]);
|
||||||
{ node_name: 'Node / NodeBIO', edge_name: 'enc_in' },
|
validateByRetainingPathFromNodes(nodes, 'Node / TLSWrap', [
|
||||||
// `Node / TLSWrap` (C++) -> `TLSWrap` (JS)
|
{ node_name: 'Node / NodeBIO', edge_name: 'enc_in' },
|
||||||
{ node_name: 'TLSWrap', edge_name: 'native_to_javascript' },
|
]);
|
||||||
// pending_cleartext_input could be empty
|
validateByRetainingPathFromNodes(nodes, 'Node / TLSWrap', [
|
||||||
],
|
// `Node / TLSWrap` (C++) -> `TLSWrap` (JS)
|
||||||
},
|
{ node_name: 'TLSWrap', edge_name: 'native_to_javascript' },
|
||||||
|
// pending_cleartext_input could be empty
|
||||||
]);
|
]);
|
||||||
}));
|
}));
|
||||||
|
@ -1,24 +1,23 @@
|
|||||||
// Flags: --expose-internals
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
// This tests heap snapshot integration of URLPattern.
|
||||||
require('../common');
|
require('../common');
|
||||||
const { validateSnapshotNodes } = require('../common/heap');
|
const { validateByRetainingPath } = require('../common/heap');
|
||||||
const { URLPattern } = require('node:url');
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
validateSnapshotNodes('Node / URLPattern', []);
|
|
||||||
const urlPattern = new URLPattern('https://example.com/:id');
|
const urlPattern = new URLPattern('https://example.com/:id');
|
||||||
validateSnapshotNodes('Node / URLPattern', [
|
|
||||||
{
|
// After url pattern is used, a URLPattern should be created.
|
||||||
children: [
|
validateByRetainingPath('Node / URLPattern', [
|
||||||
{ node_name: 'Node / ada::url_pattern', edge_name: 'url_pattern' },
|
{ 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' },
|
||||||
]);
|
|
||||||
validateSnapshotNodes('Node / ada::url_pattern', [
|
|
||||||
{
|
|
||||||
children: [
|
|
||||||
{ node_name: 'Node / ada::url_pattern_component', edge_name: 'protocol_component' },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Use `urlPattern`.
|
// Use `urlPattern`.
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
require('../common');
|
require('../common');
|
||||||
const { findByRetainingPath } = require('../common/heap');
|
const { validateByRetainingPath } = require('../common/heap');
|
||||||
const source = 'const foo = 123';
|
const source = 'const foo = 123';
|
||||||
const script = require('vm').createScript(source);
|
const script = require('vm').createScript(source);
|
||||||
|
|
||||||
findByRetainingPath('Node / ContextifyScript', [
|
validateByRetainingPath('Node / ContextifyScript', [
|
||||||
{ node_name: '(shared function info)' }, // This is the UnboundScript referenced by ContextifyScript.
|
{ node_name: '(shared function info)' }, // This is the UnboundScript referenced by ContextifyScript.
|
||||||
{ edge_name: 'script' },
|
{ edge_name: 'script' },
|
||||||
{ edge_name: 'source', node_type: 'string', node_name: source },
|
{ edge_name: 'source', node_type: 'string', node_name: source },
|
||||||
|
@ -1,16 +1,27 @@
|
|||||||
// Flags: --expose-internals
|
|
||||||
'use strict';
|
'use strict';
|
||||||
require('../common');
|
|
||||||
const { validateSnapshotNodes } = require('../common/heap');
|
|
||||||
const { Worker } = require('worker_threads');
|
|
||||||
|
|
||||||
validateSnapshotNodes('Node / Worker', []);
|
// 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 });
|
const worker = new Worker('setInterval(() => {}, 100);', { eval: true });
|
||||||
validateSnapshotNodes('Node / MessagePort', [
|
// When a worker is alive, a Worker instance and its message port should be captured.
|
||||||
{
|
{
|
||||||
children: [
|
validateByRetainingPath('Node / Worker', [
|
||||||
{ node_name: 'Node / MessagePortData', edge_name: 'data' },
|
{ node_name: 'Worker', edge_name: 'native_to_javascript' },
|
||||||
],
|
{ node_name: 'MessagePort', edge_name: 'messagePort' },
|
||||||
},
|
{ node_name: 'Node / MessagePort', edge_name: 'javascript_to_native' },
|
||||||
], { loose: true });
|
{ node_name: 'Node / MessagePortData', edge_name: 'data' },
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
worker.terminate();
|
worker.terminate();
|
||||||
|
@ -1,28 +1,35 @@
|
|||||||
// Flags: --expose-internals
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
// This tests heap snapshot integration of zlib stream.
|
||||||
|
|
||||||
const common = require('../common');
|
const common = require('../common');
|
||||||
const { validateSnapshotNodes } = require('../common/heap');
|
const assert = require('assert');
|
||||||
|
const { validateByRetainingPath, validateByRetainingPathFromNodes } = require('../common/heap');
|
||||||
const zlib = require('zlib');
|
const zlib = require('zlib');
|
||||||
|
|
||||||
validateSnapshotNodes('Node / ZlibStream', []);
|
// Before zlib stream is created, no ZlibStream should be created.
|
||||||
|
{
|
||||||
|
const nodes = validateByRetainingPath('Node / ZlibStream', []);
|
||||||
|
assert.strictEqual(nodes.length, 0);
|
||||||
|
}
|
||||||
|
|
||||||
const gzip = zlib.createGzip();
|
const gzip = zlib.createGzip();
|
||||||
validateSnapshotNodes('Node / ZlibStream', [
|
|
||||||
{
|
|
||||||
children: [
|
|
||||||
{ node_name: 'Zlib', edge_name: 'native_to_javascript' },
|
|
||||||
// No entry for memory because zlib memory is initialized lazily.
|
|
||||||
],
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
|
||||||
|
// 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(() => {
|
gzip.write('hello world', common.mustCall(() => {
|
||||||
validateSnapshotNodes('Node / ZlibStream', [
|
validateByRetainingPath('Node / ZlibStream', [
|
||||||
{
|
{ node_name: 'Node / zlib_memory', edge_name: 'zlib_memory' },
|
||||||
children: [
|
|
||||||
{ node_name: 'Zlib', edge_name: 'native_to_javascript' },
|
|
||||||
{ node_name: 'Node / zlib_memory', edge_name: 'zlib_memory' },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
]);
|
]);
|
||||||
}));
|
}));
|
||||||
|
Loading…
Reference in New Issue
Block a user