Skip to content

Commit

Permalink
improved to execute concurrency
Browse files Browse the repository at this point in the history
  • Loading branch information
keiya01 committed Sep 22, 2020
1 parent 7655ff7 commit 35ed13c
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 33 deletions.
8 changes: 4 additions & 4 deletions packages/performance-testing-cli/src/__tests__/exec.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,18 @@ afterEach(() => {
logger.logError.mockRestore();
});

test('should output error', () => {
test('should output error', async () => {
error = new Error();

exec('test', 'path', []);
await exec('test', 'path', []);

expect(logger.logError).toBeCalledTimes(1);
});

test('should not output error when error is undefined', () => {
test('should not output error when error is undefined', async () => {
error = null;

exec('test', 'path', []);
await exec('test', 'path', []);

expect(logger.logError).not.toBeCalled();
});
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import mockFs from 'mock-fs';
import { getAllFilesBy } from '../getAllFilesBy';
import { matchDefault } from '../constants/matchDefault';
import { matchDefault } from '../constants/defaultOptions';

mockFs({
'path/to': {
Expand Down
122 changes: 105 additions & 17 deletions packages/performance-testing-cli/src/__tests__/run.test.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,32 @@
import mockFs from 'mock-fs';
import { run } from '../index';
import * as executer from '../exec';
import * as args from '../toArgs';
import * as _argv from '../getArgv';
import { matchDefault } from '../constants/matchDefault';
import { matchDefault, concurrentDefault } from '../constants/defaultOptions';

mockFs({
path: {
'test1.test.ts': 'test1',
'test2.spec.js': 'test2',
'test3.test.ts': 'test3',
dir: {
'test4.test.ts': 'test4',
'test5.test.ts': 'test5',
'test6.test.ts': 'test6',
'test7.test.ts': 'test7',
'test8.test.ts': 'test8',
'test9.test.ts': 'test9',
'test10.test.ts': 'test10',
'test11.test.ts': 'test11',
'test12.test.ts': 'test12',
'test13.test.ts': 'test13',
'test14.test.ts': 'test14',
'test15.test.ts': 'test15',
'test16.test.ts': 'test16',
'test17.test.ts': 'test17',
'test18.test.ts': 'test18',
},
},
});

Expand All @@ -29,56 +47,126 @@ afterEach(() => {

afterAll(() => mockFs.restore());

test('should exit when argv is invalid', () => {
test('should exit when argv is invalid', async () => {
argv = { _: [] };

run();
await run();

expect(process.exit).toBeCalled();
});

test('should exit when file could not find', () => {
argv = { cmd: 'test', root: 'path/notFound.js', match: matchDefault, _: [] };
test('should exit when file could not find', async () => {
argv = {
cmd: 'test',
root: 'path/notFound.js',
match: matchDefault,
concurrent: concurrentDefault,
_: [],
};

run();
await run();

expect(process.exit).toBeCalled();
});

test('should not exit when argv is valid', () => {
argv = { cmd: 'test', root: 'path', match: matchDefault, _: [] };
test('should not exit when argv is valid', async () => {
argv = {
cmd: 'test',
root: 'path',
match: matchDefault,
concurrent: concurrentDefault,
_: [],
};

run();
await run();

expect(process.exit).not.toBeCalled();
});

test('should invoke exec method', () => {
jest.spyOn(executer, 'exec').mockImplementation(() => {});
test('should exclude argv correctly when toArgs method is called', async () => {
jest.spyOn(args, 'toArgs');

argv = {
cmd: 'test',
root: 'path',
match: matchDefault,
concurrent: concurrentDefault,
_: [],
};

argv = { cmd: 'test', root: 'path', match: matchDefault, _: [] };
await run();

run();
expect(args.toArgs).toBeCalledWith(expect.any(Object), [
'_',
'$1',
'cmd',
'c',
'root',
'r',
'match',
'm',
'concurrent',
]);

expect(executer.exec).toBeCalledTimes(3);
// @ts-ignore
args.toArgs.mockRestore();
});

test('should invoke exec method', async () => {
jest.spyOn(executer, 'exec').mockImplementation(async () => {});

argv = {
cmd: 'test',
root: 'path',
match: matchDefault,
concurrent: concurrentDefault,
_: [],
};

await run();

expect(executer.exec).toBeCalledTimes(18);
// @ts-ignore
executer.exec.mockRestore();
});

test('should invoke exec method when _ argument has path', () => {
jest.spyOn(executer, 'exec').mockImplementation(() => {});
test('should invoke exec method when _ argument has path', async () => {
jest.spyOn(executer, 'exec').mockImplementation(async () => {});

argv = {
cmd: 'test',
root: 'path',
match: matchDefault,
concurrent: concurrentDefault,
_: ['path/test1.test.ts'],
};

run();
await run();

expect(executer.exec).toBeCalledTimes(1);

// @ts-ignore
executer.exec.mockRestore();
});

test('should resolve all execution at once', async () => {
jest.spyOn(executer, 'exec').mockImplementation(async () => {});
jest.spyOn(Promise, 'all');

argv = {
cmd: 'test',
root: 'path/dir',
match: matchDefault,
concurrent: concurrentDefault,
_: [],
};

await run();

expect(Promise.all).toBeCalledTimes(1);

// @ts-ignore
executer.exec.mockRestore();
// @ts-ignore
Promise.all.mockRestore();
});
17 changes: 10 additions & 7 deletions packages/performance-testing-cli/src/exec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@ import child_process from 'child_process';
import { logError } from './logger';

export const exec = (cmd: string, filepath: string, args: string[]) => {
const { error } = child_process.spawnSync(cmd, [filepath, ...args], {
stdio: 'inherit',
env: { ...process.env },
});
return new Promise((resolve) => {
const { error } = child_process.spawnSync(cmd, [filepath, ...args], {
stdio: 'inherit',
env: { ...process.env },
});

if (error) {
logError(error);
}
if (error) {
logError(error);
}
return resolve();
});
};
26 changes: 22 additions & 4 deletions packages/performance-testing-cli/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,42 @@ import { getAllFilesBy } from './getAllFilesBy';
import { validate } from './validate';
import { getArgv } from './getArgv';
import { toArgs } from './toArgs';
import { options } from './options';

export const run = () => {
export const run = async () => {
const argv = getArgv();

if (!validate(argv)) {
return process.exit(1);
}

const root = argv._[0] || argv.root!;
const concurrent = argv.concurrent as number;

// We are checking if file is exist in `validate()`
// Therefore, we will not receive undefined from `getAllFilesBy()`
const matchedFiles = getAllFilesBy(root, argv.match)!;

const excludes = ['_', '$1', 'cmd', 'c', 'root', 'r', 'match', 'm'];
const excludes = Object.keys(options)
.reduce(
(res, key) => [...res, key, (options as Record<string, any>)[key].alias],
['_', '$1'],
)
.filter(Boolean);
const args = toArgs(argv, excludes);

for (let i = 0; i < matchedFiles.length; i++) {
exec(argv.cmd!, matchedFiles[i], args);
let pending = [];
let i = 0;
while (matchedFiles[i]) {
pending.push(exec(argv.cmd!, matchedFiles[i], args));
if (pending.length >= concurrent) {
await Promise.all(pending);
pending = [];
}
i++;
}

if (pending.length) {
await Promise.all(pending);
}
};

0 comments on commit 35ed13c

Please sign in to comment.