1'use strict';
2const common = require('../common');
3const assert = require('assert');
4const child_process = require('child_process');
5
6// Test that workers fail with meaningful error message
7// when their initialization fails.
8
9if (common.isWindows) {
10  common.skip('ulimit does not work on Windows.');
11}
12
13if (process.config.variables.node_builtin_modules_path) {
14  common.skip('this test cannot pass when Node.js is built with --node-builtin-modules-path');
15}
16
17// A reasonably low fd count. An empty node process
18// creates around 30 fds for its internal purposes,
19// so making it too low will crash the process early,
20// making it too high will cause too much resource use.
21const OPENFILES = 128;
22
23// Double the open files - so that some workers fail for sure.
24const WORKERCOUNT = 256;
25
26if (process.argv[2] === 'child') {
27  const { Worker } = require('worker_threads');
28  for (let i = 0; i < WORKERCOUNT; ++i) {
29    const worker = new Worker(
30      'require(\'worker_threads\').parentPort.postMessage(2 + 2)',
31      { eval: true });
32    worker.on('message', (result) => {
33      assert.strictEqual(result, 4);
34    });
35
36    // We want to test that if there is an error in a constrained running
37    // environment, it will be one of `ENFILE`, `EMFILE`, 'ENOENT', or
38    // `ERR_WORKER_INIT_FAILED`.
39    const expected = ['ERR_WORKER_INIT_FAILED', 'EMFILE', 'ENFILE', 'ENOENT'];
40
41    // `common.mustCall*` cannot be used here as in some environments
42    // (i.e. single cpu) `ulimit` may not lead to such an error.
43    worker.on('error', (e) => {
44      assert.ok(expected.includes(e.code), `${e.code} not expected`);
45    });
46  }
47
48} else {
49  // Limit the number of open files, to force workers to fail.
50  let testCmd = `ulimit -n ${OPENFILES} && `;
51  testCmd += `${process.execPath} ${__filename} child`;
52  const cp = child_process.exec(testCmd);
53
54  // Turn on the child streams for debugging purposes.
55  let stdout = '';
56  cp.stdout.setEncoding('utf8');
57  cp.stdout.on('data', (chunk) => {
58    stdout += chunk;
59  });
60  let stderr = '';
61  cp.stderr.setEncoding('utf8');
62  cp.stderr.on('data', (chunk) => {
63    stderr += chunk;
64  });
65
66  cp.on('exit', common.mustCall((code, signal) => {
67    console.log(`child stdout: ${stdout}\n`);
68    console.log(`child stderr: ${stderr}\n`);
69    assert.strictEqual(code, 0);
70    assert.strictEqual(signal, null);
71  }));
72}
73