X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;f=tests%2Fpools%2Fabstract-pool.test.mjs;h=ecb1c5670e095a4f89678f8a511a99721084d3ea;hb=5993cfc5a031fd2d64f644505db125bc1d28b05b;hp=e8dfcb8acbdbf6f1b10ea5a24da3516703e8fd83;hpb=2107bc577c9620f6140183691f8038e71304489b;p=poolifier.git diff --git a/tests/pools/abstract-pool.test.mjs b/tests/pools/abstract-pool.test.mjs index e8dfcb8a..ecb1c567 100644 --- a/tests/pools/abstract-pool.test.mjs +++ b/tests/pools/abstract-pool.test.mjs @@ -8,7 +8,7 @@ import { fileURLToPath } from 'node:url' import { expect } from 'expect' import { restore, stub } from 'sinon' -import { CircularArray } from '../../lib/circular-array.cjs' +import { CircularBuffer } from '../../lib/circular-buffer.cjs' import { DynamicClusterPool, DynamicThreadPool, @@ -17,10 +17,10 @@ import { PoolEvents, PoolTypes, WorkerChoiceStrategies, - WorkerTypes + WorkerTypes, } from '../../lib/index.cjs' import { WorkerNode } from '../../lib/pools/worker-node.cjs' -import { PriorityQueue } from '../../lib/priority-queue.cjs' +import { defaultBucketSize, PriorityQueue } from '../../lib/priority-queue.cjs' import { DEFAULT_TASK_NAME } from '../../lib/utils.cjs' import { waitPoolEvents } from '../test-utils.cjs' @@ -58,7 +58,7 @@ describe('Abstract pool test suite', () => { numberOfWorkers, './tests/worker-files/thread/testWorker.mjs', { - errorHandler: e => console.error(e) + errorHandler: e => console.error(e), } ) ).toThrow( @@ -230,7 +230,7 @@ describe('Abstract pool test suite', () => { enableEvents: true, restartWorkerOnError: true, enableTasksQueue: false, - workerChoiceStrategy: WorkerChoiceStrategies.ROUND_ROBIN + workerChoiceStrategy: WorkerChoiceStrategies.ROUND_ROBIN, }) for (const [, workerChoiceStrategy] of pool.workerChoiceStrategiesContext .workerChoiceStrategies) { @@ -240,8 +240,8 @@ describe('Abstract pool test suite', () => { elu: { median: false }, weights: expect.objectContaining({ 0: expect.any(Number), - [pool.info.maxSize - 1]: expect.any(Number) - }) + [pool.info.maxSize - 1]: expect.any(Number), + }), }) } await pool.destroy() @@ -253,7 +253,7 @@ describe('Abstract pool test suite', () => { workerChoiceStrategy: WorkerChoiceStrategies.LEAST_USED, workerChoiceStrategyOptions: { runTime: { median: true }, - weights: { 0: 300, 1: 200 } + weights: { 0: 300, 1: 200 }, }, enableEvents: false, restartWorkerOnError: false, @@ -262,7 +262,7 @@ describe('Abstract pool test suite', () => { messageHandler: testHandler, errorHandler: testHandler, onlineHandler: testHandler, - exitHandler: testHandler + exitHandler: testHandler, } ) expect(pool.emitter).toBeUndefined() @@ -276,17 +276,17 @@ describe('Abstract pool test suite', () => { size: Math.pow(numberOfWorkers, 2), taskStealing: true, tasksStealingOnBackPressure: false, - tasksFinishedTimeout: 2000 + tasksFinishedTimeout: 2000, }, workerChoiceStrategy: WorkerChoiceStrategies.LEAST_USED, workerChoiceStrategyOptions: { runTime: { median: true }, - weights: { 0: 300, 1: 200 } + weights: { 0: 300, 1: 200 }, }, onlineHandler: testHandler, messageHandler: testHandler, errorHandler: testHandler, - exitHandler: testHandler + exitHandler: testHandler, }) for (const [, workerChoiceStrategy] of pool.workerChoiceStrategiesContext .workerChoiceStrategies) { @@ -294,7 +294,7 @@ describe('Abstract pool test suite', () => { runTime: { median: true }, waitTime: { median: false }, elu: { median: false }, - weights: { 0: 300, 1: 200 } + weights: { 0: 300, 1: 200 }, }) } await pool.destroy() @@ -307,7 +307,7 @@ describe('Abstract pool test suite', () => { numberOfWorkers, './tests/worker-files/thread/testWorker.mjs', { - workerChoiceStrategy: 'invalidStrategy' + workerChoiceStrategy: 'invalidStrategy', } ) ).toThrow(new Error("Invalid worker choice strategy 'invalidStrategy'")) @@ -317,7 +317,7 @@ describe('Abstract pool test suite', () => { numberOfWorkers, './tests/worker-files/thread/testWorker.mjs', { - workerChoiceStrategyOptions: { weights: {} } + workerChoiceStrategyOptions: { weights: {} }, } ) ).toThrow( @@ -331,7 +331,7 @@ describe('Abstract pool test suite', () => { numberOfWorkers, './tests/worker-files/thread/testWorker.mjs', { - workerChoiceStrategyOptions: { measurement: 'invalidMeasurement' } + workerChoiceStrategyOptions: { measurement: 'invalidMeasurement' }, } ) ).toThrow( @@ -346,7 +346,7 @@ describe('Abstract pool test suite', () => { './tests/worker-files/thread/testWorker.mjs', { enableTasksQueue: true, - tasksQueueOptions: 'invalidTasksQueueOptions' + tasksQueueOptions: 'invalidTasksQueueOptions', } ) ).toThrow( @@ -359,7 +359,7 @@ describe('Abstract pool test suite', () => { './tests/worker-files/thread/testWorker.mjs', { enableTasksQueue: true, - tasksQueueOptions: { concurrency: 0 } + tasksQueueOptions: { concurrency: 0 }, } ) ).toThrow( @@ -374,7 +374,7 @@ describe('Abstract pool test suite', () => { './tests/worker-files/thread/testWorker.mjs', { enableTasksQueue: true, - tasksQueueOptions: { concurrency: -1 } + tasksQueueOptions: { concurrency: -1 }, } ) ).toThrow( @@ -389,7 +389,7 @@ describe('Abstract pool test suite', () => { './tests/worker-files/thread/testWorker.mjs', { enableTasksQueue: true, - tasksQueueOptions: { concurrency: 0.2 } + tasksQueueOptions: { concurrency: 0.2 }, } ) ).toThrow( @@ -402,7 +402,7 @@ describe('Abstract pool test suite', () => { './tests/worker-files/thread/testWorker.mjs', { enableTasksQueue: true, - tasksQueueOptions: { size: 0 } + tasksQueueOptions: { size: 0 }, } ) ).toThrow( @@ -417,7 +417,7 @@ describe('Abstract pool test suite', () => { './tests/worker-files/thread/testWorker.mjs', { enableTasksQueue: true, - tasksQueueOptions: { size: -1 } + tasksQueueOptions: { size: -1 }, } ) ).toThrow( @@ -432,7 +432,7 @@ describe('Abstract pool test suite', () => { './tests/worker-files/thread/testWorker.mjs', { enableTasksQueue: true, - tasksQueueOptions: { size: 0.2 } + tasksQueueOptions: { size: 0.2 }, } ) ).toThrow( @@ -455,8 +455,8 @@ describe('Abstract pool test suite', () => { elu: { median: false }, weights: expect.objectContaining({ 0: expect.any(Number), - [pool.info.maxSize - 1]: expect.any(Number) - }) + [pool.info.maxSize - 1]: expect.any(Number), + }), }) } expect( @@ -465,26 +465,26 @@ describe('Abstract pool test suite', () => { runTime: { aggregate: true, average: true, - median: false + median: false, }, waitTime: { aggregate: true, average: true, - median: false + median: false, }, elu: { aggregate: true, average: true, - median: false - } + median: false, + }, }) pool.setWorkerChoiceStrategyOptions({ runTime: { median: true }, - elu: { median: true } + elu: { median: true }, }) expect(pool.opts.workerChoiceStrategyOptions).toStrictEqual({ runTime: { median: true }, - elu: { median: true } + elu: { median: true }, }) for (const [, workerChoiceStrategy] of pool.workerChoiceStrategiesContext .workerChoiceStrategies) { @@ -494,8 +494,8 @@ describe('Abstract pool test suite', () => { elu: { median: true }, weights: expect.objectContaining({ 0: expect.any(Number), - [pool.info.maxSize - 1]: expect.any(Number) - }) + [pool.info.maxSize - 1]: expect.any(Number), + }), }) } expect( @@ -504,26 +504,26 @@ describe('Abstract pool test suite', () => { runTime: { aggregate: true, average: false, - median: true + median: true, }, waitTime: { aggregate: true, average: true, - median: false + median: false, }, elu: { aggregate: true, average: false, - median: true - } + median: true, + }, }) pool.setWorkerChoiceStrategyOptions({ runTime: { median: false }, - elu: { median: false } + elu: { median: false }, }) expect(pool.opts.workerChoiceStrategyOptions).toStrictEqual({ runTime: { median: false }, - elu: { median: false } + elu: { median: false }, }) for (const [, workerChoiceStrategy] of pool.workerChoiceStrategiesContext .workerChoiceStrategies) { @@ -533,8 +533,8 @@ describe('Abstract pool test suite', () => { elu: { median: false }, weights: expect.objectContaining({ 0: expect.any(Number), - [pool.info.maxSize - 1]: expect.any(Number) - }) + [pool.info.maxSize - 1]: expect.any(Number), + }), }) } expect( @@ -543,18 +543,18 @@ describe('Abstract pool test suite', () => { runTime: { aggregate: true, average: true, - median: false + median: false, }, waitTime: { aggregate: true, average: true, - median: false + median: false, }, elu: { aggregate: true, average: true, - median: false - } + median: false, + }, }) expect(() => pool.setWorkerChoiceStrategyOptions('invalidWorkerChoiceStrategyOptions') @@ -592,7 +592,7 @@ describe('Abstract pool test suite', () => { size: Math.pow(numberOfWorkers, 2), taskStealing: true, tasksStealingOnBackPressure: false, - tasksFinishedTimeout: 2000 + tasksFinishedTimeout: 2000, }) pool.enableTasksQueue(true, { concurrency: 2 }) expect(pool.opts.enableTasksQueue).toBe(true) @@ -601,7 +601,7 @@ describe('Abstract pool test suite', () => { size: Math.pow(numberOfWorkers, 2), taskStealing: true, tasksStealingOnBackPressure: false, - tasksFinishedTimeout: 2000 + tasksFinishedTimeout: 2000, }) pool.enableTasksQueue(false) expect(pool.opts.enableTasksQueue).toBe(false) @@ -620,7 +620,7 @@ describe('Abstract pool test suite', () => { size: Math.pow(numberOfWorkers, 2), taskStealing: true, tasksStealingOnBackPressure: false, - tasksFinishedTimeout: 2000 + tasksFinishedTimeout: 2000, }) for (const workerNode of pool.workerNodes) { expect(workerNode.tasksQueueBackPressureSize).toBe( @@ -632,14 +632,14 @@ describe('Abstract pool test suite', () => { size: 2, taskStealing: false, tasksStealingOnBackPressure: false, - tasksFinishedTimeout: 3000 + tasksFinishedTimeout: 3000, }) expect(pool.opts.tasksQueueOptions).toStrictEqual({ concurrency: 2, size: 2, taskStealing: false, tasksStealingOnBackPressure: false, - tasksFinishedTimeout: 3000 + tasksFinishedTimeout: 3000, }) for (const workerNode of pool.workerNodes) { expect(workerNode.tasksQueueBackPressureSize).toBe( @@ -649,14 +649,14 @@ describe('Abstract pool test suite', () => { pool.setTasksQueueOptions({ concurrency: 1, taskStealing: true, - tasksStealingOnBackPressure: true + tasksStealingOnBackPressure: true, }) expect(pool.opts.tasksQueueOptions).toStrictEqual({ concurrency: 1, size: Math.pow(numberOfWorkers, 2), taskStealing: true, tasksStealingOnBackPressure: true, - tasksFinishedTimeout: 2000 + tasksFinishedTimeout: 2000, }) for (const workerNode of pool.workerNodes) { expect(workerNode.tasksQueueBackPressureSize).toBe( @@ -715,7 +715,7 @@ describe('Abstract pool test suite', () => { busyWorkerNodes: 0, executedTasks: 0, executingTasks: 0, - failedTasks: 0 + failedTasks: 0, }) await pool.destroy() pool = new DynamicClusterPool( @@ -738,7 +738,7 @@ describe('Abstract pool test suite', () => { busyWorkerNodes: 0, executedTasks: 0, executingTasks: 0, - failedTasks: 0 + failedTasks: 0, }) await pool.destroy() }) @@ -758,22 +758,22 @@ describe('Abstract pool test suite', () => { maxQueued: 0, sequentiallyStolen: 0, stolen: 0, - failed: 0 + failed: 0, }, runTime: { - history: new CircularArray() + history: expect.any(CircularBuffer), }, waitTime: { - history: new CircularArray() + history: expect.any(CircularBuffer), }, elu: { idle: { - history: new CircularArray() + history: expect.any(CircularBuffer), }, active: { - history: new CircularArray() - } - } + history: expect.any(CircularBuffer), + }, + }, }) } await pool.destroy() @@ -789,7 +789,8 @@ describe('Abstract pool test suite', () => { expect(workerNode.tasksQueue).toBeInstanceOf(PriorityQueue) expect(workerNode.tasksQueue.size).toBe(0) expect(workerNode.tasksQueue.maxSize).toBe(0) - expect(workerNode.tasksQueue.bucketSize).toBe(numberOfWorkers * 2) + expect(workerNode.tasksQueue.bucketSize).toBe(defaultBucketSize) + expect(workerNode.tasksQueue.enablePriority).toBe(false) } await pool.destroy() pool = new DynamicThreadPool( @@ -802,7 +803,8 @@ describe('Abstract pool test suite', () => { expect(workerNode.tasksQueue).toBeInstanceOf(PriorityQueue) expect(workerNode.tasksQueue.size).toBe(0) expect(workerNode.tasksQueue.maxSize).toBe(0) - expect(workerNode.tasksQueue.bucketSize).toBe(numberOfWorkers * 2) + expect(workerNode.tasksQueue.bucketSize).toBe(defaultBucketSize) + expect(workerNode.tasksQueue.enablePriority).toBe(false) } await pool.destroy() }) @@ -820,7 +822,7 @@ describe('Abstract pool test suite', () => { dynamic: false, ready: true, stealing: false, - backPressure: false + backPressure: false, }) } await pool.destroy() @@ -837,7 +839,7 @@ describe('Abstract pool test suite', () => { dynamic: false, ready: true, stealing: false, - backPressure: false + backPressure: false, }) } await pool.destroy() @@ -866,7 +868,7 @@ describe('Abstract pool test suite', () => { numberOfWorkers, './tests/worker-files/cluster/testWorker.cjs', { - startWorkers: false + startWorkers: false, } ) expect(pool.info.started).toBe(false) @@ -930,22 +932,22 @@ describe('Abstract pool test suite', () => { maxQueued: 0, sequentiallyStolen: 0, stolen: 0, - failed: 0 + failed: 0, }, runTime: { - history: expect.any(CircularArray) + history: expect.any(CircularBuffer), }, waitTime: { - history: expect.any(CircularArray) + history: expect.any(CircularBuffer), }, elu: { idle: { - history: expect.any(CircularArray) + history: expect.any(CircularBuffer), }, active: { - history: expect.any(CircularArray) - } - } + history: expect.any(CircularBuffer), + }, + }, }) } await Promise.all(promises) @@ -958,22 +960,22 @@ describe('Abstract pool test suite', () => { maxQueued: 0, sequentiallyStolen: 0, stolen: 0, - failed: 0 + failed: 0, }, runTime: { - history: expect.any(CircularArray) + history: expect.any(CircularBuffer), }, waitTime: { - history: expect.any(CircularArray) + history: expect.any(CircularBuffer), }, elu: { idle: { - history: expect.any(CircularArray) + history: expect.any(CircularBuffer), }, active: { - history: expect.any(CircularArray) - } - } + history: expect.any(CircularBuffer), + }, + }, }) } await pool.destroy() @@ -1000,31 +1002,27 @@ describe('Abstract pool test suite', () => { maxQueued: 0, sequentiallyStolen: 0, stolen: 0, - failed: 0 + failed: 0, }, runTime: { - history: expect.any(CircularArray) + history: expect.any(CircularBuffer), }, waitTime: { - history: expect.any(CircularArray) + history: expect.any(CircularBuffer), }, elu: { idle: { - history: expect.any(CircularArray) + history: expect.any(CircularBuffer), }, active: { - history: expect.any(CircularArray) - } - } + history: expect.any(CircularBuffer), + }, + }, }) expect(workerNode.usage.tasks.executed).toBeGreaterThan(0) expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual( numberOfWorkers * maxMultiplier ) - expect(workerNode.usage.runTime.history.length).toBe(0) - expect(workerNode.usage.waitTime.history.length).toBe(0) - expect(workerNode.usage.elu.idle.history.length).toBe(0) - expect(workerNode.usage.elu.active.history.length).toBe(0) } pool.setWorkerChoiceStrategy(WorkerChoiceStrategies.FAIR_SHARE) for (const workerNode of pool.workerNodes) { @@ -1036,31 +1034,27 @@ describe('Abstract pool test suite', () => { maxQueued: 0, sequentiallyStolen: 0, stolen: 0, - failed: 0 + failed: 0, }, runTime: { - history: expect.any(CircularArray) + history: expect.any(CircularBuffer), }, waitTime: { - history: expect.any(CircularArray) + history: expect.any(CircularBuffer), }, elu: { idle: { - history: expect.any(CircularArray) + history: expect.any(CircularBuffer), }, active: { - history: expect.any(CircularArray) - } - } + history: expect.any(CircularBuffer), + }, + }, }) expect(workerNode.usage.tasks.executed).toBeGreaterThan(0) expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual( numberOfWorkers * maxMultiplier ) - expect(workerNode.usage.runTime.history.length).toBe(0) - expect(workerNode.usage.waitTime.history.length).toBe(0) - expect(workerNode.usage.elu.idle.history.length).toBe(0) - expect(workerNode.usage.elu.active.history.length).toBe(0) } await pool.destroy() }) @@ -1096,7 +1090,7 @@ describe('Abstract pool test suite', () => { busyWorkerNodes: expect.any(Number), executedTasks: expect.any(Number), executingTasks: expect.any(Number), - failedTasks: expect.any(Number) + failedTasks: expect.any(Number), }) await pool.destroy() }) @@ -1137,7 +1131,7 @@ describe('Abstract pool test suite', () => { busyWorkerNodes: expect.any(Number), executedTasks: expect.any(Number), executingTasks: expect.any(Number), - failedTasks: expect.any(Number) + failedTasks: expect.any(Number), }) await pool.destroy() }) @@ -1177,7 +1171,7 @@ describe('Abstract pool test suite', () => { busyWorkerNodes: expect.any(Number), executedTasks: expect.any(Number), executingTasks: expect.any(Number), - failedTasks: expect.any(Number) + failedTasks: expect.any(Number), }) await pool.destroy() }) @@ -1187,7 +1181,7 @@ describe('Abstract pool test suite', () => { numberOfWorkers, './tests/worker-files/thread/testWorker.mjs', { - enableTasksQueue: true + enableTasksQueue: true, } ) stub(pool, 'hasBackPressure').returns(true) @@ -1225,7 +1219,7 @@ describe('Abstract pool test suite', () => { queuedTasks: expect.any(Number), backPressure: true, stolenTasks: expect.any(Number), - failedTasks: expect.any(Number) + failedTasks: expect.any(Number), }) expect(pool.hasBackPressure.callCount).toBeGreaterThanOrEqual(7) await pool.destroy() @@ -1238,7 +1232,7 @@ describe('Abstract pool test suite', () => { './tests/worker-files/thread/asyncWorker.mjs', { enableTasksQueue: true, - tasksQueueOptions: { tasksFinishedTimeout } + tasksQueueOptions: { tasksFinishedTimeout }, } ) const maxMultiplier = 4 @@ -1267,7 +1261,7 @@ describe('Abstract pool test suite', () => { './tests/worker-files/thread/asyncWorker.mjs', { enableTasksQueue: true, - tasksQueueOptions: { tasksFinishedTimeout } + tasksQueueOptions: { tasksFinishedTimeout }, } ) const maxMultiplier = 4 @@ -1309,7 +1303,7 @@ describe('Abstract pool test suite', () => { }, promiseResolve () { if (executionAsyncId() === taskAsyncId) resolveCalls++ - } + }, }) const pool = new FixedThreadPool( numberOfWorkers, @@ -1385,7 +1379,7 @@ describe('Abstract pool test suite', () => { await expect( dynamicThreadPool.addTaskFunction('test', { taskFunction: () => {}, - priority: -21 + priority: -21, }) ).rejects.toThrow( new RangeError("Property 'priority' must be between -20 and 19") @@ -1393,7 +1387,7 @@ describe('Abstract pool test suite', () => { await expect( dynamicThreadPool.addTaskFunction('test', { taskFunction: () => {}, - priority: 20 + priority: 20, }) ).rejects.toThrow( new RangeError("Property 'priority' must be between -20 and 19") @@ -1401,17 +1395,17 @@ describe('Abstract pool test suite', () => { await expect( dynamicThreadPool.addTaskFunction('test', { taskFunction: () => {}, - strategy: 'invalidStrategy' + strategy: 'invalidStrategy', }) ).rejects.toThrow( new Error("Invalid worker choice strategy 'invalidStrategy'") ) expect(dynamicThreadPool.listTaskFunctionsProperties()).toStrictEqual([ { name: DEFAULT_TASK_NAME }, - { name: 'test' } + { name: 'test' }, ]) expect([ - ...dynamicThreadPool.workerChoiceStrategiesContext.workerChoiceStrategies.keys() + ...dynamicThreadPool.workerChoiceStrategiesContext.workerChoiceStrategies.keys(), ]).toStrictEqual([WorkerChoiceStrategies.ROUND_ROBIN]) const echoTaskFunction = data => { return data @@ -1419,24 +1413,24 @@ describe('Abstract pool test suite', () => { await expect( dynamicThreadPool.addTaskFunction('echo', { taskFunction: echoTaskFunction, - strategy: WorkerChoiceStrategies.LEAST_ELU + strategy: WorkerChoiceStrategies.LEAST_ELU, }) ).resolves.toBe(true) expect(dynamicThreadPool.taskFunctions.size).toBe(1) expect(dynamicThreadPool.taskFunctions.get('echo')).toStrictEqual({ taskFunction: echoTaskFunction, - strategy: WorkerChoiceStrategies.LEAST_ELU + strategy: WorkerChoiceStrategies.LEAST_ELU, }) expect([ - ...dynamicThreadPool.workerChoiceStrategiesContext.workerChoiceStrategies.keys() + ...dynamicThreadPool.workerChoiceStrategiesContext.workerChoiceStrategies.keys(), ]).toStrictEqual([ WorkerChoiceStrategies.ROUND_ROBIN, - WorkerChoiceStrategies.LEAST_ELU + WorkerChoiceStrategies.LEAST_ELU, ]) expect(dynamicThreadPool.listTaskFunctionsProperties()).toStrictEqual([ { name: DEFAULT_TASK_NAME }, { name: 'test' }, - { name: 'echo', strategy: WorkerChoiceStrategies.LEAST_ELU } + { name: 'echo', strategy: WorkerChoiceStrategies.LEAST_ELU }, ]) const taskFunctionData = { test: 'test' } const echoResult = await dynamicThreadPool.execute(taskFunctionData, 'echo') @@ -1449,22 +1443,22 @@ describe('Abstract pool test suite', () => { queued: 0, sequentiallyStolen: 0, stolen: 0, - failed: 0 + failed: 0, }, runTime: { - history: new CircularArray() + history: expect.any(CircularBuffer), }, waitTime: { - history: new CircularArray() + history: expect.any(CircularBuffer), }, elu: expect.objectContaining({ idle: expect.objectContaining({ - history: expect.any(CircularArray) + history: expect.any(CircularBuffer), }), active: expect.objectContaining({ - history: expect.any(CircularArray) - }) - }) + history: expect.any(CircularBuffer), + }), + }), }) expect( workerNode.getTaskFunctionWorkerUsage('echo').tasks.executed @@ -1519,7 +1513,7 @@ describe('Abstract pool test suite', () => { await waitPoolEvents(dynamicThreadPool, PoolEvents.ready, 1) expect(dynamicThreadPool.listTaskFunctionsProperties()).toStrictEqual([ { name: DEFAULT_TASK_NAME }, - { name: 'test' } + { name: 'test' }, ]) await expect(dynamicThreadPool.removeTaskFunction('test')).rejects.toThrow( new Error('Cannot remove a task function not handled on the pool side') @@ -1529,23 +1523,23 @@ describe('Abstract pool test suite', () => { } await dynamicThreadPool.addTaskFunction('echo', { taskFunction: echoTaskFunction, - strategy: WorkerChoiceStrategies.LEAST_ELU + strategy: WorkerChoiceStrategies.LEAST_ELU, }) expect(dynamicThreadPool.taskFunctions.size).toBe(1) expect(dynamicThreadPool.taskFunctions.get('echo')).toStrictEqual({ taskFunction: echoTaskFunction, - strategy: WorkerChoiceStrategies.LEAST_ELU + strategy: WorkerChoiceStrategies.LEAST_ELU, }) expect([ - ...dynamicThreadPool.workerChoiceStrategiesContext.workerChoiceStrategies.keys() + ...dynamicThreadPool.workerChoiceStrategiesContext.workerChoiceStrategies.keys(), ]).toStrictEqual([ WorkerChoiceStrategies.ROUND_ROBIN, - WorkerChoiceStrategies.LEAST_ELU + WorkerChoiceStrategies.LEAST_ELU, ]) expect(dynamicThreadPool.listTaskFunctionsProperties()).toStrictEqual([ { name: DEFAULT_TASK_NAME }, { name: 'test' }, - { name: 'echo', strategy: WorkerChoiceStrategies.LEAST_ELU } + { name: 'echo', strategy: WorkerChoiceStrategies.LEAST_ELU }, ]) await expect(dynamicThreadPool.removeTaskFunction('echo')).resolves.toBe( true @@ -1553,11 +1547,11 @@ describe('Abstract pool test suite', () => { expect(dynamicThreadPool.taskFunctions.size).toBe(0) expect(dynamicThreadPool.taskFunctions.get('echo')).toBeUndefined() expect([ - ...dynamicThreadPool.workerChoiceStrategiesContext.workerChoiceStrategies.keys() + ...dynamicThreadPool.workerChoiceStrategiesContext.workerChoiceStrategies.keys(), ]).toStrictEqual([WorkerChoiceStrategies.ROUND_ROBIN]) expect(dynamicThreadPool.listTaskFunctionsProperties()).toStrictEqual([ { name: DEFAULT_TASK_NAME }, - { name: 'test' } + { name: 'test' }, ]) await dynamicThreadPool.destroy() }) @@ -1573,7 +1567,7 @@ describe('Abstract pool test suite', () => { { name: DEFAULT_TASK_NAME }, { name: 'jsonIntegerSerialization' }, { name: 'factorial' }, - { name: 'fibonacci' } + { name: 'fibonacci' }, ]) await dynamicThreadPool.destroy() const fixedClusterPool = new FixedClusterPool( @@ -1585,7 +1579,7 @@ describe('Abstract pool test suite', () => { { name: DEFAULT_TASK_NAME }, { name: 'jsonIntegerSerialization' }, { name: 'factorial' }, - { name: 'fibonacci' } + { name: 'fibonacci' }, ]) await fixedClusterPool.destroy() }) @@ -1621,7 +1615,7 @@ describe('Abstract pool test suite', () => { { name: DEFAULT_TASK_NAME }, { name: 'jsonIntegerSerialization' }, { name: 'factorial' }, - { name: 'fibonacci' } + { name: 'fibonacci' }, ]) await expect( dynamicThreadPool.setDefaultTaskFunction('factorial') @@ -1630,7 +1624,7 @@ describe('Abstract pool test suite', () => { { name: DEFAULT_TASK_NAME }, { name: 'factorial' }, { name: 'jsonIntegerSerialization' }, - { name: 'fibonacci' } + { name: 'fibonacci' }, ]) await expect( dynamicThreadPool.setDefaultTaskFunction('fibonacci') @@ -1639,7 +1633,7 @@ describe('Abstract pool test suite', () => { { name: DEFAULT_TASK_NAME }, { name: 'fibonacci' }, { name: 'jsonIntegerSerialization' }, - { name: 'factorial' } + { name: 'factorial' }, ]) await dynamicThreadPool.destroy() }) @@ -1666,9 +1660,11 @@ describe('Abstract pool test suite', () => { { name: DEFAULT_TASK_NAME }, { name: 'jsonIntegerSerialization' }, { name: 'factorial' }, - { name: 'fibonacci' } + { name: 'fibonacci' }, ]) expect(workerNode.taskFunctionsUsage.size).toBe(3) + expect(workerNode.usage.tasks.executed).toBeGreaterThan(0) + expect(workerNode.tasksQueue.enablePriority).toBe(false) for (const taskFunctionProperties of pool.listTaskFunctionsProperties()) { expect( workerNode.getTaskFunctionWorkerUsage(taskFunctionProperties.name) @@ -1679,22 +1675,130 @@ describe('Abstract pool test suite', () => { failed: 0, queued: 0, sequentiallyStolen: 0, - stolen: 0 + stolen: 0, }, runTime: { - history: expect.any(CircularArray) + history: expect.any(CircularBuffer), }, waitTime: { - history: expect.any(CircularArray) + history: expect.any(CircularBuffer), }, elu: { idle: { - history: expect.any(CircularArray) + history: expect.any(CircularBuffer), }, active: { - history: expect.any(CircularArray) - } - } + history: expect.any(CircularBuffer), + }, + }, + }) + expect( + workerNode.getTaskFunctionWorkerUsage(taskFunctionProperties.name) + .tasks.executed + ).toBeGreaterThan(0) + } + expect( + workerNode.getTaskFunctionWorkerUsage(DEFAULT_TASK_NAME) + ).toStrictEqual( + workerNode.getTaskFunctionWorkerUsage( + workerNode.info.taskFunctionsProperties[1].name + ) + ) + } + await pool.destroy() + }) + + it('Verify that mapExecute() is working', async () => { + const pool = new DynamicThreadPool( + Math.floor(numberOfWorkers / 2), + numberOfWorkers, + './tests/worker-files/thread/testMultipleTaskFunctionsWorker.mjs' + ) + expect(() => pool.mapExecute()).toThrow(new TypeError('data argument must be a defined iterable')) + expect(() => pool.mapExecute(0)).toThrow(new TypeError('data argument must be an iterable')) + let results = await pool.mapExecute([{}, {}, {}, {}]) + expect(results).toStrictEqual([ + { ok: 1 }, + { ok: 1 }, + { ok: 1 }, + { ok: 1 }, + ]) + expect(pool.info.executingTasks).toBe(0) + expect(pool.info.executedTasks).toBe(4) + results = await pool.mapExecute([{ n: 10 }, { n: 20 }, { n: 30 }, { n: 40 }], 'factorial') + expect(results).toStrictEqual([ + 3628800, + 2432902008176640000, + 2.6525285981219103e+32, + 8.159152832478977e+47, + ]) + expect(pool.info.executingTasks).toBe(0) + expect(pool.info.executedTasks).toBe(8) + results = await pool.mapExecute(new Set([{ n: 10 }, { n: 20 }, { n: 30 }, { n: 40 }]), 'factorial') + expect(results).toStrictEqual([ + 3628800, + 2432902008176640000, + 2.6525285981219103e+32, + 8.159152832478977e+47, + ]) + expect(pool.info.executingTasks).toBe(0) + expect(pool.info.executedTasks).toBe(12) + await pool.destroy() + }) + + it('Verify that task function objects worker is working', async () => { + const pool = new DynamicThreadPool( + Math.floor(numberOfWorkers / 2), + numberOfWorkers, + './tests/worker-files/thread/testTaskFunctionObjectsWorker.mjs' + ) + const data = { n: 10 } + const result0 = await pool.execute(data) + expect(result0).toStrictEqual({ ok: 1 }) + const result1 = await pool.execute(data, 'jsonIntegerSerialization') + expect(result1).toStrictEqual({ ok: 1 }) + const result2 = await pool.execute(data, 'factorial') + expect(result2).toBe(3628800) + const result3 = await pool.execute(data, 'fibonacci') + expect(result3).toBe(55) + expect(pool.info.executingTasks).toBe(0) + expect(pool.info.executedTasks).toBe(4) + for (const workerNode of pool.workerNodes) { + expect(workerNode.info.taskFunctionsProperties).toStrictEqual([ + { name: DEFAULT_TASK_NAME }, + { name: 'jsonIntegerSerialization' }, + { name: 'factorial' }, + { name: 'fibonacci', priority: -5 }, + ]) + expect(workerNode.taskFunctionsUsage.size).toBe(3) + expect(workerNode.usage.tasks.executed).toBeGreaterThan(0) + expect(workerNode.tasksQueue.enablePriority).toBe(true) + for (const taskFunctionProperties of pool.listTaskFunctionsProperties()) { + expect( + workerNode.getTaskFunctionWorkerUsage(taskFunctionProperties.name) + ).toStrictEqual({ + tasks: { + executed: expect.any(Number), + executing: 0, + failed: 0, + queued: 0, + sequentiallyStolen: 0, + stolen: 0, + }, + runTime: { + history: expect.any(CircularBuffer), + }, + waitTime: { + history: expect.any(CircularBuffer), + }, + elu: { + idle: { + history: expect.any(CircularBuffer), + }, + active: { + history: expect.any(CircularBuffer), + }, + }, }) expect( workerNode.getTaskFunctionWorkerUsage(taskFunctionProperties.name) @@ -1736,7 +1840,7 @@ describe('Abstract pool test suite', () => { pool.sendTaskFunctionOperationToWorker(workerNodeKey, { taskFunctionOperation: 'add', taskFunctionProperties: { name: 'empty' }, - taskFunction: (() => {}).toString() + taskFunction: (() => {}).toString(), }) ).resolves.toBe(true) expect( @@ -1744,7 +1848,7 @@ describe('Abstract pool test suite', () => { ).toStrictEqual([ { name: DEFAULT_TASK_NAME }, { name: 'test' }, - { name: 'empty' } + { name: 'empty' }, ]) await pool.destroy() }) @@ -1759,14 +1863,14 @@ describe('Abstract pool test suite', () => { pool.sendTaskFunctionOperationToWorkers({ taskFunctionOperation: 'add', taskFunctionProperties: { name: 'empty' }, - taskFunction: (() => {}).toString() + taskFunction: (() => {}).toString(), }) ).resolves.toBe(true) for (const workerNode of pool.workerNodes) { expect(workerNode.info.taskFunctionsProperties).toStrictEqual([ { name: DEFAULT_TASK_NAME }, { name: 'test' }, - { name: 'empty' } + { name: 'empty' }, ]) } await pool.destroy()