X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;f=tests%2Fworker%2Fabstract-worker.test.mjs;h=ed4fcbdb2f887068d53212b6e7e3b2e36aed5111;hb=refs%2Fheads%2Fmaster;hp=df844eef9a9cc72c5bac6c8749f95f8b42bb3d5c;hpb=c6e4045f0809e888bfbd1dbfc04fa10b7f93a66e;p=poolifier.git diff --git a/tests/worker/abstract-worker.test.mjs b/tests/worker/abstract-worker.test.mjs index df844eef..ed4fcbdb 100644 --- a/tests/worker/abstract-worker.test.mjs +++ b/tests/worker/abstract-worker.test.mjs @@ -1,7 +1,13 @@ import { expect } from 'expect' import { restore, stub } from 'sinon' -import { ClusterWorker, KillBehaviors, ThreadWorker } from '../../lib/index.js' -import { DEFAULT_TASK_NAME, EMPTY_FUNCTION } from '../../lib/utils.js' + +import { + ClusterWorker, + KillBehaviors, + ThreadWorker, + WorkerChoiceStrategies, +} from '../../lib/index.cjs' +import { DEFAULT_TASK_NAME, EMPTY_FUNCTION } from '../../lib/utils.cjs' describe('Abstract worker test suite', () => { class StubWorkerWithMainWorker extends ThreadWorker { @@ -20,49 +26,42 @@ describe('Abstract worker test suite', () => { expect(worker.opts).toStrictEqual({ killBehavior: KillBehaviors.SOFT, maxInactiveTime: 60000, - killHandler: EMPTY_FUNCTION + killHandler: EMPTY_FUNCTION, }) }) it('Verify that worker options are checked at worker creation', () => { - expect(() => new ClusterWorker(() => {}, '')).toThrowError( + expect(() => new ClusterWorker(() => {}, '')).toThrow( new TypeError('opts worker options parameter is not a plain object') ) - expect( - () => new ClusterWorker(() => {}, { killBehavior: '' }) - ).toThrowError(new TypeError("killBehavior option '' is not valid")) - expect(() => new ClusterWorker(() => {}, { killBehavior: 0 })).toThrowError( + expect(() => new ClusterWorker(() => {}, { killBehavior: '' })).toThrow( + new TypeError("killBehavior option '' is not valid") + ) + expect(() => new ClusterWorker(() => {}, { killBehavior: 0 })).toThrow( new TypeError("killBehavior option '0' is not valid") ) - expect( - () => new ThreadWorker(() => {}, { maxInactiveTime: '' }) - ).toThrowError(new TypeError('maxInactiveTime option is not an integer')) - expect( - () => new ThreadWorker(() => {}, { maxInactiveTime: 0.5 }) - ).toThrowError(new TypeError('maxInactiveTime option is not an integer')) - expect( - () => new ThreadWorker(() => {}, { maxInactiveTime: 0 }) - ).toThrowError( + expect(() => new ThreadWorker(() => {}, { maxInactiveTime: '' })).toThrow( + new TypeError('maxInactiveTime option is not an integer') + ) + expect(() => new ThreadWorker(() => {}, { maxInactiveTime: 0.5 })).toThrow( + new TypeError('maxInactiveTime option is not an integer') + ) + expect(() => new ThreadWorker(() => {}, { maxInactiveTime: 0 })).toThrow( new TypeError( 'maxInactiveTime option is not a positive integer greater or equal than 5' ) ) - expect( - () => new ThreadWorker(() => {}, { maxInactiveTime: 4 }) - ).toThrowError( + expect(() => new ThreadWorker(() => {}, { maxInactiveTime: 4 })).toThrow( new TypeError( 'maxInactiveTime option is not a positive integer greater or equal than 5' ) ) - expect(() => new ThreadWorker(() => {}, { killHandler: '' })).toThrowError( + expect(() => new ThreadWorker(() => {}, { killHandler: '' })).toThrow( new TypeError('killHandler option is not a function') ) - expect(() => new ThreadWorker(() => {}, { killHandler: 0 })).toThrowError( + expect(() => new ThreadWorker(() => {}, { killHandler: 0 })).toThrow( new TypeError('killHandler option is not a function') ) - expect(() => new ThreadWorker(() => {}, { async: true })).toThrowError( - new TypeError('async option is deprecated') - ) }) it('Verify that worker options are set at worker creation', () => { @@ -72,58 +71,58 @@ describe('Abstract worker test suite', () => { const worker = new ClusterWorker(() => {}, { killBehavior: KillBehaviors.HARD, maxInactiveTime: 6000, - killHandler + killHandler, }) expect(worker.opts).toStrictEqual({ killBehavior: KillBehaviors.HARD, maxInactiveTime: 6000, - killHandler + killHandler, }) }) it('Verify that taskFunctions parameter is mandatory', () => { - expect(() => new ClusterWorker()).toThrowError( + expect(() => new ClusterWorker()).toThrow( new Error('taskFunctions parameter is mandatory') ) }) it('Verify that taskFunctions parameter is a function or a plain object', () => { - expect(() => new ClusterWorker(0)).toThrowError( + expect(() => new ClusterWorker(0)).toThrow( new TypeError( 'taskFunctions parameter is not a function or a plain object' ) ) - expect(() => new ClusterWorker('')).toThrowError( + expect(() => new ClusterWorker('')).toThrow( new TypeError( 'taskFunctions parameter is not a function or a plain object' ) ) - expect(() => new ClusterWorker(true)).toThrowError( + expect(() => new ClusterWorker(true)).toThrow( new TypeError( 'taskFunctions parameter is not a function or a plain object' ) ) - expect(() => new ClusterWorker([])).toThrowError( + expect(() => new ClusterWorker([])).toThrow( new TypeError( 'taskFunctions parameter is not a function or a plain object' ) ) - expect(() => new ClusterWorker(new Map())).toThrowError( + expect(() => new ClusterWorker(new Map())).toThrow( new TypeError( 'taskFunctions parameter is not a function or a plain object' ) ) - expect(() => new ClusterWorker(new Set())).toThrowError( + expect(() => new ClusterWorker(new Set())).toThrow( new TypeError( 'taskFunctions parameter is not a function or a plain object' ) ) - expect(() => new ClusterWorker(new WeakMap())).toThrowError( + expect(() => new ClusterWorker(new WeakMap())).toThrow( new TypeError( 'taskFunctions parameter is not a function or a plain object' ) ) - expect(() => new ClusterWorker(new WeakSet())).toThrowError( + expect(() => new ClusterWorker(new WeakSet())).toThrow( new TypeError( 'taskFunctions parameter is not a function or a plain object' ) @@ -131,15 +130,19 @@ describe('Abstract worker test suite', () => { }) it('Verify that taskFunctions parameter is not an empty object', () => { - expect(() => new ClusterWorker({})).toThrowError( + expect(() => new ClusterWorker({})).toThrow( new Error('taskFunctions parameter object is empty') ) }) it('Verify that taskFunctions parameter with unique function is taken', () => { const worker = new ThreadWorker(() => {}) - expect(worker.taskFunctions.get(DEFAULT_TASK_NAME)).toBeInstanceOf(Function) - expect(worker.taskFunctions.get('fn1')).toBeInstanceOf(Function) + expect(worker.taskFunctions.get(DEFAULT_TASK_NAME)).toStrictEqual({ + taskFunction: expect.any(Function), + }) + expect(worker.taskFunctions.get('fn1')).toStrictEqual({ + taskFunction: expect.any(Function), + }) expect(worker.taskFunctions.size).toBe(2) expect(worker.taskFunctions.get(DEFAULT_TASK_NAME)).toStrictEqual( worker.taskFunctions.get('fn1') @@ -151,12 +154,39 @@ describe('Abstract worker test suite', () => { return 1 } const fn2 = '' - expect(() => new ThreadWorker({ '': fn1 })).toThrowError( + expect(() => new ThreadWorker({ '': fn1 })).toThrow( new TypeError('A taskFunctions parameter object key is an empty string') ) - expect(() => new ThreadWorker({ fn1, fn2 })).toThrowError( - new TypeError('A taskFunctions parameter object value is not a function') + expect(() => new ThreadWorker({ fn1, fn2 })).toThrow( + new TypeError( + "taskFunction object 'taskFunction' property 'undefined' is not a function" + ) + ) + expect(() => new ThreadWorker({ fn1: { fn1 } })).toThrow( + new TypeError( + "taskFunction object 'taskFunction' property 'undefined' is not a function" + ) ) + expect(() => new ThreadWorker({ fn2: { taskFunction: fn2 } })).toThrow( + new TypeError( + "taskFunction object 'taskFunction' property '' is not a function" + ) + ) + expect( + () => new ThreadWorker({ fn1: { taskFunction: fn1, priority: '' } }) + ).toThrow(new TypeError("Invalid property 'priority': ''")) + expect( + () => new ThreadWorker({ fn1: { taskFunction: fn1, priority: -21 } }) + ).toThrow(new RangeError("Property 'priority' must be between -20 and 19")) + expect( + () => new ThreadWorker({ fn1: { taskFunction: fn1, priority: 20 } }) + ).toThrow(new RangeError("Property 'priority' must be between -20 and 19")) + expect( + () => + new ThreadWorker({ + fn1: { taskFunction: fn1, strategy: 'invalidStrategy' }, + }) + ).toThrow(new Error("Invalid worker choice strategy 'invalidStrategy'")) }) it('Verify that taskFunctions parameter with multiple task functions is taken', () => { @@ -167,9 +197,42 @@ describe('Abstract worker test suite', () => { return 2 } const worker = new ClusterWorker({ fn1, fn2 }) - expect(worker.taskFunctions.get(DEFAULT_TASK_NAME)).toBeInstanceOf(Function) - expect(worker.taskFunctions.get('fn1')).toBeInstanceOf(Function) - expect(worker.taskFunctions.get('fn2')).toBeInstanceOf(Function) + expect(worker.taskFunctions.get(DEFAULT_TASK_NAME)).toStrictEqual({ + taskFunction: expect.any(Function), + }) + expect(worker.taskFunctions.get('fn1')).toStrictEqual({ + taskFunction: expect.any(Function), + }) + expect(worker.taskFunctions.get('fn2')).toStrictEqual({ + taskFunction: expect.any(Function), + }) + expect(worker.taskFunctions.size).toBe(3) + expect(worker.taskFunctions.get(DEFAULT_TASK_NAME)).toStrictEqual( + worker.taskFunctions.get('fn1') + ) + }) + + it('Verify that taskFunctions parameter with multiple task functions object is taken', () => { + const fn1Obj = { + taskFunction: () => { + return 1 + }, + priority: 5, + } + const fn2Obj = { + taskFunction: () => { + return 2 + }, + priority: 6, + strategy: WorkerChoiceStrategies.LESS_BUSY, + } + const worker = new ThreadWorker({ + fn1: fn1Obj, + fn2: fn2Obj, + }) + expect(worker.taskFunctions.get(DEFAULT_TASK_NAME)).toStrictEqual(fn1Obj) + expect(worker.taskFunctions.get('fn1')).toStrictEqual(fn1Obj) + expect(worker.taskFunctions.get('fn2')).toStrictEqual(fn2Obj) expect(worker.taskFunctions.size).toBe(3) expect(worker.taskFunctions.get(DEFAULT_TASK_NAME)).toStrictEqual( worker.taskFunctions.get('fn1') @@ -179,7 +242,7 @@ describe('Abstract worker test suite', () => { it('Verify that async kill handler is called when worker is killed', () => { const killHandlerStub = stub().returns() const worker = new ClusterWorker(() => {}, { - killHandler: async () => await Promise.resolve(killHandlerStub()) + killHandler: async () => await Promise.resolve(killHandlerStub()), }) worker.isMain = false worker.handleKillMessage() @@ -189,7 +252,7 @@ describe('Abstract worker test suite', () => { it('Verify that getMainWorker() throw error if main worker is not set', () => { expect(() => new StubWorkerWithMainWorker(() => {}).getMainWorker() - ).toThrowError('Main worker not set') + ).toThrow('Main worker not set') }) it('Verify that hasTaskFunction() is working', () => { @@ -202,14 +265,14 @@ describe('Abstract worker test suite', () => { const worker = new ClusterWorker({ fn1, fn2 }) expect(worker.hasTaskFunction(0)).toStrictEqual({ status: false, - error: new TypeError('name parameter is not a string') + error: new TypeError('name parameter is not a string'), }) expect(worker.hasTaskFunction('')).toStrictEqual({ status: false, - error: new TypeError('name parameter is an empty string') + error: new TypeError('name parameter is an empty string'), }) expect(worker.hasTaskFunction(DEFAULT_TASK_NAME)).toStrictEqual({ - status: true + status: true, }) expect(worker.hasTaskFunction('fn1')).toStrictEqual({ status: true }) expect(worker.hasTaskFunction('fn2')).toStrictEqual({ status: true }) @@ -229,18 +292,63 @@ describe('Abstract worker test suite', () => { const worker = new ThreadWorker(fn1) expect(worker.addTaskFunction(0, fn1)).toStrictEqual({ status: false, - error: new TypeError('name parameter is not a string') + error: new TypeError('name parameter is not a string'), }) expect(worker.addTaskFunction('', fn1)).toStrictEqual({ status: false, - error: new TypeError('name parameter is an empty string') + error: new TypeError('name parameter is an empty string'), + }) + expect(worker.addTaskFunction('fn2', 0)).toStrictEqual({ + status: false, + error: new TypeError( + "taskFunction object 'taskFunction' property 'undefined' is not a function" + ), }) expect(worker.addTaskFunction('fn3', '')).toStrictEqual({ status: false, - error: new TypeError('fn parameter is not a function') + error: new TypeError( + "taskFunction object 'taskFunction' property 'undefined' is not a function" + ), + }) + expect(worker.addTaskFunction('fn2', { taskFunction: 0 })).toStrictEqual({ + status: false, + error: new TypeError( + "taskFunction object 'taskFunction' property '0' is not a function" + ), + }) + expect(worker.addTaskFunction('fn3', { taskFunction: '' })).toStrictEqual({ + status: false, + error: new TypeError( + "taskFunction object 'taskFunction' property '' is not a function" + ), + }) + expect( + worker.addTaskFunction('fn2', { taskFunction: () => {}, priority: -21 }) + ).toStrictEqual({ + status: false, + error: new RangeError("Property 'priority' must be between -20 and 19"), + }) + expect( + worker.addTaskFunction('fn3', { taskFunction: () => {}, priority: 20 }) + ).toStrictEqual({ + status: false, + error: new RangeError("Property 'priority' must be between -20 and 19"), + }) + expect( + worker.addTaskFunction('fn2', { + taskFunction: () => {}, + strategy: 'invalidStrategy', + }) + ).toStrictEqual({ + status: false, + error: new Error("Invalid worker choice strategy 'invalidStrategy'"), + }) + expect(worker.taskFunctions.get(DEFAULT_TASK_NAME)).toStrictEqual({ + taskFunction: expect.any(Function), + }) + expect(worker.taskFunctions.get('fn1')).toStrictEqual({ + taskFunction: expect.any(Function), }) - expect(worker.taskFunctions.get(DEFAULT_TASK_NAME)).toBeInstanceOf(Function) - expect(worker.taskFunctions.get('fn1')).toBeInstanceOf(Function) expect(worker.taskFunctions.size).toBe(2) expect(worker.taskFunctions.get(DEFAULT_TASK_NAME)).toStrictEqual( worker.taskFunctions.get('fn1') @@ -249,27 +357,39 @@ describe('Abstract worker test suite', () => { status: false, error: new Error( 'Cannot add a task function with the default reserved name' - ) + ), }) worker.addTaskFunction('fn2', fn2) - expect(worker.taskFunctions.get(DEFAULT_TASK_NAME)).toBeInstanceOf(Function) - expect(worker.taskFunctions.get('fn1')).toBeInstanceOf(Function) - expect(worker.taskFunctions.get('fn2')).toBeInstanceOf(Function) + expect(worker.taskFunctions.get(DEFAULT_TASK_NAME)).toStrictEqual({ + taskFunction: expect.any(Function), + }) + expect(worker.taskFunctions.get('fn1')).toStrictEqual({ + taskFunction: expect.any(Function), + }) + expect(worker.taskFunctions.get('fn2')).toStrictEqual({ + taskFunction: expect.any(Function), + }) expect(worker.taskFunctions.size).toBe(3) expect(worker.taskFunctions.get(DEFAULT_TASK_NAME)).toStrictEqual( worker.taskFunctions.get('fn1') ) worker.addTaskFunction('fn1', fn1Replacement) - expect(worker.taskFunctions.get(DEFAULT_TASK_NAME)).toBeInstanceOf(Function) - expect(worker.taskFunctions.get('fn1')).toBeInstanceOf(Function) - expect(worker.taskFunctions.get('fn2')).toBeInstanceOf(Function) + expect(worker.taskFunctions.get(DEFAULT_TASK_NAME)).toStrictEqual({ + taskFunction: expect.any(Function), + }) + expect(worker.taskFunctions.get('fn1')).toStrictEqual({ + taskFunction: expect.any(Function), + }) + expect(worker.taskFunctions.get('fn2')).toStrictEqual({ + taskFunction: expect.any(Function), + }) expect(worker.taskFunctions.size).toBe(3) expect(worker.taskFunctions.get(DEFAULT_TASK_NAME)).toStrictEqual( worker.taskFunctions.get('fn1') ) }) - it('Verify that listTaskFunctionNames() is working', () => { + it('Verify that listTaskFunctionsProperties() is working', () => { const fn1 = () => { return 1 } @@ -277,10 +397,10 @@ describe('Abstract worker test suite', () => { return 2 } const worker = new ClusterWorker({ fn1, fn2 }) - expect(worker.listTaskFunctionNames()).toStrictEqual([ - DEFAULT_TASK_NAME, - 'fn1', - 'fn2' + expect(worker.listTaskFunctionsProperties()).toStrictEqual([ + { name: DEFAULT_TASK_NAME }, + { name: 'fn1' }, + { name: 'fn2' }, ]) }) @@ -294,15 +414,21 @@ describe('Abstract worker test suite', () => { const worker = new ThreadWorker({ fn1, fn2 }) expect(worker.setDefaultTaskFunction(0, fn1)).toStrictEqual({ status: false, - error: new TypeError('name parameter is not a string') + error: new TypeError('name parameter is not a string'), }) expect(worker.setDefaultTaskFunction('', fn1)).toStrictEqual({ status: false, - error: new TypeError('name parameter is an empty string') + error: new TypeError('name parameter is an empty string'), + }) + expect(worker.taskFunctions.get(DEFAULT_TASK_NAME)).toStrictEqual({ + taskFunction: expect.any(Function), + }) + expect(worker.taskFunctions.get('fn1')).toStrictEqual({ + taskFunction: expect.any(Function), + }) + expect(worker.taskFunctions.get('fn2')).toStrictEqual({ + taskFunction: expect.any(Function), }) - expect(worker.taskFunctions.get(DEFAULT_TASK_NAME)).toBeInstanceOf(Function) - expect(worker.taskFunctions.get('fn1')).toBeInstanceOf(Function) - expect(worker.taskFunctions.get('fn2')).toBeInstanceOf(Function) expect(worker.taskFunctions.size).toBe(3) expect(worker.taskFunctions.get(DEFAULT_TASK_NAME)).toStrictEqual( worker.taskFunctions.get('fn1') @@ -311,13 +437,13 @@ describe('Abstract worker test suite', () => { status: false, error: new Error( 'Cannot set the default task function reserved name as the default task function' - ) + ), }) expect(worker.setDefaultTaskFunction('fn3')).toStrictEqual({ status: false, error: new Error( 'Cannot set the default task function to a non-existing task function' - ) + ), }) worker.setDefaultTaskFunction('fn1') expect(worker.taskFunctions.get(DEFAULT_TASK_NAME)).toStrictEqual(