From d37d513ea314d4f2e930a9e6abcf272c497ac36e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A1bio=20Santos?= Date: Mon, 15 Oct 2018 17:27:39 +0100 Subject: [PATCH 1/7] reuse processes using a process pool --- .editorconfig | 2 +- .travis.yml | 3 + src/main/mocha.ts | 90 +++++++++++++---------- src/main/process-pool.ts | 78 ++++++++++++++++++++ src/subprocess/runner.ts | 99 +++++++++++--------------- test/.editorconfig | 10 +++ test/full-trace/index.spec.js | 5 +- test/index.sh | 1 + test/reusing-processes/README | 1 + test/reusing-processes/index.2.spec.js | 5 ++ test/reusing-processes/index.js | 21 ++++++ test/reusing-processes/index.spec.js | 5 ++ 12 files changed, 224 insertions(+), 96 deletions(-) create mode 100644 src/main/process-pool.ts create mode 100644 test/.editorconfig create mode 100644 test/reusing-processes/README create mode 100644 test/reusing-processes/index.2.spec.js create mode 100755 test/reusing-processes/index.js create mode 100644 test/reusing-processes/index.spec.js diff --git a/.editorconfig b/.editorconfig index d8a97bd..f5190e1 100644 --- a/.editorconfig +++ b/.editorconfig @@ -6,5 +6,5 @@ insert_final_newline = true indent_style = space indent_size = 2 -[{*.js,test/index.sh}] +[{*.js}] indent_size = 4 diff --git a/.travis.yml b/.travis.yml index 6f27eeb..af6a998 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,3 +17,6 @@ install: npm install before_script: greenkeeper-lockfile-update after_script: greenkeeper-lockfile-upload script: npm run test:ci +cache: + directories: + - node_modules diff --git a/src/main/mocha.ts b/src/main/mocha.ts index e60c0e8..37d2d5b 100644 --- a/src/main/mocha.ts +++ b/src/main/mocha.ts @@ -1,17 +1,17 @@ -import { fork } from 'child_process'; +import * as assert from 'assert'; import * as CircularJSON from 'circular-json'; import * as debug from 'debug'; import * as Mocha from 'mocha'; import { resolve as pathResolve } from 'path'; +import ProcessPool from './process-pool'; import RunnerMain from './runner'; import TaskManager from './task-manager'; import { - removeDebugArgs, subprocessParseReviver, } from './util'; -import { DEBUG_SUBPROCESS, SUITE_OWN_OPTIONS } from '../config'; +import { SUITE_OWN_OPTIONS } from '../config'; import { IRetriedTest, ISubprocessOutputMessage, @@ -24,6 +24,7 @@ import { const debugLog = debug('mocha-parallel-tests'); export default class MochaWrapper extends Mocha { + private pool = new ProcessPool(); private isTypescriptRunMode = false; private maxParallel: number | undefined; private requires: string[] = []; @@ -50,6 +51,7 @@ export default class MochaWrapper extends Mocha { setMaxParallel(maxParallel: number) { this.maxParallel = maxParallel; + this.pool.setMaxParallel(maxParallel); } enableExitMode() { @@ -136,6 +138,7 @@ export default class MochaWrapper extends Mocha { }; runner.emitFinishEvents(done); + this.pool.destroyAll(); }); return runner; @@ -162,89 +165,90 @@ export default class MochaWrapper extends Mocha { } private spawnTestProcess(file: string): Promise { - return new Promise((resolve) => { - const nodeFlags: string[] = []; - const extension = this.isTypescriptRunMode ? 'ts' : 'js'; - const runnerPath = pathResolve(__dirname, `../subprocess/runner.${extension}`); + return new Promise(async (resolve) => { const resolvedFilePath = pathResolve(file); - const forkArgs: string[] = ['--test', resolvedFilePath]; + const testOptions: {[key: string]: any} = { test: resolvedFilePath }; + for (const option of SUITE_OWN_OPTIONS) { const propValue = this.suite[option](); // bail is undefined by default, we need to somehow pass its value to the subprocess - forkArgs.push(`--${option}`, propValue === undefined ? false : propValue); + testOptions[option] = propValue === undefined ? false : propValue; } for (const requirePath of this.requires) { - forkArgs.push('--require', requirePath); + testOptions.require = requirePath; } - for (const compilerPath of this.compilers) { - forkArgs.push('--compilers', compilerPath); - } + testOptions.compilers = this.compilers || []; if (this.options.delay) { - forkArgs.push('--delay'); + testOptions.delay = true; } if (this.options.grep) { - forkArgs.push('--grep', this.options.grep.toString()); + testOptions.grep = this.options.grep.toString(); } if (this.exitImmediately) { - forkArgs.push('--exit'); + testOptions.exit = true; } if (this.options.fullStackTrace) { - forkArgs.push('--full-trace'); + testOptions.fullStackTrace = true; } - const test = fork(runnerPath, forkArgs, { - // otherwise `--inspect-brk` and other params will be passed to subprocess - execArgv: process.execArgv.filter(removeDebugArgs), - stdio: ['ipc'], - }); - - if (this.isTypescriptRunMode) { - nodeFlags.push('--require', 'ts-node/register'); + let test; + try { + test = await this.pool.getOrCreate(this.isTypescriptRunMode); + } catch (e) { + throw e; } - debugLog('Process spawned. You can run it manually with this command:'); - debugLog(`node ${nodeFlags.join(' ')} ${runnerPath} ${forkArgs.concat([DEBUG_SUBPROCESS.argument]).join(' ')}`); + test.send(JSON.stringify({ type: 'start', testOptions })); const events: Array = []; let syncedSubprocessData: ISubprocessSyncedData | undefined; const startedAt = Date.now(); - test.on('message', function onMessageHandler({ event, data }) { + function onMessageHandler({ event, data }) { if (event === 'sync') { syncedSubprocessData = data; + } else if (event === 'end') { + clean(); + resolve({ + code: data.code || 0, + events, + execTime: Date.now() - startedAt, + file, + syncedSubprocessData, + }); } else { + assert(event); events.push({ data, event, type: 'runner', }); } - }); + } - test.stdout.on('data', function onStdoutData(data: Buffer) { + function onStdoutData(data: Buffer) { events.push({ data, event: undefined, type: 'stdout', }); - }); + } - test.stderr.on('data', function onStderrData(data: Buffer) { + function onStderrData(data: Buffer) { events.push({ data, event: undefined, type: 'stderr', }); - }); - - test.on('close', (code) => { + } + function onClose(code) { debugLog(`Process for ${file} exited with code ${code}`); resolve({ @@ -254,7 +258,21 @@ export default class MochaWrapper extends Mocha { file, syncedSubprocessData, }); - }); + } + + test.on('message', onMessageHandler); + test.stdout.on('data', onStdoutData); + test.stderr.on('data', onStderrData); + test.on('close', onClose); + + function clean() { + test.removeListener('message', onMessageHandler); + test.stdout.removeListener('data', onStdoutData); + test.stderr.removeListener('data', onStderrData); + test.removeListener('close', onClose); + test.destroy(); + return null; + } }); } } diff --git a/src/main/process-pool.ts b/src/main/process-pool.ts new file mode 100644 index 0000000..153344f --- /dev/null +++ b/src/main/process-pool.ts @@ -0,0 +1,78 @@ +import { fork } from 'child_process'; +import * as os from 'os'; +import { resolve as pathResolve } from 'path'; +import { removeDebugArgs } from './util'; + +interface IMochaProcess { + send: (msg: any) => void; + kill: () => void; + destroy: () => void; +} + +export default class ProcessPool { + private maxParallel: number; + private waitingList: Array<(proc: IMochaProcess) => void> = []; + private unusedProcesses: IMochaProcess[] = []; + private processes: IMochaProcess[] = []; + + constructor() { + this.maxParallel = os.cpus().length; + } + + setMaxParallel(n) { + this.maxParallel = n; + } + + async getOrCreate(isTypescriptRunMode): Promise { + const extension = isTypescriptRunMode ? 'ts' : 'js'; + const runnerPath = pathResolve(__dirname, `../subprocess/runner.${extension}`); + + const lastUnusedProcess = this.unusedProcesses.pop(); + if (lastUnusedProcess) { + return lastUnusedProcess; + } + + if (this.processes.length >= this.maxParallel) { + const process: IMochaProcess = await new Promise((resolve) => { + this.waitingList.push(resolve); + }); + return process; + } + return this.create(runnerPath, { + // otherwise `--inspect-brk` and other params will be passed to subprocess + execArgv: process.execArgv.filter(removeDebugArgs), + stdio: ['ipc'], + }); + } + + create(runnerPath: string, opt: object): IMochaProcess { + const process = fork(runnerPath, [], opt); + + const handle = { + destroy: () => { + const nextOnWaitingList = this.waitingList.pop(); + if (nextOnWaitingList) { + nextOnWaitingList(handle); + } else { + this.unusedProcesses.push(handle); + } + }, + kill: () => { + process.kill(); + }, + send: (msg: any) => { + process.send(msg); + }, + }; + + this.processes.push(handle); + + return handle; + } + + destroyAll() { + this.processes.forEach((proc) => { + proc.kill(); + }); + } +} diff --git a/src/subprocess/runner.ts b/src/subprocess/runner.ts index ad8d05a..7737e86 100755 --- a/src/subprocess/runner.ts +++ b/src/subprocess/runner.ts @@ -2,10 +2,8 @@ import * as assert from 'assert'; import * as CircularJSON from 'circular-json'; import * as Mocha from 'mocha'; import { IRunner, reporters } from 'mocha'; -import * as yargs from 'yargs'; import { - DEBUG_SUBPROCESS, RUNNABLE_IPC_PROP, SUBPROCESS_RETRIED_SUITE_ID, } from '../config'; @@ -29,32 +27,6 @@ import { import applyExit from './options/exit'; import applyFullTrace from './options/full-trace'; -const argv = yargs - .boolean('bail') - .option('compilers', { - array: true, - default: [], - }) - .boolean('delay') - .string('grep') - .boolean('enableTimeouts') - .option('exit', { - boolean: true, - }) - .option('full-trace', { - boolean: true, - }) - .number('slow') - .option('require', { - array: true, - default: [], - }) - .number('retries') - .number('timeout') - .parse(process.argv); - -const debugSubprocess = argv[DEBUG_SUBPROCESS.yargs]; - class Reporter extends reporters.Base { /** * If `--retries N` option is specified runner can emit `test` events @@ -185,12 +157,7 @@ class Reporter extends reporters.Base { } private notifyParent(event: string, data = {}) { - if (debugSubprocess) { - // tslint:disable-next-line:no-console - console.log({ event, data }); - } else { - this.notifyParentThroughIPC(event, data); - } + this.notifyParentThroughIPC(event, data); } private notifyParentThroughIPC(event: string, data = {}) { @@ -222,37 +189,53 @@ class Reporter extends reporters.Base { } } -const mocha = new Mocha(); -mocha.addFile(argv.test); +process.on('message', (msg) => { + try { + msg = JSON.parse(msg); + } catch (_) { + return; + } + const { type, testOptions } = msg; -// --compilers -applyCompilers(argv.compilers); + if (type !== 'start') { + return; + } -// --delay -applyDelay(mocha, argv.delay); + const mocha = new Mocha(); + mocha.addFile(testOptions.test); -// --grep -applyGrepPattern(mocha, argv.grep); + // --compilers + applyCompilers(testOptions.compilers); -// --enableTimeouts -applyNoTimeouts(mocha, argv.enableTimeouts); + // --delay + applyDelay(mocha, testOptions.delay); -// --exit -const onComplete = applyExit(argv.exit); + // --grep + applyGrepPattern(mocha, testOptions.grep); -// --require -applyRequires(argv.require); + // --enableTimeouts + applyNoTimeouts(mocha, testOptions.enableTimeouts); -// --timeout -applyTimeouts(mocha, argv.timeout); + // --exit + const onComplete = applyExit(testOptions.exit); -// --full-trace -applyFullTrace(mocha, argv.fullTrace); + // --require + applyRequires(testOptions.require || []); -// apply main process root suite properties -for (const option of SUITE_OWN_OPTIONS) { - const suiteProp = `_${option}`; - mocha.suite[suiteProp] = argv[option]; -} + // --full-trace + applyFullTrace(mocha, testOptions.fullStackTrace); + + // --timeout + applyTimeouts(mocha, testOptions.timeout); + + // --full-trace + applyFullTrace(mocha, testOptions.fullStackTrace); + + // apply main process root suite properties + for (const option of SUITE_OWN_OPTIONS) { + const suiteProp = `_${option}`; + mocha.suite[suiteProp] = testOptions[option]; + } -mocha.reporter(Reporter).run(onComplete); + mocha.reporter(Reporter).run(onComplete); +}); diff --git a/test/.editorconfig b/test/.editorconfig new file mode 100644 index 0000000..3c6c04e --- /dev/null +++ b/test/.editorconfig @@ -0,0 +1,10 @@ +# EditorConfig is awesome: http://EditorConfig.org +root = true + +# Unix-style newlines with a newline ending every file +[*] +end_of_line = lf +insert_final_newline = true +charset = utf-8 +indent_style = space +indent_size = 4 diff --git a/test/full-trace/index.spec.js b/test/full-trace/index.spec.js index b01232f..32f2862 100644 --- a/test/full-trace/index.spec.js +++ b/test/full-trace/index.spec.js @@ -1,5 +1,8 @@ describe('Throwing error', () => { it('should throw', () => { - throw new Error('foo'); + function x() { + throw new Error('foo'); + } + x(); }); }); diff --git a/test/index.sh b/test/index.sh index f95cafe..e5630e5 100755 --- a/test/index.sh +++ b/test/index.sh @@ -29,6 +29,7 @@ function test { MOCHA_VERSION=`mocha --version` echo "You're running tests with mocha version $MOCHA_VERSION" +test 'process reuse' test/reusing-processes/index.js test 'native (json) reporter' test/reporter-native-json/index.sh test 'native (tap) reporter' test/reporter-native-tap/index.sh test 'custom (teamcity) reporter' test/reporter-custom-teamcity/index.sh diff --git a/test/reusing-processes/README b/test/reusing-processes/README new file mode 100644 index 0000000..0267e28 --- /dev/null +++ b/test/reusing-processes/README @@ -0,0 +1 @@ +Check if processes are being reused diff --git a/test/reusing-processes/index.2.spec.js b/test/reusing-processes/index.2.spec.js new file mode 100644 index 0000000..cb2b7c9 --- /dev/null +++ b/test/reusing-processes/index.2.spec.js @@ -0,0 +1,5 @@ +describe('suite 2', () => { + it('output pid', () => { + console.log('pid:', process.pid); + }); +}); diff --git a/test/reusing-processes/index.js b/test/reusing-processes/index.js new file mode 100755 index 0000000..4fef0dc --- /dev/null +++ b/test/reusing-processes/index.js @@ -0,0 +1,21 @@ +#!/usr/bin/env node + +'use strict'; + +const assert = require('assert'); +const { resolve } = require('path'); +const { exec } = require('child_process'); +const libExecutable = resolve(__dirname, '../../dist/bin/cli.js'); + +exec(`${libExecutable} --max-parallel 1 test/reusing-processes/index.spec.js test/reusing-processes/index.2.spec.js`, { + cwd: resolve(__dirname, '../../'), +}, (err, stdout) => { + if (err) { + console.error(err); + process.exit(1); + } + + const [pid1, pid2] = stdout.split(/\n/g).filter(line => /^pid/.test(line)); + + if (pid1 && pid2) assert.strictEqual(pid1, pid2); +}); diff --git a/test/reusing-processes/index.spec.js b/test/reusing-processes/index.spec.js new file mode 100644 index 0000000..9586940 --- /dev/null +++ b/test/reusing-processes/index.spec.js @@ -0,0 +1,5 @@ +describe('suite', () => { + it('output pid', () => { + console.log('pid:', process.pid); + }); +}); From 92921f9b093e50d5c6548c5dd69b8a5266549fd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A1bio=20Santos?= Date: Fri, 9 Nov 2018 16:48:05 +0000 Subject: [PATCH 2/7] change style, and complete process wrapper --- src/main/mocha.ts | 34 +++++++++++++++++----------------- src/main/process-pool.ts | 20 +++++++++++++++++--- 2 files changed, 34 insertions(+), 20 deletions(-) diff --git a/src/main/mocha.ts b/src/main/mocha.ts index 37d2d5b..f3edc15 100644 --- a/src/main/mocha.ts +++ b/src/main/mocha.ts @@ -211,7 +211,15 @@ export default class MochaWrapper extends Mocha { let syncedSubprocessData: ISubprocessSyncedData | undefined; const startedAt = Date.now(); - function onMessageHandler({ event, data }) { + const clean = () => { + test.removeListener('message', onMessageHandler); + test.stdout.removeListener('data', onStdoutData); + test.stderr.removeListener('data', onStderrData); + test.removeListener('close', onClose); + test.destroy(); + }; + + const onMessageHandler = ({ event, data }: { event: string, data: any }) => { if (event === 'sync') { syncedSubprocessData = data; } else if (event === 'end') { @@ -231,24 +239,25 @@ export default class MochaWrapper extends Mocha { type: 'runner', }); } - } + }; - function onStdoutData(data: Buffer) { + const onStdoutData = (data: Buffer) => { events.push({ data, event: undefined, type: 'stdout', }); - } + }; - function onStderrData(data: Buffer) { + const onStderrData = (data: Buffer) => { events.push({ data, event: undefined, type: 'stderr', }); - } - function onClose(code) { + }; + + const onClose = (code: number) => { debugLog(`Process for ${file} exited with code ${code}`); resolve({ @@ -258,21 +267,12 @@ export default class MochaWrapper extends Mocha { file, syncedSubprocessData, }); - } + }; test.on('message', onMessageHandler); test.stdout.on('data', onStdoutData); test.stderr.on('data', onStderrData); test.on('close', onClose); - - function clean() { - test.removeListener('message', onMessageHandler); - test.stdout.removeListener('data', onStdoutData); - test.stderr.removeListener('data', onStderrData); - test.removeListener('close', onClose); - test.destroy(); - return null; - } }); } } diff --git a/src/main/process-pool.ts b/src/main/process-pool.ts index 153344f..4c8dce5 100644 --- a/src/main/process-pool.ts +++ b/src/main/process-pool.ts @@ -3,10 +3,16 @@ import * as os from 'os'; import { resolve as pathResolve } from 'path'; import { removeDebugArgs } from './util'; +type eventFn = (data: any) => void; + interface IMochaProcess { send: (msg: any) => void; kill: () => void; destroy: () => void; + on: (event: string, fn: eventFn) => void; + removeListener: (event: string, eventFn) => void; + stdout: NodeJS.ReadableStream; + stderr: NodeJS.ReadableStream; } export default class ProcessPool { @@ -19,11 +25,11 @@ export default class ProcessPool { this.maxParallel = os.cpus().length; } - setMaxParallel(n) { + setMaxParallel(n: number) { this.maxParallel = n; } - async getOrCreate(isTypescriptRunMode): Promise { + async getOrCreate(isTypescriptRunMode: boolean): Promise { const extension = isTypescriptRunMode ? 'ts' : 'js'; const runnerPath = pathResolve(__dirname, `../subprocess/runner.${extension}`); @@ -60,9 +66,17 @@ export default class ProcessPool { kill: () => { process.kill(); }, + on: (ev, fn) => { + process.on(ev, fn); + }, + removeListener: (ev, fn) => { + process.removeListener(ev, fn); + }, send: (msg: any) => { process.send(msg); }, + stderr: process.stderr, + stdout: process.stdout, }; this.processes.push(handle); @@ -71,7 +85,7 @@ export default class ProcessPool { } destroyAll() { - this.processes.forEach((proc) => { + this.processes.forEach((proc: IMochaProcess) => { proc.kill(); }); } From 756d770cace12b43dfd1ecc84b90f9db5aa29aea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A1bio=20Santos?= Date: Fri, 9 Nov 2018 16:54:25 +0000 Subject: [PATCH 3/7] GCC is already 4.8 --- .travis.yml | 9 --------- 1 file changed, 9 deletions(-) diff --git a/.travis.yml b/.travis.yml index af6a998..5dafbe9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,15 +3,6 @@ node_js: - "stable" - "8" - "9" -env: - - CXX=g++-4.8 -addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - gcc-4.8 - - g++-4.8 before_install: npm install -g greenkeeper-lockfile install: npm install before_script: greenkeeper-lockfile-update From 5048a63c4350152e137c2f1f831a2113e615a849 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A1bio=20Santos?= Date: Fri, 9 Nov 2018 17:26:11 +0000 Subject: [PATCH 4/7] test process reuse and timeouts --- test/index.sh | 3 +++ test/process-timeouts/README | 1 + test/process-timeouts/index.1.spec.js | 5 +++++ test/process-timeouts/index.2.spec.js | 4 ++++ test/process-timeouts/index.js | 14 +++++++++++++ test/reusing-processes-2/README | 1 + test/reusing-processes-2/index.1.spec.js | 6 ++++++ test/reusing-processes-2/index.2.spec.js | 6 ++++++ test/reusing-processes-2/index.3.spec.js | 5 +++++ test/reusing-processes-2/index.js | 26 ++++++++++++++++++++++++ 10 files changed, 71 insertions(+) create mode 100644 test/process-timeouts/README create mode 100644 test/process-timeouts/index.1.spec.js create mode 100644 test/process-timeouts/index.2.spec.js create mode 100755 test/process-timeouts/index.js create mode 100644 test/reusing-processes-2/README create mode 100644 test/reusing-processes-2/index.1.spec.js create mode 100644 test/reusing-processes-2/index.2.spec.js create mode 100644 test/reusing-processes-2/index.3.spec.js create mode 100755 test/reusing-processes-2/index.js diff --git a/test/index.sh b/test/index.sh index e5630e5..8357c53 100755 --- a/test/index.sh +++ b/test/index.sh @@ -20,6 +20,7 @@ function test { ((FAILES++)) echo -e "${RED}FAIL${NO_COLOUR}" echo $output + exit 1 else ((PASSES++)) echo -e "${GREEN}OK${NO_COLOUR}" @@ -30,6 +31,8 @@ MOCHA_VERSION=`mocha --version` echo "You're running tests with mocha version $MOCHA_VERSION" test 'process reuse' test/reusing-processes/index.js +test 'process reuse (2)' test/reusing-processes-2/index.js +test 'process timeouts' test/process-timeouts/index.js test 'native (json) reporter' test/reporter-native-json/index.sh test 'native (tap) reporter' test/reporter-native-tap/index.sh test 'custom (teamcity) reporter' test/reporter-custom-teamcity/index.sh diff --git a/test/process-timeouts/README b/test/process-timeouts/README new file mode 100644 index 0000000..0267e28 --- /dev/null +++ b/test/process-timeouts/README @@ -0,0 +1 @@ +Check if processes are being reused diff --git a/test/process-timeouts/index.1.spec.js b/test/process-timeouts/index.1.spec.js new file mode 100644 index 0000000..52ffbab --- /dev/null +++ b/test/process-timeouts/index.1.spec.js @@ -0,0 +1,5 @@ +describe('suite 1', () => { + it('hoard the process', (done) => { + setTimeout(done, 10000); + }); +}); diff --git a/test/process-timeouts/index.2.spec.js b/test/process-timeouts/index.2.spec.js new file mode 100644 index 0000000..3a85497 --- /dev/null +++ b/test/process-timeouts/index.2.spec.js @@ -0,0 +1,4 @@ +describe('suite 2', () => { + it('success', () => { + }); +}); diff --git a/test/process-timeouts/index.js b/test/process-timeouts/index.js new file mode 100755 index 0000000..a0dc882 --- /dev/null +++ b/test/process-timeouts/index.js @@ -0,0 +1,14 @@ +#!/usr/bin/env node + +'use strict'; + +const assert = require('assert'); +const { resolve } = require('path'); +const { exec } = require('child_process'); +const libExecutable = resolve(__dirname, '../../dist/bin/cli.js'); + +exec(`${libExecutable} --max-parallel 1 test/reusing-processes-2/index.1.spec.js test/reusing-processes-2/index.2.spec.js`, { + cwd: resolve(__dirname, '../../'), +}, err => { + assert(err); +}); diff --git a/test/reusing-processes-2/README b/test/reusing-processes-2/README new file mode 100644 index 0000000..0267e28 --- /dev/null +++ b/test/reusing-processes-2/README @@ -0,0 +1 @@ +Check if processes are being reused diff --git a/test/reusing-processes-2/index.1.spec.js b/test/reusing-processes-2/index.1.spec.js new file mode 100644 index 0000000..1deb23a --- /dev/null +++ b/test/reusing-processes-2/index.1.spec.js @@ -0,0 +1,6 @@ +describe('suite 1', () => { + it('output pid', (done) => { + console.log('pid:', process.pid); + setTimeout(done, 3000); + }); +}); diff --git a/test/reusing-processes-2/index.2.spec.js b/test/reusing-processes-2/index.2.spec.js new file mode 100644 index 0000000..4c10275 --- /dev/null +++ b/test/reusing-processes-2/index.2.spec.js @@ -0,0 +1,6 @@ +describe('suite 2', () => { + it('output pid', (done) => { + console.log('pid:', process.pid); + setTimeout(done, 2000); + }); +}); diff --git a/test/reusing-processes-2/index.3.spec.js b/test/reusing-processes-2/index.3.spec.js new file mode 100644 index 0000000..36c42a8 --- /dev/null +++ b/test/reusing-processes-2/index.3.spec.js @@ -0,0 +1,5 @@ +describe('suite 3', () => { + it('output pid', () => { + console.log('pid:', process.pid); + }); +}); diff --git a/test/reusing-processes-2/index.js b/test/reusing-processes-2/index.js new file mode 100755 index 0000000..9a5f733 --- /dev/null +++ b/test/reusing-processes-2/index.js @@ -0,0 +1,26 @@ +#!/usr/bin/env node + +'use strict'; + +const assert = require('assert'); +const { resolve } = require('path'); +const { exec } = require('child_process'); +const libExecutable = resolve(__dirname, '../../dist/bin/cli.js'); + +exec(`${libExecutable} --max-parallel 2 --timeout 4000 test/reusing-processes-2/index.1.spec.js test/reusing-processes-2/index.2.spec.js test/reusing-processes-2/index.3.spec.js`, { + cwd: resolve(__dirname, '../../'), +}, (err, stdout) => { + if (err) { + console.error(err); + process.exit(1); + } + + const pid1 = (stdout.match(/suite 1\npid: (\d+)/) || [])[1]; + const pid2 = (stdout.match(/suite 2\npid: (\d+)/) || [])[1]; + const pid3 = (stdout.match(/suite 3\npid: (\d+)/) || [])[1]; + + if (pid1 && pid2 && pid3) { + assert.strictEqual(pid3, pid2); + assert.notEqual(pid1, pid2); + } +}); From 85477fef217a31b9aefd901d49a8d15bf430039f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A1bio=20Santos?= Date: Sat, 10 Nov 2018 17:07:54 +0000 Subject: [PATCH 5/7] use own test in process-timeouts --- test/process-timeouts/index.2.spec.js | 4 ---- test/process-timeouts/index.js | 2 +- test/process-timeouts/{index.1.spec.js => index.spec.js} | 0 3 files changed, 1 insertion(+), 5 deletions(-) delete mode 100644 test/process-timeouts/index.2.spec.js rename test/process-timeouts/{index.1.spec.js => index.spec.js} (100%) diff --git a/test/process-timeouts/index.2.spec.js b/test/process-timeouts/index.2.spec.js deleted file mode 100644 index 3a85497..0000000 --- a/test/process-timeouts/index.2.spec.js +++ /dev/null @@ -1,4 +0,0 @@ -describe('suite 2', () => { - it('success', () => { - }); -}); diff --git a/test/process-timeouts/index.js b/test/process-timeouts/index.js index a0dc882..871b341 100755 --- a/test/process-timeouts/index.js +++ b/test/process-timeouts/index.js @@ -7,7 +7,7 @@ const { resolve } = require('path'); const { exec } = require('child_process'); const libExecutable = resolve(__dirname, '../../dist/bin/cli.js'); -exec(`${libExecutable} --max-parallel 1 test/reusing-processes-2/index.1.spec.js test/reusing-processes-2/index.2.spec.js`, { +exec(`${libExecutable} --max-parallel 1 test/process-timeouts/index.spec.js`, { cwd: resolve(__dirname, '../../'), }, err => { assert(err); diff --git a/test/process-timeouts/index.1.spec.js b/test/process-timeouts/index.spec.js similarity index 100% rename from test/process-timeouts/index.1.spec.js rename to test/process-timeouts/index.spec.js From 833d66c76eefd00da1bb77d2e6450d0ed4e7ee5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A1bio=20Santos?= Date: Sun, 11 Nov 2018 18:00:26 +0000 Subject: [PATCH 6/7] further test documentation --- test/process-timeouts/README | 2 +- test/reusing-processes-2/README | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/process-timeouts/README b/test/process-timeouts/README index 0267e28..507f31c 100644 --- a/test/process-timeouts/README +++ b/test/process-timeouts/README @@ -1 +1 @@ -Check if processes are being reused +Check if a hoarding process is duly timed out diff --git a/test/reusing-processes-2/README b/test/reusing-processes-2/README index 0267e28..86c028d 100644 --- a/test/reusing-processes-2/README +++ b/test/reusing-processes-2/README @@ -1 +1 @@ -Check if processes are being reused +Check if processes are being reused (some more) From 0777db2aecfd044422b8b7db0d0a1eec6ea18c55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A1bio=20Santos?= Date: Mon, 12 Nov 2018 19:41:03 +0000 Subject: [PATCH 7/7] add assertion message --- test/process-timeouts/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/process-timeouts/index.js b/test/process-timeouts/index.js index 871b341..7e6d900 100755 --- a/test/process-timeouts/index.js +++ b/test/process-timeouts/index.js @@ -10,5 +10,5 @@ const libExecutable = resolve(__dirname, '../../dist/bin/cli.js'); exec(`${libExecutable} --max-parallel 1 test/process-timeouts/index.spec.js`, { cwd: resolve(__dirname, '../../'), }, err => { - assert(err); + assert(err, 'CLI was supposed to exit with an error'); });