Skip to content

Commit 10bea1c

Browse files
tannaltargos
authored andcommitted
test: merge ongc and gcutil into gc.js
PR-URL: #54355 Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com> Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
1 parent 2f5b98e commit 10bea1c

31 files changed

Lines changed: 119 additions & 99 deletions

‎test/addons/cppgc-object/test.js‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
// Flags: --expose-gc
44

55
constcommon=require('../../common');
6-
6+
const{ gcUntil }=require('../../common/gc');
77
// Verify that addons can create GarbageCollected objects and
88
// have them traced properly.
99

@@ -35,7 +35,7 @@ setTimeout(async function() {
3535
for(leti=0;i<count;++i){
3636
array[i]=newCppGCed();
3737
}
38-
awaitcommon.gcUntil(
38+
awaitgcUntil(
3939
'All old CppGCed are destroyed',
4040
()=>states[kDestructCount]===count,
4141
);
@@ -44,7 +44,7 @@ setTimeout(async function() {
4444
array=null;
4545
globalThis.gc();
4646

47-
awaitcommon.gcUntil(
47+
awaitgcUntil(
4848
'All old CppGCed are destroyed',
4949
()=>states[kDestructCount]===count*2,
5050
);

‎test/async-hooks/test-async-local-storage-gcable.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
constcommon=require('../common');
88
const{ AsyncLocalStorage }=require('async_hooks');
9-
constonGC=require('../common/ongc');
9+
const{onGC }=require('../common/gc');
1010

1111
letasyncLocalStorage=newAsyncLocalStorage();
1212

‎test/common/README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -982,7 +982,7 @@ module exports a single `onGC()` function.
982982

983983
```js
984984
require('../common');
985-
constonGC=require('../common/ongc');
985+
const{ onGC} =require('../common/gc');
986986

987987
onGC({}, { ongc() { console.log('collected'); } });
988988
```

‎test/common/gc.js‎

Lines changed: 67 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,72 @@
11
'use strict';
22

33
constwait=require('timers/promises').setTimeout;
4+
constassert=require('assert');
5+
constcommon=require('../common');
6+
constgcTrackerMap=newWeakMap();
7+
constgcTrackerTag='NODE_TEST_COMMON_GC_TRACKER';
48

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+
functiononGC(obj,gcListener){
18+
constasync_hooks=require('async_hooks');
19+
20+
constonGcAsyncHook=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,newasync_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+
functiongcUntil(name,condition){
48+
if(typeofname==='function'){
49+
condition=name;
50+
name=undefined;
51+
}
52+
returnnewPromise((resolve,reject)=>{
53+
letcount=0;
54+
functiongcAndCheck(){
55+
setImmediate(()=>{
56+
count++;
57+
global.gc();
58+
if(condition()){
59+
resolve();
60+
}elseif(count<10){
61+
gcAndCheck();
62+
}else{
63+
reject(name===undefined ? undefined : 'Test '+name+' failed');
64+
}
65+
});
66+
}
67+
gcAndCheck();
68+
});
69+
}
770

871
// This function can be used to check if an object factor leaks or not,
972
// but it needs to be used with care:
@@ -124,4 +187,6 @@ module.exports = {
124187
checkIfCollectable,
125188
runAndBreathe,
126189
checkIfCollectableByCounting,
190+
onGC,
191+
gcUntil,
127192
};

‎test/common/index.js‎

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -837,30 +837,6 @@ function skipIfDumbTerminal() {
837837
}
838838
}
839839

840-
functiongcUntil(name,condition){
841-
if(typeofname==='function'){
842-
condition=name;
843-
name=undefined;
844-
}
845-
returnnewPromise((resolve,reject)=>{
846-
letcount=0;
847-
functiongcAndCheck(){
848-
setImmediate(()=>{
849-
count++;
850-
global.gc();
851-
if(condition()){
852-
resolve();
853-
}elseif(count<10){
854-
gcAndCheck();
855-
}else{
856-
reject(name===undefined ? undefined : 'Test '+name+' failed');
857-
}
858-
});
859-
}
860-
gcAndCheck();
861-
});
862-
}
863-
864840
functionrequireNoPackageJSONAbove(dir=__dirname){
865841
letpossiblePackage=path.join(dir,'..','package.json');
866842
letlastPackage=null;
@@ -966,7 +942,6 @@ const common = {
966942
expectsError,
967943
expectRequiredModule,
968944
expectWarning,
969-
gcUntil,
970945
getArrayBufferViews,
971946
getBufferSources,
972947
getCallSite,

‎test/common/ongc.js‎

Lines changed: 0 additions & 32 deletions
This file was deleted.

‎test/js-native-api/6_object_wrap/test-object-wrap-ref.js‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@
33
'use strict';
44
constcommon=require('../../common');
55
constaddon=require(`./build/${common.buildType}/6_object_wrap`);
6+
const{ gcUntil }=require('../../common/gc');
67

78
(functionscope(){
89
addon.objectWrapDanglingReference({});
910
})();
1011

11-
common.gcUntil('object-wrap-ref',()=>{
12+
gcUntil('object-wrap-ref',()=>{
1213
returnaddon.objectWrapDanglingReferenceTest();
1314
});

‎test/js-native-api/7_factory_wrap/test.js‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
constcommon=require('../../common');
55
constassert=require('assert');
66
consttest=require(`./build/${common.buildType}/7_factory_wrap`);
7+
const{ gcUntil }=require('../../common/gc');
78

89
assert.strictEqual(test.finalizeCount,0);
910
asyncfunctionrunGCTests(){
@@ -13,14 +14,14 @@ async function runGCTests() {
1314
assert.strictEqual(obj.plusOne(),12);
1415
assert.strictEqual(obj.plusOne(),13);
1516
})();
16-
awaitcommon.gcUntil('test 1',()=>(test.finalizeCount===1));
17+
awaitgcUntil('test 1',()=>(test.finalizeCount===1));
1718

1819
(()=>{
1920
constobj2=test.createObject(20);
2021
assert.strictEqual(obj2.plusOne(),21);
2122
assert.strictEqual(obj2.plusOne(),22);
2223
assert.strictEqual(obj2.plusOne(),23);
2324
})();
24-
awaitcommon.gcUntil('test 2',()=>(test.finalizeCount===2));
25+
awaitgcUntil('test 2',()=>(test.finalizeCount===2));
2526
}
2627
runGCTests();

‎test/js-native-api/8_passing_wrapped/test.js‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
constcommon=require('../../common');
55
constassert=require('assert');
66
constaddon=require(`./build/${common.buildType}/8_passing_wrapped`);
7+
const{ gcUntil }=require('../../common/gc');
78

89
asyncfunctionrunTest(){
910
letobj1=addon.createObject(10);
@@ -14,7 +15,7 @@ async function runTest() {
1415
// Make sure the native destructor gets called.
1516
obj1=null;
1617
obj2=null;
17-
awaitcommon.gcUntil('8_passing_wrapped',
18-
()=>(addon.finalizeCount()===2));
18+
awaitgcUntil('8_passing_wrapped',
19+
()=>(addon.finalizeCount()===2));
1920
}
2021
runTest();

‎test/js-native-api/test_finalizer/test.js‎

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@ const common = require('../../common');
55
consttest_finalizer=require(`./build/${common.buildType}/test_finalizer`);
66
constassert=require('assert');
77

8+
const{ gcUntil }=require('../../common/gc');
9+
810
// 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
1012
// asynchronously using micro tasks.
1113
// We use IIFE for the obj scope instead of {} to be compatible with
1214
// non-V8 JS engines that do not support scoped variables.
@@ -25,7 +27,7 @@ for (let i = 0; i < 10; ++i) {
2527
assert.strictEqual(test_finalizer.getFinalizerCallCount(),1);
2628

2729
// 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.
2931
asyncfunctionrunAsyncTests(){
3032
// We do not use common.mustCall() because we want to see the finalizer
3133
// called in response to GC and not as a part of env destruction.
@@ -36,8 +38,8 @@ async function runAsyncTests() {
3638
constobj={};
3739
test_finalizer.addFinalizerWithJS(obj,()=>{js_is_called=true;});
3840
})();
39-
awaitcommon.gcUntil('ensure JS finalizer called',
40-
()=>(test_finalizer.getFinalizerCallCount()===2));
41+
awaitgcUntil('ensure JS finalizer called',
42+
()=>(test_finalizer.getFinalizerCallCount()===2));
4143
assert(js_is_called);
4244
}
4345
runAsyncTests();

0 commit comments

Comments
 (0)