test: Make N-API weak-ref GC tests asynchronous

One of the N-API weak-reference test cases already had to be made
asynchronous to handle different behavior in a newer V8 version:
https://github.com/nodejs/node/pull/12864
When porting N-API to Node-ChakraCore, we found more of the test
cases needed similar treatment:
https://github.com/nodejs/node-chakracore/issues/246 So to make
thes tests more robust (and avoid having differences in the test code
for Node-ChakraCore), I am refactoring the tests in this file to
insert a `setImmedate()` callback before every call to `gc()` and
assertions about the effects of the GC.

PR-URL: https://github.com/nodejs/node/pull/13121
Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com>
This commit is contained in:
Jason Ginchereau 2017-05-18 15:29:49 -07:00
parent 43e4efdf21
commit bb91879f31

View File

@ -11,80 +11,110 @@ const test_reference = require(`./build/${common.buildType}/test_reference`);
// of a finalizer callback increments the finalizeCount property.
assert.strictEqual(test_reference.finalizeCount, 0);
{
// External value without a finalizer
let value = test_reference.createExternal();
assert.strictEqual(test_reference.finalizeCount, 0);
assert.strictEqual(typeof value, 'object');
test_reference.checkExternal(value);
value = null;
global.gc();
assert.strictEqual(test_reference.finalizeCount, 0);
// Run each test function in sequence,
// with an async delay and GC call between each.
function runTests(i, title, tests) {
if (tests[i]) {
if (typeof tests[i] === 'string') {
title = tests[i];
runTests(i + 1, title, tests);
} else {
try {
tests[i]();
} catch (e) {
console.error('Test failed: ' + title);
throw e;
}
setImmediate(() => {
global.gc();
runTests(i + 1, title, tests);
});
}
}
}
runTests(0, undefined, [
{
// External value with a finalizer
let value = test_reference.createExternalWithFinalize();
assert.strictEqual(test_reference.finalizeCount, 0);
assert.strictEqual(typeof value, 'object');
test_reference.checkExternal(value);
value = null;
global.gc();
assert.strictEqual(test_reference.finalizeCount, 1);
}
'External value without a finalizer',
() => {
const value = test_reference.createExternal();
assert.strictEqual(test_reference.finalizeCount, 0);
assert.strictEqual(typeof value, 'object');
test_reference.checkExternal(value);
},
() => {
assert.strictEqual(test_reference.finalizeCount, 0);
},
{
// Strong reference
let value = test_reference.createExternalWithFinalize();
assert.strictEqual(test_reference.finalizeCount, 0);
test_reference.createReference(value, 1);
assert.strictEqual(test_reference.referenceValue, value);
value = null;
global.gc(); // Value should NOT be GC'd because there is a strong ref
assert.strictEqual(test_reference.finalizeCount, 0);
test_reference.deleteReference();
global.gc(); // Value should be GC'd because the strong ref was deleted
assert.strictEqual(test_reference.finalizeCount, 1);
}
'External value with a finalizer',
() => {
const value = test_reference.createExternalWithFinalize();
assert.strictEqual(test_reference.finalizeCount, 0);
assert.strictEqual(typeof value, 'object');
test_reference.checkExternal(value);
},
() => {
assert.strictEqual(test_reference.finalizeCount, 1);
},
{
// Strong reference, increment then decrement to weak reference
let value = test_reference.createExternalWithFinalize();
assert.strictEqual(test_reference.finalizeCount, 0);
test_reference.createReference(value, 1);
value = null;
global.gc(); // Value should NOT be GC'd because there is a strong ref
assert.strictEqual(test_reference.finalizeCount, 0);
assert.strictEqual(test_reference.incrementRefcount(), 2);
global.gc(); // Value should NOT be GC'd because there is a strong ref
assert.strictEqual(test_reference.finalizeCount, 0);
assert.strictEqual(test_reference.decrementRefcount(), 1);
global.gc(); // Value should NOT be GC'd because there is a strong ref
assert.strictEqual(test_reference.finalizeCount, 0);
assert.strictEqual(test_reference.decrementRefcount(), 0);
global.gc(); // Value should be GC'd because the ref is now weak!
assert.strictEqual(test_reference.finalizeCount, 1);
test_reference.deleteReference();
global.gc(); // Value was already GC'd
assert.strictEqual(test_reference.finalizeCount, 1);
}
{
// Weak reference
let value = test_reference.createExternalWithFinalize();
assert.strictEqual(test_reference.finalizeCount, 0);
test_reference.createReference(value, 0);
assert.strictEqual(test_reference.referenceValue, value);
value = null;
setImmediate(common.mustCall(() => {
// This test only works if gc() is called from an immediate callback.
global.gc(); // Value should be GC'd because there is only a weak ref
'Weak reference',
() => {
const value = test_reference.createExternalWithFinalize();
assert.strictEqual(test_reference.finalizeCount, 0);
test_reference.createReference(value, 0);
assert.strictEqual(test_reference.referenceValue, value);
},
() => {
// Value should be GC'd because there is only a weak ref
assert.strictEqual(test_reference.referenceValue, undefined);
assert.strictEqual(test_reference.finalizeCount, 1);
test_reference.deleteReference();
}));
}
},
'Strong reference',
() => {
const value = test_reference.createExternalWithFinalize();
assert.strictEqual(test_reference.finalizeCount, 0);
test_reference.createReference(value, 1);
assert.strictEqual(test_reference.referenceValue, value);
},
() => {
// Value should NOT be GC'd because there is a strong ref
assert.strictEqual(test_reference.finalizeCount, 0);
test_reference.deleteReference();
},
() => {
// Value should be GC'd because the strong ref was deleted
assert.strictEqual(test_reference.finalizeCount, 1);
},
'Strong reference, increment then decrement to weak reference',
() => {
const value = test_reference.createExternalWithFinalize();
assert.strictEqual(test_reference.finalizeCount, 0);
test_reference.createReference(value, 1);
},
() => {
// Value should NOT be GC'd because there is a strong ref
assert.strictEqual(test_reference.finalizeCount, 0);
assert.strictEqual(test_reference.incrementRefcount(), 2);
},
() => {
// Value should NOT be GC'd because there is a strong ref
assert.strictEqual(test_reference.finalizeCount, 0);
assert.strictEqual(test_reference.decrementRefcount(), 1);
},
() => {
// Value should NOT be GC'd because there is a strong ref
assert.strictEqual(test_reference.finalizeCount, 0);
assert.strictEqual(test_reference.decrementRefcount(), 0);
},
() => {
// Value should be GC'd because the ref is now weak!
assert.strictEqual(test_reference.finalizeCount, 1);
test_reference.deleteReference();
},
() => {
// Value was already GC'd
assert.strictEqual(test_reference.finalizeCount, 1);
},
]);