mirror of
https://github.com/serverless/serverless.git
synced 2025-12-08 19:46:03 +00:00
115 lines
3.5 KiB
JavaScript
Executable File
115 lines
3.5 KiB
JavaScript
Executable File
#!/usr/bin/env node
|
|
|
|
// Basic isolated tests runner
|
|
// Ensures each test file is run in distinct process and does not interfere with other test runs.
|
|
// To be used to confirm test files do not introduce and work by chance of side effects
|
|
// Temporary solution until we migrate to runner which provides that (reliably) on its own
|
|
|
|
'use strict';
|
|
|
|
process.on('unhandledRejection', err => {
|
|
throw err;
|
|
});
|
|
|
|
const globby = require('globby');
|
|
const spawn = require('child-process-ext/spawn');
|
|
const chalk = require('chalk');
|
|
const pLimit = require('p-limit');
|
|
|
|
const shouldApplyFsCleanupCheck = (() => {
|
|
const argIndex = process.argv.indexOf('--skip-fs-cleanup-check');
|
|
if (argIndex === -1) return true;
|
|
process.argv.splice(argIndex, 1);
|
|
return false;
|
|
})();
|
|
|
|
const patterns = process.argv.length <= 2 ? ['**/*.test.js'] : process.argv.slice(2);
|
|
patterns.push('!node_modules/**');
|
|
|
|
const resolveGitStatus = () =>
|
|
spawn('git', ['status', '--porcelain']).then(
|
|
({ stdoutBuffer }) => String(stdoutBuffer),
|
|
error => {
|
|
process.stdout.write(error.stdoutBuffer);
|
|
process.stderr.write(error.stderrBuffer);
|
|
throw error;
|
|
}
|
|
);
|
|
|
|
const initialGitStatusDeferred = shouldApplyFsCleanupCheck ? resolveGitStatus() : null;
|
|
|
|
const initialSetupDeferred = shouldApplyFsCleanupCheck
|
|
? initialGitStatusDeferred
|
|
: Promise.resolve();
|
|
|
|
globby(patterns).then(paths => {
|
|
if (!paths.length) {
|
|
process.stderr.write(chalk.red.bold('No test files matched\n\n'));
|
|
process.exit(1);
|
|
}
|
|
|
|
const processesCount = shouldApplyFsCleanupCheck
|
|
? 1
|
|
: Math.max(require('os').cpus().length - 1, 1);
|
|
|
|
const isMultiProcessRun = processesCount > 1;
|
|
|
|
const { ongoing, cliFooter } = (() => {
|
|
if (!isMultiProcessRun) return {};
|
|
return { ongoing: new Set(), cliFooter: require('cli-progress-footer')() };
|
|
})();
|
|
|
|
const run = path => {
|
|
if (isMultiProcessRun) {
|
|
ongoing.add(path);
|
|
cliFooter.updateProgress(Array.from(ongoing));
|
|
}
|
|
|
|
const onFinally = (() => {
|
|
if (isMultiProcessRun) {
|
|
return ({ stdoutBuffer, stderrBuffer }) => {
|
|
ongoing.delete(path);
|
|
cliFooter.updateProgress(Array.from(ongoing));
|
|
process.stdout.write(stdoutBuffer);
|
|
process.stderr.write(stderrBuffer);
|
|
return Promise.resolve();
|
|
};
|
|
}
|
|
if (!shouldApplyFsCleanupCheck) return () => Promise.resolve();
|
|
return () =>
|
|
Promise.all([initialGitStatusDeferred, resolveGitStatus()]).then(
|
|
([initialStatus, currentStatus]) => {
|
|
if (initialStatus !== currentStatus) {
|
|
process.stderr.write(
|
|
chalk.red.bold(`${path} didn't clean created temporary files\n\n`)
|
|
);
|
|
process.exit(1);
|
|
}
|
|
}
|
|
);
|
|
})();
|
|
|
|
return spawn('npx', ['mocha', path], {
|
|
stdio: isMultiProcessRun ? null : 'inherit',
|
|
env: {
|
|
APPDATA: process.env.APPDATA,
|
|
FORCE_COLOR: '1',
|
|
HOME: process.env.HOME,
|
|
PATH: process.env.PATH,
|
|
TMPDIR: process.env.TMPDIR,
|
|
USERPROFILE: process.env.USERPROFILE,
|
|
},
|
|
}).then(onFinally, error => {
|
|
if (isMultiProcessRun) ongoing.clear();
|
|
return onFinally(error).then(() => {
|
|
process.stderr.write(chalk.red.bold(`${path} failed\n\n`));
|
|
if (error.code <= 2) process.exit(error.code);
|
|
throw error;
|
|
});
|
|
});
|
|
};
|
|
|
|
const limit = pLimit(processesCount);
|
|
return initialSetupDeferred.then(() => Promise.all(paths.map(path => limit(() => run(path)))));
|
|
});
|