236 lines
7.3 KiB
JavaScript
236 lines
7.3 KiB
JavaScript
import createWorker from './worker-executor';
|
|
|
|
function mockWorker({ init, postMessage, terminate } = {}) {
|
|
global.Worker = jest.fn(function () {
|
|
setImmediate(
|
|
(init && init(this)) ||
|
|
(() =>
|
|
this.onmessage && this.onmessage({ data: { type: 'contentLoaded' } }))
|
|
);
|
|
this.onmessage = null;
|
|
this.postMessage =
|
|
postMessage ||
|
|
function (data) {
|
|
setImmediate(
|
|
() => this.onmessage && this.onmessage({ data: `${data} processed` })
|
|
);
|
|
};
|
|
this.terminate = terminate || (() => {});
|
|
return this;
|
|
});
|
|
}
|
|
|
|
afterEach(() => {
|
|
delete global.Worker;
|
|
});
|
|
|
|
it('Worker executor should successfully execute one task', async () => {
|
|
const terminateHandler = jest.fn();
|
|
mockWorker({ terminate: terminateHandler });
|
|
const testWorker = createWorker('test');
|
|
expect(testWorker).not.toBeUndefined();
|
|
|
|
const task = testWorker.execute('test');
|
|
expect(task).not.toBeUndefined();
|
|
expect(task.done).not.toBeUndefined();
|
|
const handler = jest.fn();
|
|
task.on('done', handler);
|
|
const errorHandler = jest.fn();
|
|
task.on('error', errorHandler);
|
|
|
|
await expect(task.done).resolves.toBe('test processed');
|
|
|
|
expect(handler).toBeCalledTimes(1);
|
|
expect(handler).toBeCalledWith('test processed');
|
|
|
|
expect(errorHandler).not.toBeCalled();
|
|
expect(terminateHandler).not.toBeCalled();
|
|
|
|
expect(global.Worker).toBeCalledTimes(1);
|
|
expect(global.Worker).toBeCalledWith('/js/test.js');
|
|
});
|
|
|
|
// eslint-disable-next-line max-len
|
|
it('Worker executor should successfully execute two tasks in parallel', async () => {
|
|
const terminateHandler = jest.fn();
|
|
mockWorker({ terminate: terminateHandler });
|
|
const testWorker = createWorker('test');
|
|
|
|
const task1 = testWorker.execute('test1');
|
|
const handler1 = jest.fn();
|
|
task1.on('done', handler1);
|
|
const errorHandler1 = jest.fn();
|
|
task1.on('error', errorHandler1);
|
|
|
|
const task2 = testWorker.execute('test2');
|
|
const handler2 = jest.fn();
|
|
task2.on('done', handler2);
|
|
const errorHandler2 = jest.fn();
|
|
task2.on('error', errorHandler2);
|
|
|
|
await expect(Promise.all([task1.done, task2.done])).resolves.toEqual([
|
|
'test1 processed',
|
|
'test2 processed'
|
|
]);
|
|
|
|
expect(handler1).toBeCalledTimes(1);
|
|
expect(handler1).toBeCalledWith('test1 processed');
|
|
expect(errorHandler1).not.toBeCalled();
|
|
|
|
expect(handler2).toBeCalledTimes(1);
|
|
expect(handler2).toBeCalledWith('test2 processed');
|
|
expect(errorHandler2).not.toBeCalled();
|
|
expect(terminateHandler).not.toBeCalled();
|
|
|
|
expect(global.Worker).toBeCalledTimes(2);
|
|
});
|
|
|
|
// eslint-disable-next-line max-len
|
|
it('Worker executor should successfully execute 3 tasks in parallel and use two workers', async () => {
|
|
mockWorker();
|
|
const testWorker = createWorker('test');
|
|
|
|
const task1 = testWorker.execute('test1');
|
|
const task2 = testWorker.execute('test2');
|
|
const task3 = testWorker.execute('test3');
|
|
await expect(
|
|
Promise.all([task1.done, task2.done, task3.done])
|
|
).resolves.toEqual(['test1 processed', 'test2 processed', 'test3 processed']);
|
|
|
|
expect(global.Worker).toBeCalledTimes(2);
|
|
});
|
|
|
|
// eslint-disable-next-line max-len
|
|
it('Worker executor should successfully execute 3 tasks, use 3 workers and terminate each worker', async () => {
|
|
const terminateHandler = jest.fn();
|
|
mockWorker({ terminate: terminateHandler });
|
|
const testWorker = createWorker('test', { terminateWorker: true });
|
|
|
|
const task1 = testWorker.execute('test1');
|
|
const task2 = testWorker.execute('test2');
|
|
const task3 = testWorker.execute('test3');
|
|
await expect(
|
|
Promise.all([task1.done, task2.done, task3.done])
|
|
).resolves.toEqual(['test1 processed', 'test2 processed', 'test3 processed']);
|
|
|
|
expect(terminateHandler).toBeCalledTimes(3);
|
|
expect(global.Worker).toBeCalledTimes(3);
|
|
});
|
|
|
|
// eslint-disable-next-line max-len
|
|
it('Worker executor should successfully execute 3 tasks in parallel and use 3 workers', async () => {
|
|
mockWorker();
|
|
const testWorker = createWorker('test', { concurrency: 3 });
|
|
|
|
const task1 = testWorker.execute('test1');
|
|
const task2 = testWorker.execute('test2');
|
|
const task3 = testWorker.execute('test3');
|
|
await expect(
|
|
Promise.all([task1.done, task2.done, task3.done])
|
|
).resolves.toEqual(['test1 processed', 'test2 processed', 'test3 processed']);
|
|
|
|
expect(global.Worker).toBeCalledTimes(3);
|
|
});
|
|
|
|
// eslint-disable-next-line max-len
|
|
it('Worker executor should successfully execute 3 tasks and use 1 worker', async () => {
|
|
mockWorker();
|
|
const testWorker = createWorker('test', { concurrency: 1 });
|
|
|
|
const task1 = testWorker.execute('test1');
|
|
const task2 = testWorker.execute('test2');
|
|
const task3 = testWorker.execute('test3');
|
|
await expect(
|
|
Promise.all([task1.done, task2.done, task3.done])
|
|
).resolves.toEqual(['test1 processed', 'test2 processed', 'test3 processed']);
|
|
|
|
expect(global.Worker).toBeCalledTimes(1);
|
|
});
|
|
|
|
it('Worker executor should reject task', async () => {
|
|
const error = { message: 'Error on init worker' };
|
|
mockWorker({
|
|
init: () => {
|
|
throw error;
|
|
}
|
|
});
|
|
const testWorker = createWorker('test');
|
|
|
|
const task = testWorker.execute('test');
|
|
const errorHandler = jest.fn();
|
|
task.on('error', errorHandler);
|
|
await expect(task.done).rejects.toBe(error.message);
|
|
|
|
expect(errorHandler).toBeCalledTimes(1);
|
|
expect(errorHandler).toBeCalledWith(error);
|
|
});
|
|
|
|
it('Worker executor should emit LOG events', async () => {
|
|
mockWorker({
|
|
postMessage: function (data) {
|
|
setImmediate(() => {
|
|
for (let i = 0; i < 3; i++) {
|
|
// eslint-disable-next-line no-unused-expressions
|
|
this.onmessage && this.onmessage({ data: { type: 'LOG', data: i } });
|
|
}
|
|
// eslint-disable-next-line no-unused-expressions
|
|
this.onmessage && this.onmessage({ data: `${data} processed` });
|
|
setImmediate(
|
|
() =>
|
|
this.onmessage && this.onmessage({ data: { type: 'LOG', data: 3 } })
|
|
);
|
|
});
|
|
}
|
|
});
|
|
const testWorker = createWorker('test');
|
|
|
|
const task = testWorker.execute('test');
|
|
const handler = jest.fn();
|
|
task.on('done', handler);
|
|
const errorHandler = jest.fn();
|
|
task.on('error', errorHandler);
|
|
const logHandler = jest.fn();
|
|
task.on('LOG', logHandler);
|
|
|
|
await expect(task.done).resolves.toBe('test processed');
|
|
|
|
expect(handler).toBeCalledTimes(1);
|
|
expect(handler).toBeCalledWith('test processed');
|
|
expect(errorHandler).not.toBeCalled();
|
|
|
|
expect(logHandler).toBeCalledTimes(3);
|
|
for (let i = 0; i < 3; i++) {
|
|
expect(logHandler.mock.calls[i][0]).toBe(i);
|
|
}
|
|
});
|
|
|
|
it('Worker executor should reject task on timeout', async () => {
|
|
const terminateHandler = jest.fn();
|
|
mockWorker({
|
|
postMessage: () => {},
|
|
terminate: terminateHandler
|
|
});
|
|
const testWorker = createWorker('test');
|
|
|
|
const task = testWorker.execute('test', 0);
|
|
const errorHandler = jest.fn();
|
|
task.on('error', errorHandler);
|
|
await expect(task.done).rejects.toBe('timeout');
|
|
|
|
expect(errorHandler).toBeCalledTimes(1);
|
|
expect(errorHandler.mock.calls[0][0]).toEqual({ message: 'timeout' });
|
|
|
|
expect(terminateHandler).toBeCalledTimes(1);
|
|
});
|
|
|
|
it('Worker executor should get worker from specified location', async () => {
|
|
mockWorker();
|
|
const testWorker = createWorker('test', { location: '/other/location/' });
|
|
|
|
const task = testWorker.execute('test');
|
|
await expect(task.done).resolves.toBe('test processed');
|
|
|
|
expect(global.Worker).toBeCalledTimes(1);
|
|
expect(global.Worker).toBeCalledWith('/other/location/test.js');
|
|
});
|