eng: add assertHeap method for memory assertions (#198334)

This adds an `assertHeap` function that can be used in tests. It
takes a heap snapshot, and asserts the state of classes in memory. This
works in Node and the Electron sandbox, but is a no-op in the browser.
Snapshots are process asynchronously and will report failures at the end
of the suite.

This method should be used sparingly (e.g. once at the end of a suite to
ensure nothing leaked before), as gathering a heap snapshot is fairly
slow, at least until V8 11.5.130 (https://v8.dev/blog/speeding-up-v8-heap-snapshots).

When used, the function will ensure the test has a minimum timeout
duration of 20s to avoid immediate failures.

It takes options containing a mapping of class names, and assertion functions
to run on the number of retained instances of that class. For example:

```ts
assertSnapshot({
	classes: {
		ShouldNeverLeak: count => assert.strictEqual(count, 0),
		SomeSingleton: count => assert(count <= 1),
	}
});
```

Closes https://github.com/microsoft/vscode/issues/191920
This commit is contained in:
Connor Peet
2023-11-15 10:41:22 -08:00
committed by GitHub
parent 8cac42ebe2
commit a0b548807a
7 changed files with 181 additions and 1 deletions

View File

@@ -16,6 +16,7 @@ const glob = require('glob');
const minimatch = require('minimatch');
const coverage = require('../coverage');
const minimist = require('minimist');
const { takeSnapshotAndCountClasses } = require('../analyzeSnapshot');
/**
* @type {{ build: boolean; run: string; runGlob: string; coverage: boolean; help: boolean; }}
@@ -83,6 +84,7 @@ function main() {
// Test file operations that are common across platforms. Used for test infra, namely snapshot tests
Object.assign(globalThis, {
__analyzeSnapshotInTests: takeSnapshotAndCountClasses,
__readFileInTests: (/** @type {string} */ path) => fs.promises.readFile(path, 'utf-8'),
__writeFileInTests: (/** @type {string} */ path, /** @type {BufferEncoding} */ contents) => fs.promises.writeFile(path, contents),
__readDirInTests: (/** @type {string} */ path) => fs.promises.readdir(path),