Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 20 additions & 19 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +130,9 @@
"@rollup/plugin-json": "^4.1.0",
"@rollup/plugin-multi-entry": "^4.0.1",
"@rollup/plugin-node-resolve": "^13.1.3",
"@test/esm-only-loader": "./test/compiler-fixtures/esm-only-loader",
"@types/node": "^22.15.3",
"@types/yargs": "^17.0.33",
"@test/esm-only-loader": "./test/compiler-fixtures/esm-only-loader",
"chai": "^4.3.4",
"coffeescript": "^2.6.1",
"cross-env": "^7.0.2",
Expand Down Expand Up @@ -160,8 +160,8 @@
"needle": "^2.5.0",
"npm-run-all2": "^6.2.0",
"nyc": "^15.1.0",
"pidtree": "^0.5.0",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Non-Actionable] It is kind of funny to me that pidtree's README.md mentions it exists because a previous project is unmaintained. And pidtree itself is now unmaintained, last commit 3 years ago.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the circle of life :)

"prettier": "^2.4.1",
"ps-list": "^9.0.0",
"remark": "^14.0.2",
"remark-github": "^11.2.2",
"remark-inline-links": "^6.0.1",
Expand Down
80 changes: 42 additions & 38 deletions test/integration/options/parallel.spec.js

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Praise] 👌 very clean in this file, nice!

Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,37 @@ const {
getSummary,
resolveFixturePath
} = require('../helpers');
const pidtree = require('pidtree');
const psList = require('ps-list').default;

const REPORTER_FIXTURE_PATH = resolveFixturePath('options/parallel/test-a');

/**
* Get child processes of a given PID using ps-list
* @param {number} pid - Parent process ID
* @param {Object} options - Options object
* @param {boolean} options.root - Include the parent PID in results
* @returns {Promise<number[]>} Array of child process PIDs
*/
async function getChildPids(pid) {
return (
(await psList())
// ppid = parent process ID
.filter(proc => proc.ppid === pid)
.map(proc => proc.pid)
);
}

/**
* Check if a process exists using ps-list
* @param {number} pid - Process ID to check
* @param {Object} options - Options object
* @param {boolean} options.root - Include the PID itself in results
* @returns {Promise<boolean>} Array with the PID if exists, null otherwise
*/
async function checkProcessExists(pid) {
return (await psList()).some(proc => proc.pid === pid);
}

/**
* Run a test fixture with the same reporter in both parallel and serial modes,
* returning both outputs for comparison
Expand Down Expand Up @@ -55,7 +82,7 @@ async function assertReporterOutputEquality(reporter) {
async function waitForChildPids(pid) {
let childPids = [];
while (!childPids.length) {
childPids = await pidtree(pid);
childPids = await getChildPids(pid);
await new Promise(resolve => setTimeout(resolve, 100));
}
return childPids;
Expand Down Expand Up @@ -475,27 +502,12 @@ describe('--parallel', function () {
});
});

// - `waitForChildPids` polls for created children
// - `await promise` waits for `invokeMochaAsync` to complete, which should
// kill all children
// - `checkProcessExists` validates that each child was killed
// - if any weren't killed, the test fails
describe('pool shutdown', function () {
// these are unusual and deserve some explanation. we start our mocha
// subprocess, and in parallel mode, that subprocess spawns more
// subprocesses. `invokeMochaAsync` returns a tuple of a `mocha`
// `ChildProcess` object and a `Promise` (which will resolve/reject when the
// subprocess finishes its test run). we use the `pid` from the `mocha`
// `ChildProcess` to ask `pidtree` (https://npm.im/pidtree) for the
// children, which are the worker processes. the `mocha` subprocess does
// _not_ immediately spawn worker processes, so we need to _poll_ for child
// processes. when we have them, we record them. once the `Promise`
// resolves, we then attempt to get pid information for our `mocha` process
// and _each_ worker process we retrieved earlier. if a process does not
// exist, `pidtree` will reject--this is what we _want_ to happen. we check
// each explicitly in case the child processes are somehow orphaned.
//
// we return `null` for each in the case of the expected rejection--if the
// `Promise.all()` call results in an array containing anything _except_ a
// bunch of `null`s, then this test fails, because one of the processes is
// still running. this behavior is dependent on `workerpool@6.0.2`, which
// added a guarantee that terminating the pool will _wait_ until all child
// processes have actually exited.
describe('during normal operation', function () {
it('should not leave orphaned processes around', async function () {
const [{pid}, promise] = invokeMochaAsync([
Expand All @@ -506,17 +518,13 @@ describe('--parallel', function () {
await promise;
return expect(
Promise.all(
[pid, ...childPids].map(async childPid => {
let pids = null;
try {
pids = await pidtree(childPid, {root: true});
} catch (ignored) {}
return pids;
})
[pid, ...childPids].map(
async childPid => await checkProcessExists(childPid)
)
Comment thread
mark-wiemer marked this conversation as resolved.
Resolved
),
'when fulfilled',
'to have items satisfying',
null
false
);
});
});
Expand All @@ -532,17 +540,13 @@ describe('--parallel', function () {
await promise;
return expect(
Promise.all(
[pid, ...childPids].map(async childPid => {
let pids = null;
try {
pids = await pidtree(childPid, {root: true});
} catch (ignored) {}
return pids;
})
[pid, ...childPids].map(
async childPid => await checkProcessExists(childPid)
)
),
'when fulfilled',
'to have items satisfying',
null
false
);
});
});
Expand Down