GeezerVison is showing github.com — test: merge ongc and gcutil into gc.js · nodejs/node@10bea1c
File treeExpand file treeCollapse file tree Open diff view settings node-api/test_reference_by_node_api_version
Expand file treeCollapse file tree Open diff view settings Collapse file Copy file name to clipboardExpand all lines: test/addons/cppgc-object/test.js +3-3Lines changed: 3 additions & 3 deletions | Original file line number | Diff line number | Diff line change |
|---|
| 3 | 3 | // Flags: --expose-gc | 4 | 4 |
| 5 | 5 | const common = require('../../common'); | 6 | | - | | 6 | +const { gcUntil } = require('../../common/gc'); | 7 | 7 | // Verify that addons can create GarbageCollected objects and | 8 | 8 | // have them traced properly. | 9 | 9 |
| @@ -35,7 +35,7 @@ setTimeout(async function() { | 35 | 35 | for (let i = 0; i < count; ++i) { | 36 | 36 | array[i] = new CppGCed(); | 37 | 37 | } | 38 | | - await common.gcUntil( | | 38 | + await gcUntil( | 39 | 39 | 'All old CppGCed are destroyed', | 40 | 40 | () => states[kDestructCount] === count, | 41 | 41 | ); | @@ -44,7 +44,7 @@ setTimeout(async function() { | 44 | 44 | array = null; | 45 | 45 | globalThis.gc(); | 46 | 46 |
| 47 | | - await common.gcUntil( | | 47 | + await gcUntil( | 48 | 48 | 'All old CppGCed are destroyed', | 49 | 49 | () => states[kDestructCount] === count * 2, | 50 | 50 | ); | |
Collapse file Copy file name to clipboardExpand all lines: test/async-hooks/test-async-local-storage-gcable.js +1-1Lines changed: 1 addition & 1 deletion | Original file line number | Diff line number | Diff line change |
|---|
| 6 | 6 |
| 7 | 7 | const common = require('../common'); | 8 | 8 | const { AsyncLocalStorage } = require('async_hooks'); | 9 | | -const onGC = require('../common/ongc'); | | 9 | +const { onGC } = require('../common/gc'); | 10 | 10 |
| 11 | 11 | let asyncLocalStorage = new AsyncLocalStorage(); | 12 | 12 |
| |
Collapse file Copy file name to clipboardExpand all lines: test/common/README.md +1-1Lines changed: 1 addition & 1 deletion - Display the source diff
- Display the rich diff
| Original file line number | Diff line number | Diff line change |
|---|
@@ -982,7 +982,7 @@ module exports a single `onGC()` function. | 982 | 982 |
| 983 | 983 | ```js | 984 | 984 | require('../common'); | 985 | | -const onGC = require('../common/ongc'); | | 985 | +const { onGC } = require('../common/gc'); | 986 | 986 |
| 987 | 987 | onGC({}, { ongc() { console.log('collected'); } }); | 988 | 988 | ``` | |
Collapse file Copy file name to clipboardExpand all lines: test/common/gc.js +67-2Lines changed: 67 additions & 2 deletions | Original file line number | Diff line number | Diff line change |
|---|
| 1 | 1 | 'use strict'; | 2 | 2 |
| 3 | 3 | const wait = require('timers/promises').setTimeout; | | 4 | +const assert = require('assert'); | | 5 | +const common = require('../common'); | | 6 | +const gcTrackerMap = new WeakMap(); | | 7 | +const gcTrackerTag = 'NODE_TEST_COMMON_GC_TRACKER'; | 4 | 8 |
| 5 | | -// TODO(joyeecheung): merge ongc.js and gcUntil from common/index.js | 6 | | -// into this. | | 9 | +/** | | 10 | + * Installs a garbage collection listener for the specified object. | | 11 | + * Uses async_hooks for GC tracking, which may affect test functionality. | | 12 | + * A full setImmediate() invocation passes between a global.gc() call and the listener being invoked. | | 13 | + * @param {object} obj - The target object to track for garbage collection. | | 14 | + * @param {object} gcListener - The listener object containing the ongc callback. | | 15 | + * @param {Function} gcListener.ongc - The function to call when the target object is garbage collected. | | 16 | + */ | | 17 | +function onGC(obj, gcListener) { | | 18 | + const async_hooks = require('async_hooks'); | | 19 | + | | 20 | + const onGcAsyncHook = async_hooks.createHook({ | | 21 | + init: common.mustCallAtLeast(function(id, type) { | | 22 | + if (this.trackedId === undefined) { | | 23 | + assert.strictEqual(type, gcTrackerTag); | | 24 | + this.trackedId = id; | | 25 | + } | | 26 | + }), | | 27 | + destroy(id) { | | 28 | + assert.notStrictEqual(this.trackedId, -1); | | 29 | + if (id === this.trackedId) { | | 30 | + this.gcListener.ongc(); | | 31 | + onGcAsyncHook.disable(); | | 32 | + } | | 33 | + }, | | 34 | + }).enable(); | | 35 | + onGcAsyncHook.gcListener = gcListener; | | 36 | + | | 37 | + gcTrackerMap.set(obj, new async_hooks.AsyncResource(gcTrackerTag)); | | 38 | + obj = null; | | 39 | +} | | 40 | + | | 41 | +/** | | 42 | + * Repeatedly triggers garbage collection until a specified condition is met or a maximum number of attempts is reached. | | 43 | + * @param {string|Function} [name] - Optional name, used in the rejection message if the condition is not met. | | 44 | + * @param {Function} condition - A function that returns true when the desired condition is met. | | 45 | + * @returns {Promise} A promise that resolves when the condition is met, or rejects after 10 failed attempts. | | 46 | + */ | | 47 | +function gcUntil(name, condition) { | | 48 | + if (typeof name === 'function') { | | 49 | + condition = name; | | 50 | + name = undefined; | | 51 | + } | | 52 | + return new Promise((resolve, reject) => { | | 53 | + let count = 0; | | 54 | + function gcAndCheck() { | | 55 | + setImmediate(() => { | | 56 | + count++; | | 57 | + global.gc(); | | 58 | + if (condition()) { | | 59 | + resolve(); | | 60 | + } else if (count < 10) { | | 61 | + gcAndCheck(); | | 62 | + } else { | | 63 | + reject(name === undefined ? undefined : 'Test ' + name + ' failed'); | | 64 | + } | | 65 | + }); | | 66 | + } | | 67 | + gcAndCheck(); | | 68 | + }); | | 69 | +} | 7 | 70 |
| 8 | 71 | // This function can be used to check if an object factor leaks or not, | 9 | 72 | // but it needs to be used with care: | @@ -124,4 +187,6 @@ module.exports = { | 124 | 187 | checkIfCollectable, | 125 | 188 | runAndBreathe, | 126 | 189 | checkIfCollectableByCounting, | | 190 | + onGC, | | 191 | + gcUntil, | 127 | 192 | }; |
Collapse file Copy file name to clipboardExpand all lines: test/common/index.js -25Lines changed: 0 additions & 25 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -837,30 +837,6 @@ function skipIfDumbTerminal() { | 837 | 837 | } | 838 | 838 | } | 839 | 839 |
| 840 | | -function gcUntil(name, condition) { | 841 | | - if (typeof name === 'function') { | 842 | | - condition = name; | 843 | | - name = undefined; | 844 | | - } | 845 | | - return new Promise((resolve, reject) => { | 846 | | - let count = 0; | 847 | | - function gcAndCheck() { | 848 | | - setImmediate(() => { | 849 | | - count++; | 850 | | - global.gc(); | 851 | | - if (condition()) { | 852 | | - resolve(); | 853 | | - } else if (count < 10) { | 854 | | - gcAndCheck(); | 855 | | - } else { | 856 | | - reject(name === undefined ? undefined : 'Test ' + name + ' failed'); | 857 | | - } | 858 | | - }); | 859 | | - } | 860 | | - gcAndCheck(); | 861 | | - }); | 862 | | -} | 863 | | - | 864 | 840 | function requireNoPackageJSONAbove(dir = __dirname) { | 865 | 841 | let possiblePackage = path.join(dir, '..', 'package.json'); | 866 | 842 | let lastPackage = null; | @@ -966,7 +942,6 @@ const common = { | 966 | 942 | expectsError, | 967 | 943 | expectRequiredModule, | 968 | 944 | expectWarning, | 969 | | - gcUntil, | 970 | 945 | getArrayBufferViews, | 971 | 946 | getBufferSources, | 972 | 947 | getCallSite, | |
Collapse file Copy file name to clipboardExpand all lines: test/common/ongc.js -32Lines changed: 0 additions & 32 deletions Collapse file Copy file name to clipboardExpand all lines: test/js-native-api/6_object_wrap/test-object-wrap-ref.js +2-1Lines changed: 2 additions & 1 deletion | Original file line number | Diff line number | Diff line change |
|---|
| 3 | 3 | 'use strict'; | 4 | 4 | const common = require('../../common'); | 5 | 5 | const addon = require(`./build/${common.buildType}/6_object_wrap`); | | 6 | +const { gcUntil } = require('../../common/gc'); | 6 | 7 |
| 7 | 8 | (function scope() { | 8 | 9 | addon.objectWrapDanglingReference({}); | 9 | 10 | })(); | 10 | 11 |
| 11 | | -common.gcUntil('object-wrap-ref', () => { | | 12 | +gcUntil('object-wrap-ref', () => { | 12 | 13 | return addon.objectWrapDanglingReferenceTest(); | 13 | 14 | }); |
Collapse file Copy file name to clipboardExpand all lines: test/js-native-api/7_factory_wrap/test.js +3-2Lines changed: 3 additions & 2 deletions | Original file line number | Diff line number | Diff line change |
|---|
| 4 | 4 | const common = require('../../common'); | 5 | 5 | const assert = require('assert'); | 6 | 6 | const test = require(`./build/${common.buildType}/7_factory_wrap`); | | 7 | +const { gcUntil } = require('../../common/gc'); | 7 | 8 |
| 8 | 9 | assert.strictEqual(test.finalizeCount, 0); | 9 | 10 | async function runGCTests() { | @@ -13,14 +14,14 @@ async function runGCTests() { | 13 | 14 | assert.strictEqual(obj.plusOne(), 12); | 14 | 15 | assert.strictEqual(obj.plusOne(), 13); | 15 | 16 | })(); | 16 | | - await common.gcUntil('test 1', () => (test.finalizeCount === 1)); | | 17 | + await gcUntil('test 1', () => (test.finalizeCount === 1)); | 17 | 18 |
| 18 | 19 | (() => { | 19 | 20 | const obj2 = test.createObject(20); | 20 | 21 | assert.strictEqual(obj2.plusOne(), 21); | 21 | 22 | assert.strictEqual(obj2.plusOne(), 22); | 22 | 23 | assert.strictEqual(obj2.plusOne(), 23); | 23 | 24 | })(); | 24 | | - await common.gcUntil('test 2', () => (test.finalizeCount === 2)); | | 25 | + await gcUntil('test 2', () => (test.finalizeCount === 2)); | 25 | 26 | } | 26 | 27 | runGCTests(); |
Collapse file Copy file name to clipboardExpand all lines: test/js-native-api/8_passing_wrapped/test.js +3-2Lines changed: 3 additions & 2 deletions | Original file line number | Diff line number | Diff line change |
|---|
| 4 | 4 | const common = require('../../common'); | 5 | 5 | const assert = require('assert'); | 6 | 6 | const addon = require(`./build/${common.buildType}/8_passing_wrapped`); | | 7 | +const { gcUntil } = require('../../common/gc'); | 7 | 8 |
| 8 | 9 | async function runTest() { | 9 | 10 | let obj1 = addon.createObject(10); | @@ -14,7 +15,7 @@ async function runTest() { | 14 | 15 | // Make sure the native destructor gets called. | 15 | 16 | obj1 = null; | 16 | 17 | obj2 = null; | 17 | | - await common.gcUntil('8_passing_wrapped', | 18 | | - () => (addon.finalizeCount() === 2)); | | 18 | + await gcUntil('8_passing_wrapped', | | 19 | + () => (addon.finalizeCount() === 2)); | 19 | 20 | } | 20 | 21 | runTest(); |
Collapse file Copy file name to clipboardExpand all lines: test/js-native-api/test_finalizer/test.js +6-4Lines changed: 6 additions & 4 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -5,8 +5,10 @@ const common = require('../../common'); | 5 | 5 | const test_finalizer = require(`./build/${common.buildType}/test_finalizer`); | 6 | 6 | const assert = require('assert'); | 7 | 7 |
| | 8 | +const { gcUntil } = require('../../common/gc'); | | 9 | + | 8 | 10 | // The goal of this test is to show that we can run "pure" finalizers in the | 9 | | -// current JS loop tick. Thus, we do not use common.gcUntil function works | | 11 | +// current JS loop tick. Thus, we do not use gcUntil function works | 10 | 12 | // asynchronously using micro tasks. | 11 | 13 | // We use IIFE for the obj scope instead of {} to be compatible with | 12 | 14 | // non-V8 JS engines that do not support scoped variables. | @@ -25,7 +27,7 @@ for (let i = 0; i < 10; ++i) { | 25 | 27 | assert.strictEqual(test_finalizer.getFinalizerCallCount(), 1); | 26 | 28 |
| 27 | 29 | // The finalizer that access JS cannot run synchronously. They are run in the | 28 | | -// next JS loop tick. Thus, we must use common.gcUntil. | | 30 | +// next JS loop tick. Thus, we must use gcUntil. | 29 | 31 | async function runAsyncTests() { | 30 | 32 | // We do not use common.mustCall() because we want to see the finalizer | 31 | 33 | // called in response to GC and not as a part of env destruction. | @@ -36,8 +38,8 @@ async function runAsyncTests() { | 36 | 38 | const obj = {}; | 37 | 39 | test_finalizer.addFinalizerWithJS(obj, () => { js_is_called = true; }); | 38 | 40 | })(); | 39 | | - await common.gcUntil('ensure JS finalizer called', | 40 | | - () => (test_finalizer.getFinalizerCallCount() === 2)); | | 41 | + await gcUntil('ensure JS finalizer called', | | 42 | + () => (test_finalizer.getFinalizerCallCount() === 2)); | 41 | 43 | assert(js_is_called); | 42 | 44 | } | 43 | 45 | runAsyncTests(); |
|