如何在摩卡中执行多个流程测试?

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.