Skip to content

Commit

Permalink
Make tests work on all Node versions
Browse files Browse the repository at this point in the history
 - Make GC tests (arraybuffer, buffer, external) async, to account for
   different GC behavior with different versions of V8 and ChakraCore,
   similar to nodejs/node#13121
 - In test/index.js, use the --napi-modules and --expose-gc
   command-line flags automatically
  • Loading branch information
jasongin committed May 21, 2017
1 parent 16fc9a5 commit debda2e
Show file tree
Hide file tree
Showing 9 changed files with 198 additions and 92 deletions.
8 changes: 3 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@
],
"dependencies": {},
"description": "Node.js API (N-API)",
"devDependencies": {
"node-gyp": "^3.6.0"
},
"devDependencies": {},
"directories": {},
"homepage": "https://github.com/nodejs/node-addon-api",
"license": "MIT",
Expand All @@ -31,7 +29,7 @@
},
"scripts": {
"pretest": "node-gyp rebuild -C test",
"test": "node --expose-gc test"
"test": "node test"
},
"version": "0.2.0"
"version": "0.2.1"
}
6 changes: 6 additions & 0 deletions test/arraybuffer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ Value CreateBuffer(const CallbackInfo& info) {
}

Value CreateExternalBuffer(const CallbackInfo& info) {
finalizeCount = 0;

ArrayBuffer buffer = ArrayBuffer::New(info.Env(), testData, testLength);

if (buffer.ByteLength() != testLength) {
Expand All @@ -50,6 +52,8 @@ Value CreateExternalBuffer(const CallbackInfo& info) {
}

Value CreateExternalBufferWithFinalize(const CallbackInfo& info) {
finalizeCount = 0;

uint8_t* data = new uint8_t[testLength];

ArrayBuffer buffer = ArrayBuffer::New(
Expand All @@ -74,6 +78,8 @@ Value CreateExternalBufferWithFinalize(const CallbackInfo& info) {
}

Value CreateExternalBufferWithFinalizeHint(const CallbackInfo& info) {
finalizeCount = 0;

uint8_t* data = new uint8_t[testLength];

char* hint = nullptr;
Expand Down
66 changes: 44 additions & 22 deletions test/arraybuffer.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,52 @@
const buildType = process.config.target_defaults.default_configuration;
const binding = require(`./build/${buildType}/binding.node`);
const assert = require('assert');
const testUtil = require('./testUtil');

let test = binding.arraybuffer.createBuffer();
binding.arraybuffer.checkBuffer(test);
assert.ok(test instanceof ArrayBuffer);
testUtil.runGCTests([
'Internal ArrayBuffer',
() => {
const test = binding.arraybuffer.createBuffer();
binding.arraybuffer.checkBuffer(test);
assert.ok(test instanceof ArrayBuffer);

let test2 = test.slice(0);
binding.arraybuffer.checkBuffer(test2);
const test2 = test.slice(0);
binding.arraybuffer.checkBuffer(test2);
},

test = binding.arraybuffer.createExternalBuffer();
binding.arraybuffer.checkBuffer(test);
assert.ok(test instanceof ArrayBuffer);
'External ArrayBuffer',
() => {
const test = binding.arraybuffer.createExternalBuffer();
binding.arraybuffer.checkBuffer(test);
assert.ok(test instanceof ArrayBuffer);
assert.strictEqual(0, binding.arraybuffer.getFinalizeCount());
},
() => {
global.gc();
assert.strictEqual(0, binding.arraybuffer.getFinalizeCount());
},

test = binding.arraybuffer.createExternalBufferWithFinalize();
binding.arraybuffer.checkBuffer(test);
assert.ok(test instanceof ArrayBuffer);
assert.strictEqual(0, binding.arraybuffer.getFinalizeCount());
test = null;
global.gc();
assert.strictEqual(1, binding.arraybuffer.getFinalizeCount());
'External ArrayBuffer with finalizer',
() => {
const test = binding.arraybuffer.createExternalBufferWithFinalize();
binding.arraybuffer.checkBuffer(test);
assert.ok(test instanceof ArrayBuffer);
assert.strictEqual(0, binding.arraybuffer.getFinalizeCount());
},
() => {
global.gc();
assert.strictEqual(1, binding.arraybuffer.getFinalizeCount());
},

test = binding.arraybuffer.createExternalBufferWithFinalizeHint();
binding.arraybuffer.checkBuffer(test);
assert.ok(test instanceof ArrayBuffer);
assert.strictEqual(1, binding.arraybuffer.getFinalizeCount());
test = null;
global.gc();
assert.strictEqual(2, binding.arraybuffer.getFinalizeCount());
'External ArrayBuffer with finalizer hint',
() => {
const test = binding.arraybuffer.createExternalBufferWithFinalizeHint();
binding.arraybuffer.checkBuffer(test);
assert.ok(test instanceof ArrayBuffer);
assert.strictEqual(0, binding.arraybuffer.getFinalizeCount());
},
() => {
global.gc();
assert.strictEqual(1, binding.arraybuffer.getFinalizeCount());
},
]);
6 changes: 6 additions & 0 deletions test/buffer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ Value CreateBuffer(const CallbackInfo& info) {
}

Value CreateExternalBuffer(const CallbackInfo& info) {
finalizeCount = 0;

Buffer<uint16_t> buffer = Buffer<uint16_t>::New(
info.Env(),
testData,
Expand All @@ -55,6 +57,8 @@ Value CreateExternalBuffer(const CallbackInfo& info) {
}

Value CreateExternalBufferWithFinalize(const CallbackInfo& info) {
finalizeCount = 0;

uint16_t* data = new uint16_t[testLength];

Buffer<uint16_t> buffer = Buffer<uint16_t>::New(
Expand All @@ -79,6 +83,8 @@ Value CreateExternalBufferWithFinalize(const CallbackInfo& info) {
}

Value CreateExternalBufferWithFinalizeHint(const CallbackInfo& info) {
finalizeCount = 0;

uint16_t* data = new uint16_t[testLength];

char* hint = nullptr;
Expand Down
77 changes: 51 additions & 26 deletions test/buffer.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,60 @@
const buildType = process.config.target_defaults.default_configuration;
const binding = require(`./build/${buildType}/binding.node`);
const assert = require('assert');
const testUtil = require('./testUtil');

let test = binding.buffer.createBuffer();
binding.buffer.checkBuffer(test);
assert.ok(test instanceof Buffer);
testUtil.runGCTests([
'Internal Buffer',
() => {
const test = binding.buffer.createBuffer();
binding.buffer.checkBuffer(test);
assert.ok(test instanceof Buffer);

let test2 = Buffer.alloc(test.length);
test.copy(test2);
binding.buffer.checkBuffer(test2);
const test2 = Buffer.alloc(test.length);
test.copy(test2);
binding.buffer.checkBuffer(test2);
},

test = binding.buffer.createBufferCopy();
binding.buffer.checkBuffer(test);
assert.ok(test instanceof Buffer);
'Buffer copy',
() => {
const test = binding.buffer.createBufferCopy();
binding.buffer.checkBuffer(test);
assert.ok(test instanceof Buffer);
},

test = binding.buffer.createExternalBuffer();
binding.buffer.checkBuffer(test);
assert.ok(test instanceof Buffer);
'External Buffer',
() => {
const test = binding.buffer.createExternalBuffer();
binding.buffer.checkBuffer(test);
assert.ok(test instanceof Buffer);
assert.strictEqual(0, binding.buffer.getFinalizeCount());
},
() => {
global.gc();
assert.strictEqual(0, binding.buffer.getFinalizeCount());
},

test = binding.buffer.createExternalBufferWithFinalize();
binding.buffer.checkBuffer(test);
assert.ok(test instanceof Buffer);
assert.strictEqual(0, binding.buffer.getFinalizeCount());
test = null;
global.gc();
assert.strictEqual(1, binding.buffer.getFinalizeCount());
'External Buffer with finalizer',
() => {
const test = binding.buffer.createExternalBufferWithFinalize();
binding.buffer.checkBuffer(test);
assert.ok(test instanceof Buffer);
assert.strictEqual(0, binding.buffer.getFinalizeCount());
},
() => {
global.gc();
assert.strictEqual(1, binding.buffer.getFinalizeCount());
},

test = binding.buffer.createExternalBufferWithFinalizeHint();
binding.buffer.checkBuffer(test);
assert.ok(test instanceof Buffer);
assert.strictEqual(1, binding.buffer.getFinalizeCount());
test = null;
global.gc();
assert.strictEqual(2, binding.buffer.getFinalizeCount());
'External Buffer with finalizer hint',
() => {
const test = binding.buffer.createExternalBufferWithFinalizeHint();
binding.buffer.checkBuffer(test);
assert.ok(test instanceof Buffer);
assert.strictEqual(0, binding.buffer.getFinalizeCount());
},
() => {
global.gc();
assert.strictEqual(1, binding.buffer.getFinalizeCount());
},
]);
3 changes: 3 additions & 0 deletions test/external.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@ int testData = 1;
int finalizeCount = 0;

Value CreateExternal(const CallbackInfo& info) {
finalizeCount = 0;
return External<int>::New(info.Env(), &testData);
}

Value CreateExternalWithFinalize(const CallbackInfo& info) {
finalizeCount = 0;
return External<int>::New(info.Env(), new int(1),
[](Env env, int* data) {
delete data;
Expand All @@ -20,6 +22,7 @@ Value CreateExternalWithFinalize(const CallbackInfo& info) {
}

Value CreateExternalWithFinalizeHint(const CallbackInfo& info) {
finalizeCount = 0;
char* hint = nullptr;
return External<int>::New(info.Env(), new int(1),
[](Env env, int* data, char* hint) {
Expand Down
53 changes: 33 additions & 20 deletions test/external.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,39 @@
const buildType = process.config.target_defaults.default_configuration;
const binding = require(`./build/${buildType}/binding.node`);
const assert = require('assert');
const testUtil = require('./testUtil');

assert.strictEqual(0, binding.external.getFinalizeCount());
testUtil.runGCTests([
'External without finalizer',
() => {
const test = binding.external.createExternal();
assert.strictEqual(typeof test, 'object');
binding.external.checkExternal(test);
assert.strictEqual(0, binding.external.getFinalizeCount());
},
() => {
assert.strictEqual(0, binding.external.getFinalizeCount());
},

let test = binding.external.createExternal();
assert.strictEqual(typeof test, 'object');
binding.external.checkExternal(test);
test = null;
global.gc();
assert.strictEqual(0, binding.external.getFinalizeCount());
'External with finalizer',
() => {
const test = binding.external.createExternalWithFinalize();
assert.strictEqual(typeof test, 'object');
binding.external.checkExternal(test);
assert.strictEqual(0, binding.external.getFinalizeCount());
},
() => {
assert.strictEqual(1, binding.external.getFinalizeCount());
},

test = binding.external.createExternalWithFinalize();
assert.strictEqual(typeof test, 'object');
binding.external.checkExternal(test);
test = null;
global.gc();
assert.strictEqual(1, binding.external.getFinalizeCount());

test = binding.external.createExternalWithFinalizeHint();
assert.strictEqual(typeof test, 'object');
binding.external.checkExternal(test);
test = null;
global.gc();
assert.strictEqual(2, binding.external.getFinalizeCount());
'External with finalizer hint',
() => {
const test = binding.external.createExternalWithFinalizeHint();
assert.strictEqual(typeof test, 'object');
binding.external.checkExternal(test);
assert.strictEqual(0, binding.external.getFinalizeCount());
},
() => {
assert.strictEqual(1, binding.external.getFinalizeCount());
},
]);
42 changes: 23 additions & 19 deletions test/index.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,28 @@
'use strict';

if (typeof global.gc !== 'function') {
throw new Error('Tests require --expose-gc flag.')
}

let testModules = [
'arraybuffer',
'asyncworker',
'buffer',
'error',
'external',
'function',
'name',
'arraybuffer',
'asyncworker',
'buffer',
'error',
'external',
'function',
'name',
];

testModules.forEach(name => {
try {
require('./' + name);
}
catch (e) {
console.error(e);
}
});
if (typeof global.gc === 'function') {
// Requiring each module runs tests in the module.
testModules.forEach(name => {
require('./' + name);
});
} else {
// Make it easier to run with the correct (version-dependent) command-line args.
const args = [ '--expose-gc', __filename ];
if (require('../index').isNodeApiBuiltin) {
args.splice(0, 0, '--napi-modules');
}
const child = require('child_process').spawnSync(process.argv[0], args, {
stdio: 'inherit',
});
process.exitCode = child.status;
}
29 changes: 29 additions & 0 deletions test/testUtil.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Run each test function in sequence,
// with an async delay and GC call between each.
function runGCTests(tests, i, title) {
if (!i) {
i = 0;
}

if (tests[i]) {
if (typeof tests[i] === 'string') {
title = tests[i];
runGCTests(tests, i + 1, title);
} else {
try {
tests[i]();
} catch (e) {
console.error('Test failed: ' + title);
throw e;
}
setImmediate(() => {
global.gc();
runGCTests(tests, i + 1, title);
});
}
}
}

module.exports = {
runGCTests,
};

0 comments on commit debda2e

Please sign in to comment.