test: make WeakReference tests robust

Previously we assume that the objects are GC'ed after one
global.gc() returns, which is not necessarily always the case. Use
gcUntil() to run GC multiple times if they are not GC'ed in the
first time around.

PR-URL: https://github.com/nodejs/node/pull/49053
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
This commit is contained in:
Joyee Cheung 2023-08-07 16:24:06 +02:00
parent 72151769b8
commit c64c9149ad
3 changed files with 37 additions and 15 deletions

View File

@ -5,16 +5,27 @@ const { WeakReference } = internalBinding('util');
const {
setDeserializeMainFunction
} = require('v8').startupSnapshot
const assert = require('assert');
let obj = { hello: 'world' };
const ref = new WeakReference(obj);
let gcCount = 0;
let maxGC = 10;
function run() {
globalThis.gc();
setImmediate(() => {
gcCount++;
if (ref.get() === undefined) {
return;
} else if (gcCount < maxGC) {
run();
} else {
throw new Error(`Reference is still around after ${maxGC} GC`);
}
});
}
setDeserializeMainFunction(() => {
obj = null;
globalThis.gc();
setImmediate(() => {
assert.strictEqual(ref.get(), undefined);
});
run();
});

View File

@ -13,6 +13,8 @@ const isEnumerable = Function.call.bind(Object.prototype.propertyIsEnumerable);
// See: https://github.com/nodejs/node/issues/23862
let d = domain.create();
let resourceGCed = false; let domainGCed = false; let
emitterGCed = false;
d.run(() => {
const resource = new async_hooks.AsyncResource('TestResource');
const emitter = new EventEmitter();
@ -30,10 +32,17 @@ d.run(() => {
// emitter → resource → async id ⇒ domain → emitter.
// Make sure that all of these objects are released:
onGC(resource, { ongc: common.mustCall() });
onGC(d, { ongc: common.mustCall() });
onGC(emitter, { ongc: common.mustCall() });
onGC(resource, { ongc: common.mustCall(() => { resourceGCed = true; }) });
onGC(d, { ongc: common.mustCall(() => { domainGCed = true; }) });
onGC(emitter, { ongc: common.mustCall(() => { emitterGCed = true; }) });
});
d = null;
global.gc();
async function main() {
await common.gcUntil(
'All objects garbage collected',
() => resourceGCed && domainGCed && emitterGCed);
}
main();

View File

@ -1,6 +1,6 @@
// Flags: --expose-internals --expose-gc
'use strict';
require('../common');
const common = require('../common');
const assert = require('assert');
const { internalBinding } = require('internal/test/binding');
const { WeakReference } = internalBinding('util');
@ -9,9 +9,11 @@ let obj = { hello: 'world' };
const ref = new WeakReference(obj);
assert.strictEqual(ref.get(), obj);
setImmediate(() => {
async function main() {
obj = null;
global.gc();
await common.gcUntil(
'Reference is garbage collected',
() => ref.get() === undefined);
}
assert.strictEqual(ref.get(), undefined);
});
main();