diff options
Diffstat (limited to 'test/common')
-rw-r--r-- | test/common/README.md | 37 | ||||
-rw-r--r-- | test/common/heap.js | 80 |
2 files changed, 117 insertions, 0 deletions
diff --git a/test/common/README.md b/test/common/README.md index 111ce45b00..c0051ad9f7 100644 --- a/test/common/README.md +++ b/test/common/README.md @@ -10,6 +10,7 @@ This directory contains modules used to test the Node.js implementation. * [DNS module](#dns-module) * [Duplex pair helper](#duplex-pair-helper) * [Fixtures module](#fixtures-module) +* [Heap dump checker module](#heap-dump-checker-module) * [HTTP2 module](#http2-module) * [Internet module](#internet-module) * [tmpdir module](#tmpdir-module) @@ -538,6 +539,42 @@ Returns the result of Returns the result of `fs.readFileSync(path.join(fixtures.fixturesDir, 'keys', arg), 'enc')`. +## Heap dump checker module + +This provides utilities for checking the validity of heap dumps. +This requires the usage of `--expose-internals`. + +### heap.recordState() + +Create a heap dump and an embedder graph copy for inspection. +The returned object has a `validateSnapshotNodes` function similar to the +one listed below. (`heap.validateSnapshotNodes(...)` is a shortcut for +`heap.recordState().validateSnapshotNodes(...)`.) + +### heap.validateSnapshotNodes(name, expected, options) + +* `name` [<string>] Look for this string as the name of heap dump nodes. +* `expected` [<Array>] A list of objects, possibly with an `children` + property that points to expected other adjacent nodes. +* `options` [<Array>] + * `loose` [<boolean>] Do not expect an exact listing of occurrences + of nodes with name `name` in `expected`. + +Create a heap dump and an embedder graph copy and validate occurrences. + +<!-- eslint-disable no-undef, no-unused-vars, node-core/required-modules, strict --> +```js +validateSnapshotNodes('TLSWRAP', [ + { + children: [ + { name: 'enc_out' }, + { name: 'enc_in' }, + { name: 'TLSWrap' } + ] + } +]); +``` + ## HTTP/2 Module The http2.js module provides a handful of utilities for creating mock HTTP/2 diff --git a/test/common/heap.js b/test/common/heap.js new file mode 100644 index 0000000000..a02de9a606 --- /dev/null +++ b/test/common/heap.js @@ -0,0 +1,80 @@ +/* eslint-disable node-core/required-modules */ +'use strict'; +const assert = require('assert'); +const util = require('util'); + +let internalTestHeap; +try { + internalTestHeap = require('internal/test/heap'); +} catch (e) { + console.log('using `test/common/heap.js` requires `--expose-internals`'); + throw e; +} +const { createJSHeapDump, buildEmbedderGraph } = internalTestHeap; + +class State { + constructor() { + this.snapshot = createJSHeapDump(); + this.embedderGraph = buildEmbedderGraph(); + } + + validateSnapshotNodes(name, expected, { loose = false } = {}) { + const snapshot = this.snapshot.filter( + (node) => node.name === 'Node / ' + name && node.type !== 'string'); + if (loose) + assert(snapshot.length >= expected.length); + else + assert.strictEqual(snapshot.length, expected.length); + for (const expectedNode of expected) { + if (expectedNode.children) { + for (const expectedChild of expectedNode.children) { + const check = typeof expectedChild === 'function' ? + expectedChild : + (node) => [expectedChild.name, 'Node / ' + expectedChild.name] + .includes(node.name); + + assert(snapshot.some((node) => { + return node.outgoingEdges.map((edge) => edge.toNode).some(check); + }), `expected to find child ${util.inspect(expectedChild)} ` + + `in ${util.inspect(snapshot)}`); + } + } + } + + const graph = this.embedderGraph.filter((node) => node.name === name); + if (loose) + assert(graph.length >= expected.length); + else + assert.strictEqual(graph.length, expected.length); + for (const expectedNode of expected) { + if (expectedNode.edges) { + for (const expectedChild of expectedNode.children) { + const check = typeof expectedChild === 'function' ? + expectedChild : (node) => { + return node.name === expectedChild.name || + (node.value && + node.value.constructor && + node.value.constructor.name === expectedChild.name); + }; + + assert(graph.some((node) => node.edges.some(check)), + `expected to find child ${util.inspect(expectedChild)} ` + + `in ${util.inspect(snapshot)}`); + } + } + } + } +} + +function recordState() { + return new State(); +} + +function validateSnapshotNodes(...args) { + return recordState().validateSnapshotNodes(...args); +} + +module.exports = { + recordState, + validateSnapshotNodes +}; |