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.
|
||||
* Modified from
|
||||
* 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
|
||||
* this name. For cppgc-managed objects, this is typically the name configured by
|
||||
* SET_CPPGC_NAME() prefixed with an additional "Node /" prefix e.g.
|
||||
@ -231,12 +232,12 @@ function validateSnapshotNodes(...args) {
|
||||
* node_type?: string,
|
||||
* edge_type?: string,
|
||||
* }]} 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,
|
||||
* logs the nodes found in the last matching step of the path (if any), and throws an
|
||||
* assertion error.
|
||||
*/
|
||||
function findByRetainingPath(rootName, retainingPath) {
|
||||
const nodes = createJSHeapSnapshot();
|
||||
function validateByRetainingPathFromNodes(nodes, rootName, retainingPath, allowEmpty = false) {
|
||||
let haystack = nodes.filter((n) => n.name === rootName && n.type !== 'string');
|
||||
|
||||
for (let i = 0; i < retainingPath.length; ++i) {
|
||||
@ -269,6 +270,9 @@ function findByRetainingPath(rootName, retainingPath) {
|
||||
}
|
||||
|
||||
if (newHaystack.length === 0) {
|
||||
if (allowEmpty) {
|
||||
return [];
|
||||
}
|
||||
const format = (val) => util.inspect(val, { breakLength: 128, depth: 3 });
|
||||
console.error('#');
|
||||
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.`);
|
||||
|
||||
}
|
||||
|
||||
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 = {
|
||||
recordState,
|
||||
validateSnapshotNodes,
|
||||
findByRetainingPath,
|
||||
validateByRetainingPath,
|
||||
validateByRetainingPathFromNodes,
|
||||
getHeapSnapshotOptionTests,
|
||||
createJSHeapSnapshot,
|
||||
};
|
||||
|
@ -1,19 +1,31 @@
|
||||
// Flags: --expose-internals
|
||||
'use strict';
|
||||
require('../common');
|
||||
const { validateSnapshotNodes } = require('../common/heap');
|
||||
// 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);
|
||||
}
|
||||
|
||||
validateSnapshotNodes('Node / ChannelWrap', []);
|
||||
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', () => {});
|
||||
validateSnapshotNodes('Node / ChannelWrap', [
|
||||
{
|
||||
children: [
|
||||
{ node_name: 'Node / NodeAresTask::List', edge_name: 'task_list' },
|
||||
// `Node / ChannelWrap` (C++) -> `ChannelWrap` (JS)
|
||||
{ node_name: 'ChannelWrap', edge_name: 'native_to_javascript' },
|
||||
],
|
||||
detachedness: 2,
|
||||
},
|
||||
]);
|
||||
|
||||
// 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' },
|
||||
]);
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
// Flags: --expose-internals
|
||||
'use strict';
|
||||
|
||||
// This tests that Environment is tracked in heap snapshots.
|
||||
@ -6,19 +5,24 @@
|
||||
// test-heapdump-*.js files.
|
||||
|
||||
require('../common');
|
||||
const { validateSnapshotNodes } = require('../common/heap');
|
||||
const { createJSHeapSnapshot, validateByRetainingPathFromNodes } = require('../common/heap');
|
||||
|
||||
validateSnapshotNodes('Node / Environment', [{
|
||||
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' },
|
||||
],
|
||||
}]);
|
||||
const nodes = createJSHeapSnapshot();
|
||||
|
||||
validateSnapshotNodes('Node / PrincipalRealm', [{
|
||||
children: [
|
||||
{ node_name: 'process', edge_name: 'process_object' },
|
||||
{ node_name: 'Node / BaseObjectList', edge_name: 'base_object_list' },
|
||||
],
|
||||
}]);
|
||||
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' },
|
||||
]);
|
||||
|
@ -1,16 +1,26 @@
|
||||
// Flags: --expose-internals
|
||||
'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);
|
||||
validateSnapshotNodes('Node / FSReqPromise', [
|
||||
{
|
||||
children: [
|
||||
{ node_name: 'FSReqPromise', edge_name: 'native_to_javascript' },
|
||||
{ node_name: 'Node / AliasedFloat64Array', edge_name: 'stats_field_array' },
|
||||
],
|
||||
},
|
||||
]);
|
||||
|
||||
{
|
||||
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' },
|
||||
]);
|
||||
}
|
||||
|
@ -1,15 +1,21 @@
|
||||
// Flags: --expose-internals
|
||||
'use strict';
|
||||
|
||||
// This tests heap snapshot integration of http2.
|
||||
|
||||
const common = require('../common');
|
||||
const { recordState } = require('../common/heap');
|
||||
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 state = recordState();
|
||||
state.validateSnapshotNodes('Node / Http2Session', []);
|
||||
state.validateSnapshotNodes('Node / Http2Stream', []);
|
||||
const sessions = validateByRetainingPath('Node / Http2Session', []);
|
||||
assert.strictEqual(sessions.length, 0);
|
||||
const streams = validateByRetainingPath('Node / Http2Stream', []);
|
||||
assert.strictEqual(streams.length, 0);
|
||||
}
|
||||
|
||||
const server = http2.createServer();
|
||||
@ -21,63 +27,45 @@ server.listen(0, () => {
|
||||
const req = client.request();
|
||||
|
||||
req.on('response', common.mustCall(() => {
|
||||
const state = recordState();
|
||||
const nodes = createJSHeapSnapshot();
|
||||
|
||||
// `Node / Http2Stream` (C++) -> Http2Stream (JS)
|
||||
state.validateSnapshotNodes('Node / Http2Stream', [
|
||||
{
|
||||
children: [
|
||||
// current_headers and/or queue could be empty
|
||||
{ node_name: 'Http2Stream', edge_name: 'native_to_javascript' },
|
||||
],
|
||||
},
|
||||
], { loose: true });
|
||||
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)
|
||||
state.validateSnapshotNodes('Node / FileHandle', [
|
||||
{
|
||||
children: [
|
||||
{ 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 / 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' },
|
||||
]);
|
||||
|
||||
// `Node / StreamPipe` (C++) -> StreamPipe (JS)
|
||||
validateByRetainingPathFromNodes(nodes, 'Node / StreamPipe', [
|
||||
{ node_name: 'StreamPipe', edge_name: 'native_to_javascript' },
|
||||
]);
|
||||
|
||||
// `Node / Http2Session` (C++) -> Http2Session (JS)
|
||||
state.validateSnapshotNodes('Node / Http2Session', [
|
||||
{
|
||||
children: [
|
||||
{ node_name: 'Http2Session', edge_name: 'native_to_javascript' },
|
||||
{ node_name: 'Node / nghttp2_memory', edge_name: 'nghttp2_memory' },
|
||||
{
|
||||
node_name: 'Node / streams', edge_name: 'streams',
|
||||
},
|
||||
// outstanding_pings, outgoing_buffers, outgoing_storage,
|
||||
// pending_rst_streams could be empty
|
||||
],
|
||||
},
|
||||
], { loose: true });
|
||||
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();
|
||||
|
@ -1,44 +1,29 @@
|
||||
// Flags: --expose-internals
|
||||
'use strict';
|
||||
const common = require('../common');
|
||||
// This tests heap snapshot integration of inspector.
|
||||
|
||||
const common = require('../common');
|
||||
const assert = require('assert');
|
||||
common.skipIfInspectorDisabled();
|
||||
|
||||
const { validateSnapshotNodes } = require('../common/heap');
|
||||
const { validateByRetainingPath, validateByRetainingPathFromNodes } = require('../common/heap');
|
||||
const inspector = require('inspector');
|
||||
|
||||
const snapshotNode = {
|
||||
children: [
|
||||
{ node_name: 'Node / InspectorSession', edge_name: 'session' },
|
||||
],
|
||||
};
|
||||
|
||||
// Starts with no JSBindingsConnection (or 1 if coverage enabled).
|
||||
// Starts with no JSBindingsConnection.
|
||||
{
|
||||
const expected = [];
|
||||
if (process.env.NODE_V8_COVERAGE) {
|
||||
expected.push(snapshotNode);
|
||||
}
|
||||
validateSnapshotNodes('Node / JSBindingsConnection', expected);
|
||||
const nodes = validateByRetainingPath('Node / JSBindingsConnection', []);
|
||||
assert.strictEqual(nodes.length, 0);
|
||||
}
|
||||
|
||||
// JSBindingsConnection should be added.
|
||||
// JSBindingsConnection should be added once inspector session is created.
|
||||
{
|
||||
const session = new inspector.Session();
|
||||
session.connect();
|
||||
const expected = [
|
||||
{
|
||||
children: [
|
||||
{ node_name: 'Node / InspectorSession', edge_name: 'session' },
|
||||
{ node_name: 'Connection', edge_name: 'native_to_javascript' },
|
||||
(edge) => edge.name === 'callback' &&
|
||||
(edge.to.type === undefined || // embedded graph
|
||||
edge.to.type === 'closure'), // snapshot
|
||||
],
|
||||
},
|
||||
];
|
||||
if (process.env.NODE_V8_COVERAGE) {
|
||||
expected.push(snapshotNode);
|
||||
}
|
||||
validateSnapshotNodes('Node / JSBindingsConnection', expected);
|
||||
|
||||
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' },
|
||||
]);
|
||||
}
|
||||
|
@ -1,9 +1,16 @@
|
||||
// Flags: --experimental-shadow-realm --expose-internals
|
||||
// Flags: --experimental-shadow-realm
|
||||
// This tests heap snapshot integration of ShadowRealm
|
||||
|
||||
'use strict';
|
||||
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 counter = 0;
|
||||
@ -23,19 +30,9 @@ function createRealms() {
|
||||
}
|
||||
|
||||
function validateHeap() {
|
||||
validateSnapshotNodes('Node / Environment', [
|
||||
{
|
||||
children: [
|
||||
{ node_name: 'Node / shadow_realms', edge_name: 'shadow_realms' },
|
||||
],
|
||||
},
|
||||
]);
|
||||
validateSnapshotNodes('Node / shadow_realms', [
|
||||
{
|
||||
children: [
|
||||
{ node_name: 'Node / ShadowRealm' },
|
||||
],
|
||||
},
|
||||
validateByRetainingPath('Node / Environment', [
|
||||
{ node_name: 'Node / shadow_realms', edge_name: 'shadow_realms' },
|
||||
{ node_name: 'Node / ShadowRealm' },
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -1,15 +1,20 @@
|
||||
// Flags: --expose-internals
|
||||
'use strict';
|
||||
// This tests heap snapshot integration of tls sockets.
|
||||
const common = require('../common');
|
||||
|
||||
if (!common.hasCrypto)
|
||||
common.skip('missing crypto');
|
||||
|
||||
const { validateSnapshotNodes } = require('../common/heap');
|
||||
const { validateByRetainingPath, validateByRetainingPathFromNodes } = require('../common/heap');
|
||||
const assert = require('assert');
|
||||
const net = require('net');
|
||||
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) => {
|
||||
c.end();
|
||||
@ -21,15 +26,16 @@ const server = net.createServer(common.mustCall((c) => {
|
||||
}));
|
||||
c.write('hello');
|
||||
|
||||
validateSnapshotNodes('Node / TLSWrap', [
|
||||
{
|
||||
children: [
|
||||
{ node_name: 'Node / NodeBIO', edge_name: 'enc_out' },
|
||||
{ node_name: 'Node / NodeBIO', edge_name: 'enc_in' },
|
||||
// `Node / TLSWrap` (C++) -> `TLSWrap` (JS)
|
||||
{ node_name: 'TLSWrap', edge_name: 'native_to_javascript' },
|
||||
// pending_cleartext_input could be empty
|
||||
],
|
||||
},
|
||||
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
|
||||
]);
|
||||
}));
|
||||
|
@ -1,24 +1,23 @@
|
||||
// Flags: --expose-internals
|
||||
'use strict';
|
||||
// This tests heap snapshot integration of URLPattern.
|
||||
require('../common');
|
||||
const { validateSnapshotNodes } = require('../common/heap');
|
||||
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);
|
||||
}
|
||||
|
||||
validateSnapshotNodes('Node / URLPattern', []);
|
||||
const urlPattern = new URLPattern('https://example.com/:id');
|
||||
validateSnapshotNodes('Node / URLPattern', [
|
||||
{
|
||||
children: [
|
||||
{ node_name: 'Node / ada::url_pattern', edge_name: 'url_pattern' },
|
||||
],
|
||||
},
|
||||
]);
|
||||
validateSnapshotNodes('Node / ada::url_pattern', [
|
||||
{
|
||||
children: [
|
||||
{ node_name: 'Node / ada::url_pattern_component', edge_name: 'protocol_component' },
|
||||
],
|
||||
},
|
||||
|
||||
// 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`.
|
||||
|
@ -1,10 +1,10 @@
|
||||
'use strict';
|
||||
require('../common');
|
||||
const { findByRetainingPath } = require('../common/heap');
|
||||
const { validateByRetainingPath } = require('../common/heap');
|
||||
const source = 'const foo = 123';
|
||||
const script = require('vm').createScript(source);
|
||||
|
||||
findByRetainingPath('Node / ContextifyScript', [
|
||||
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 },
|
||||
|
@ -1,16 +1,27 @@
|
||||
// Flags: --expose-internals
|
||||
'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 });
|
||||
validateSnapshotNodes('Node / MessagePort', [
|
||||
{
|
||||
children: [
|
||||
{ node_name: 'Node / MessagePortData', edge_name: 'data' },
|
||||
],
|
||||
},
|
||||
], { loose: 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();
|
||||
|
@ -1,28 +1,35 @@
|
||||
// Flags: --expose-internals
|
||||
'use strict';
|
||||
// This tests heap snapshot integration of zlib stream.
|
||||
|
||||
const common = require('../common');
|
||||
const { validateSnapshotNodes } = require('../common/heap');
|
||||
const assert = require('assert');
|
||||
const { validateByRetainingPath, validateByRetainingPathFromNodes } = require('../common/heap');
|
||||
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();
|
||||
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(() => {
|
||||
validateSnapshotNodes('Node / ZlibStream', [
|
||||
{
|
||||
children: [
|
||||
{ node_name: 'Zlib', edge_name: 'native_to_javascript' },
|
||||
{ node_name: 'Node / zlib_memory', edge_name: 'zlib_memory' },
|
||||
],
|
||||
},
|
||||
validateByRetainingPath('Node / ZlibStream', [
|
||||
{ node_name: 'Node / zlib_memory', edge_name: 'zlib_memory' },
|
||||
]);
|
||||
}));
|
||||
|
Loading…
Reference in New Issue
Block a user