From 8653a1bad4bea81504bf49f8c36d25831e6587e4 Mon Sep 17 00:00:00 2001 From: Jason Ginchereau Date: Thu, 18 May 2017 15:29:49 -0700 Subject: [PATCH] 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 --- test/addons-napi/test_reference/test.js | 168 ++++++++++++++---------- 1 file changed, 99 insertions(+), 69 deletions(-) diff --git a/test/addons-napi/test_reference/test.js b/test/addons-napi/test_reference/test.js index 30effe7eec0922..aaf5531f39e1f3 100644 --- a/test/addons-napi/test_reference/test.js +++ b/test/addons-napi/test_reference/test.js @@ -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); -} - -{ - // 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); -} - -{ - // 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); + '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); + }, - 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); + '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); + }, - 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); + '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(); + }, - test_reference.deleteReference(); - global.gc(); // Value was already GC'd - assert.strictEqual(test_reference.finalizeCount, 1); -} + '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); + }, -{ - // 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 - assert.strictEqual(test_reference.referenceValue, undefined); + '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); + }, +]);