如何在摩卡中执行多个流程测试?
How to execute many process tests in Mocha?
我有一个包含约 70 个可执行文件测试的回购协议。当 运行 在 mocha or jest 下时,它通常会在前几个承诺中出错,要么是因为超时,要么是因为 stdout 从未返回到父进程。
我对这个问题的最小复制涉及 100 个线程,每个线程调用一个休眠 10 秒的命令行:
let child_process = require('child_process');
let AllTests = [];
/* start processes */
for (let i = 0; i < 100; ++i) {
AllTests.push({
i: i,
start: new Date(),
exec: new Promise((resolve, reject) => {
let program = child_process.spawn(
'node', ['-e', 'setTimeout(() => { process.exit(0); }, 9999)'])
// 'node', ['-e', 'for (let i = 0; i < 2**28; ++i) ;'])
program.on('exit', exitCode => { resolve({exitCode:exitCode}) })
program.on('error', err => { reject(err) })
})
})
}
/* test results */
describe('churn', () => {
AllTests.forEach(test => {
it('should execute test ' + test.i + '.',
done => {
test.exec.then(exec => {
test.end = new Date()
done()
})
})
})
})
在我动力不足的笔记本电脑上,我通常得到:
93 passing (19s)
7 failing
1) churn
should execute test 0.:
Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves. (/home/eric/errz/flood.js)
...
之后添加一些会计:
after(() => {
console.log()
AllTests.forEach(test => {
console.log(test.i, (test.end - test.start)/1000.0)
})
})
显示每个进程需要 ~19s。
鉴于Mocha和Jest出现这种情况,我猜测问题与100个并发进程有关。建议?
我几乎可以分别解决超时和 stdio 流问题。
当我将进程终止的退出处理程序推入下一个事件周期时,流问题大部分得到解决:
program.on("exit", function(exitCode) {
setTimeout(
() => resolve({stdout:stdout, stderr:stderr, exitCode:exitCode}), 0
)
});
program.on("error", function(err) { reject(err); });
超时是因为我正在淹没进程 table。
我没有过于熟悉内核的调度程序,而是使用了 timeout-promise-queue,它限制了并发进程的总数,并根据每个排队进程的启动时间提供了超时。
使用 timeout-promise-queue 还解决了恶意流问题,该问题仅在进程 table 变得太大时才会出现。
经过数千次测试,我确定了 25 个进程队列和 0 长度的退出处理程序超时。
resulting diffs are pretty minimal and self-explanatory and I no longer have to hit [↻Restart job] on Travis tests.
我有一个包含约 70 个可执行文件测试的回购协议。当 运行 在 mocha or jest 下时,它通常会在前几个承诺中出错,要么是因为超时,要么是因为 stdout 从未返回到父进程。
我对这个问题的最小复制涉及 100 个线程,每个线程调用一个休眠 10 秒的命令行:
let child_process = require('child_process');
let AllTests = [];
/* start processes */
for (let i = 0; i < 100; ++i) {
AllTests.push({
i: i,
start: new Date(),
exec: new Promise((resolve, reject) => {
let program = child_process.spawn(
'node', ['-e', 'setTimeout(() => { process.exit(0); }, 9999)'])
// 'node', ['-e', 'for (let i = 0; i < 2**28; ++i) ;'])
program.on('exit', exitCode => { resolve({exitCode:exitCode}) })
program.on('error', err => { reject(err) })
})
})
}
/* test results */
describe('churn', () => {
AllTests.forEach(test => {
it('should execute test ' + test.i + '.',
done => {
test.exec.then(exec => {
test.end = new Date()
done()
})
})
})
})
在我动力不足的笔记本电脑上,我通常得到:
93 passing (19s)
7 failing
1) churn
should execute test 0.:
Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves. (/home/eric/errz/flood.js)
...
之后添加一些会计:
after(() => {
console.log()
AllTests.forEach(test => {
console.log(test.i, (test.end - test.start)/1000.0)
})
})
显示每个进程需要 ~19s。
鉴于Mocha和Jest出现这种情况,我猜测问题与100个并发进程有关。建议?
我几乎可以分别解决超时和 stdio 流问题。 当我将进程终止的退出处理程序推入下一个事件周期时,流问题大部分得到解决:
program.on("exit", function(exitCode) {
setTimeout(
() => resolve({stdout:stdout, stderr:stderr, exitCode:exitCode}), 0
)
});
program.on("error", function(err) { reject(err); });
超时是因为我正在淹没进程 table。 我没有过于熟悉内核的调度程序,而是使用了 timeout-promise-queue,它限制了并发进程的总数,并根据每个排队进程的启动时间提供了超时。
使用 timeout-promise-queue 还解决了恶意流问题,该问题仅在进程 table 变得太大时才会出现。 经过数千次测试,我确定了 25 个进程队列和 0 长度的退出处理程序超时。
resulting diffs are pretty minimal and self-explanatory and I no longer have to hit [↻Restart job] on Travis tests.