test: improve async-hooks/test-callback-error

PR-URL: https://github.com/nodejs/node/pull/13559
Fixes: https://github.com/nodejs/node/issues/13527
Reviewed-By: Andreas Madsen <amwebdk@gmail.com>
This commit is contained in:
Refael Ackermann 2017-06-08 16:48:08 -04:00
parent 1c314f5fac
commit 32c7f114c5
2 changed files with 119 additions and 34 deletions

View File

@ -0,0 +1,21 @@
prefix async-hooks
# To mark a test as flaky, list the test name in the appropriate section
# below, without ".js", followed by ": PASS,FLAKY". Example:
# sample-test : PASS,FLAKY
[true] # This section applies to all platforms
[$system==win32]
[$system==linux]
test-callback-error : PASS,FLAKY
[$system==macos]
test-callback-error : PASS,FLAKY
[$arch==arm || $arch==arm64]
[$system==solaris] # Also applies to SmartOS
[$system==freebsd]

View File

@ -1,56 +1,120 @@
'use strict'; 'use strict';
const common = require('../common'); const common = require('../common');
const assert = require('assert'); const assert = require('assert');
const spawnSync = require('child_process').spawnSync; const { spawnSync, fork } = require('child_process');
const async_hooks = require('async_hooks'); const async_hooks = require('async_hooks');
const initHooks = require('./init-hooks'); const initHooks = require('./init-hooks');
switch (process.argv[2]) { const arg = process.argv[2];
switch (arg) {
case 'test_init_callback': case 'test_init_callback':
initHooks({ initHooks({
oninit: common.mustCall(() => { throw new Error('test_init_callback'); }) oninit: common.mustCall(() => { throw new Error(arg); })
}).enable(); }).enable();
async_hooks.emitInit(
async_hooks.executionAsyncId(),
`${arg}_type`,
async_hooks.triggerAsyncId()
);
return;
async_hooks.emitInit(async_hooks.executionAsyncId(),
'test_init_callback_type',
async_hooks.triggerAsyncId());
break;
case 'test_callback': case 'test_callback':
initHooks({ initHooks({
onbefore: common.mustCall(() => { throw new Error('test_callback'); }) onbefore: common.mustCall(() => { throw new Error(arg); })
}).enable(); }).enable();
async_hooks.emitInit(
async_hooks.emitInit(async_hooks.executionAsyncId(), 'test_callback_type', async_hooks.executionAsyncId(),
async_hooks.triggerAsyncId()); `${arg}_type`,
async_hooks.triggerAsyncId()
);
async_hooks.emitBefore(async_hooks.executionAsyncId()); async_hooks.emitBefore(async_hooks.executionAsyncId());
break; return;
case 'test_callback_abort': case 'test_callback_abort':
initHooks({ initHooks({
oninit: common.mustCall(() => { throw new Error('test_callback_abort'); }) oninit: common.mustCall(() => { throw new Error(arg); })
}).enable(); }).enable();
async_hooks.emitInit(
async_hooks.emitInit(async_hooks.executionAsyncId(), 'test_callback_abort', async_hooks.executionAsyncId(),
async_hooks.triggerAsyncId()); `${arg}_type`,
break; async_hooks.triggerAsyncId()
);
return;
} }
const c1 = spawnSync(`${process.execPath}`, [__filename, 'test_init_callback']); // this part should run only for the master test
assert.strictEqual(c1.stderr.toString().split('\n')[0], assert.ok(!arg);
'Error: test_init_callback'); {
assert.strictEqual(c1.status, 1); // console.log should stay until this test's flakiness is solved
console.log('start case 1');
console.time('end case 1');
const child = spawnSync(process.execPath, [__filename, 'test_init_callback']);
assert.ifError(child.error);
const test_init_first_line = child.stderr.toString().split(/[\r\n]+/g)[0];
assert.strictEqual(test_init_first_line, 'Error: test_init_callback');
assert.strictEqual(child.status, 1);
console.timeEnd('end case 1');
}
const c2 = spawnSync(`${process.execPath}`, [__filename, 'test_callback']); {
assert.strictEqual(c2.stderr.toString().split('\n')[0], 'Error: test_callback'); console.log('start case 2');
assert.strictEqual(c2.status, 1); console.time('end case 2');
const child = spawnSync(process.execPath, [__filename, 'test_callback']);
assert.ifError(child.error);
const test_callback_first_line = child.stderr.toString().split(/[\r\n]+/g)[0];
assert.strictEqual(test_callback_first_line, 'Error: test_callback');
assert.strictEqual(child.status, 1);
console.timeEnd('end case 2');
}
const c3 = spawnSync(`${process.execPath}`, ['--abort-on-uncaught-exception', {
__filename, console.log('start case 3');
'test_callback_abort']); console.time('end case 3');
assert.strictEqual(c3.stdout.toString(), ''); // Timeout is set because this case is known to be problematic, so stderr is
// logged for further analysis.
// Ref: https://github.com/nodejs/node/issues/13527
// Ref: https://github.com/nodejs/node/pull/13559
const opts = {
execArgv: ['--abort-on-uncaught-exception'],
silent: true
};
const child = fork(__filename, ['test_callback_abort'], opts);
const stderrOutput = c3.stderr.toString() let stdout = '';
.trim() child.stdout.on('data', (data) => {
.split('\n') stdout += data;
.map((s) => s.trim()); });
assert.strictEqual(stderrOutput[0], 'Error: test_callback_abort');
let stderr = '';
child.stderr.on('data', (data) => {
stderr += data;
});
const tO = setTimeout(() => {
console.log(stderr);
child.kill('SIGKILL');
process.exit(1);
}, 15 * 1000);
tO.unref();
child.on('close', (code, signal) => {
clearTimeout(tO);
if (common.isWindows) {
assert.strictEqual(code, 3);
assert.strictEqual(signal, null);
} else {
assert.strictEqual(code, null);
// most posix systems will show 'SIGABRT', but alpine34 does not
if (signal !== 'SIGABRT') {
console.log(`parent recived signal ${signal}\nchild's stderr:`);
console.log(stderr);
process.exit(1);
}
assert.strictEqual(signal, 'SIGABRT');
}
assert.strictEqual(stdout, '');
const firstLineStderr = stderr.split(/[\r\n]+/g)[0].trim();
assert.strictEqual(firstLineStderr, 'Error: test_callback_abort');
});
console.timeEnd('end case 3');
}