chore(tests): add tests for worker-executor
This commit is contained in:
committed by
mrugesh mohapatra
parent
845b966bda
commit
80eaccc467
237
client/src/templates/Challenges/utils/worker-executor.test.js
Normal file
237
client/src/templates/Challenges/utils/worker-executor.test.js
Normal file
@@ -0,0 +1,237 @@
|
|||||||
|
/* global expect, jest */
|
||||||
|
|
||||||
|
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');
|
||||||
|
});
|
Reference in New Issue
Block a user