X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;f=tests%2Fpools%2Fabstract%2Fabstract-pool.test.js;h=945ee8e7acf6417b2e6816e87bce1dffce48265d;hb=0fe39c9754981258c5330fa20fb5ad6141340b33;hp=0ffc9e124d27e5262508dcd66e88fb06e99e1847;hpb=4445abb25ec4c9d80985ca93c65762a6c892a852;p=poolifier.git diff --git a/tests/pools/abstract/abstract-pool.test.js b/tests/pools/abstract/abstract-pool.test.js index 0ffc9e12..945ee8e7 100644 --- a/tests/pools/abstract/abstract-pool.test.js +++ b/tests/pools/abstract/abstract-pool.test.js @@ -11,7 +11,8 @@ const { WorkerTypes } = require('../../../lib') const { CircularArray } = require('../../../lib/circular-array') -const { Queue } = require('../../../lib/queue') +const { Deque } = require('../../../lib/deque') +const { DEFAULT_TASK_NAME } = require('../../../lib/utils') const { version } = require('../../../package.json') const { waitPoolEvents } = require('../../test-utils') @@ -23,6 +24,10 @@ describe('Abstract pool test suite', () => { } } + afterEach(() => { + sinon.restore() + }) + it('Simulate pool creation from a non main thread/process', () => { expect( () => @@ -40,6 +45,17 @@ describe('Abstract pool test suite', () => { ) }) + it('Verify that pool statuses properties are set', async () => { + const pool = new FixedThreadPool( + numberOfWorkers, + './tests/worker-files/thread/testWorker.js' + ) + expect(pool.starting).toBe(false) + expect(pool.started).toBe(true) + await pool.destroy() + expect(pool.started).toBe(false) + }) + it('Verify that filePath is checked', () => { const expectedError = new Error( 'Please specify a file with a worker implementation' @@ -214,7 +230,7 @@ describe('Abstract pool test suite', () => { expect(pool.opts.enableTasksQueue).toBe(true) expect(pool.opts.tasksQueueOptions).toStrictEqual({ concurrency: 2, - queueMaxSize: 4 + size: 4 }) expect(pool.opts.workerChoiceStrategy).toBe( WorkerChoiceStrategies.LEAST_USED @@ -253,6 +269,38 @@ describe('Abstract pool test suite', () => { ).toThrowError( new Error("Invalid worker choice strategy 'invalidStrategy'") ) + expect( + () => + new FixedThreadPool( + numberOfWorkers, + './tests/worker-files/thread/testWorker.js', + { + workerChoiceStrategyOptions: { + choiceRetries: 'invalidChoiceRetries' + } + } + ) + ).toThrowError( + new TypeError( + 'Invalid worker choice strategy options: choice retries must be an integer' + ) + ) + expect( + () => + new FixedThreadPool( + numberOfWorkers, + './tests/worker-files/thread/testWorker.js', + { + workerChoiceStrategyOptions: { + choiceRetries: -1 + } + } + ) + ).toThrowError( + new RangeError( + "Invalid worker choice strategy options: choice retries '-1' must be greater or equal than zero" + ) + ) expect( () => new FixedThreadPool( @@ -281,6 +329,19 @@ describe('Abstract pool test suite', () => { "Invalid worker choice strategy options: invalid measurement 'invalidMeasurement'" ) ) + expect( + () => + new FixedThreadPool( + numberOfWorkers, + './tests/worker-files/thread/testWorker.js', + { + enableTasksQueue: true, + tasksQueueOptions: 'invalidTasksQueueOptions' + } + ) + ).toThrowError( + new TypeError('Invalid tasks queue options: must be a plain object') + ) expect( () => new FixedThreadPool( @@ -303,11 +364,13 @@ describe('Abstract pool test suite', () => { './tests/worker-files/thread/testWorker.js', { enableTasksQueue: true, - tasksQueueOptions: 'invalidTasksQueueOptions' + tasksQueueOptions: { concurrency: -1 } } ) ).toThrowError( - new TypeError('Invalid tasks queue options: must be a plain object') + new RangeError( + 'Invalid worker node tasks concurrency: -1 is a negative integer or zero' + ) ) expect( () => @@ -322,6 +385,64 @@ describe('Abstract pool test suite', () => { ).toThrowError( new TypeError('Invalid worker node tasks concurrency: must be an integer') ) + expect( + () => + new FixedThreadPool( + numberOfWorkers, + './tests/worker-files/thread/testWorker.js', + { + enableTasksQueue: true, + tasksQueueOptions: { queueMaxSize: 2 } + } + ) + ).toThrowError( + new Error( + 'Invalid tasks queue options: queueMaxSize is deprecated, please use size instead' + ) + ) + expect( + () => + new FixedThreadPool( + numberOfWorkers, + './tests/worker-files/thread/testWorker.js', + { + enableTasksQueue: true, + tasksQueueOptions: { size: 0 } + } + ) + ).toThrowError( + new RangeError( + 'Invalid worker node tasks queue size: 0 is a negative integer or zero' + ) + ) + expect( + () => + new FixedThreadPool( + numberOfWorkers, + './tests/worker-files/thread/testWorker.js', + { + enableTasksQueue: true, + tasksQueueOptions: { size: -1 } + } + ) + ).toThrowError( + new RangeError( + 'Invalid worker node tasks queue size: -1 is a negative integer or zero' + ) + ) + expect( + () => + new FixedThreadPool( + numberOfWorkers, + './tests/worker-files/thread/testWorker.js', + { + enableTasksQueue: true, + tasksQueueOptions: { size: 0.2 } + } + ) + ).toThrowError( + new TypeError('Invalid worker node tasks queue size: must be an integer') + ) }) it('Verify that pool worker choice strategy options can be set', async () => { @@ -465,6 +586,22 @@ describe('Abstract pool test suite', () => { 'Invalid worker choice strategy options: must be a plain object' ) ) + expect(() => + pool.setWorkerChoiceStrategyOptions({ + choiceRetries: 'invalidChoiceRetries' + }) + ).toThrowError( + new TypeError( + 'Invalid worker choice strategy options: choice retries must be an integer' + ) + ) + expect(() => + pool.setWorkerChoiceStrategyOptions({ choiceRetries: -1 }) + ).toThrowError( + new RangeError( + "Invalid worker choice strategy options: choice retries '-1' must be greater or equal than zero" + ) + ) expect(() => pool.setWorkerChoiceStrategyOptions({ weights: {} }) ).toThrowError( @@ -493,13 +630,13 @@ describe('Abstract pool test suite', () => { expect(pool.opts.enableTasksQueue).toBe(true) expect(pool.opts.tasksQueueOptions).toStrictEqual({ concurrency: 1, - queueMaxSize: 4 + size: 4 }) pool.enableTasksQueue(true, { concurrency: 2 }) expect(pool.opts.enableTasksQueue).toBe(true) expect(pool.opts.tasksQueueOptions).toStrictEqual({ concurrency: 2, - queueMaxSize: 4 + size: 4 }) pool.enableTasksQueue(false) expect(pool.opts.enableTasksQueue).toBe(false) @@ -515,12 +652,12 @@ describe('Abstract pool test suite', () => { ) expect(pool.opts.tasksQueueOptions).toStrictEqual({ concurrency: 1, - queueMaxSize: 4 + size: 4 }) pool.setTasksQueueOptions({ concurrency: 2 }) expect(pool.opts.tasksQueueOptions).toStrictEqual({ concurrency: 2, - queueMaxSize: 4 + size: 4 }) expect(() => pool.setTasksQueueOptions('invalidTasksQueueOptions') @@ -540,21 +677,24 @@ describe('Abstract pool test suite', () => { expect(() => pool.setTasksQueueOptions({ concurrency: 0.2 })).toThrowError( new TypeError('Invalid worker node tasks concurrency: must be an integer') ) - expect(() => pool.setTasksQueueOptions({ queueMaxSize: 0 })).toThrowError( - new RangeError( - 'Invalid worker node tasks queue max size: 0 is a negative integer or zero' + expect(() => pool.setTasksQueueOptions({ queueMaxSize: 2 })).toThrowError( + new Error( + 'Invalid tasks queue options: queueMaxSize is deprecated, please use size instead' ) ) - expect(() => pool.setTasksQueueOptions({ queueMaxSize: -1 })).toThrowError( + expect(() => pool.setTasksQueueOptions({ size: 0 })).toThrowError( new RangeError( - 'Invalid worker node tasks queue max size: -1 is a negative integer or zero' + 'Invalid worker node tasks queue size: 0 is a negative integer or zero' ) ) - expect(() => pool.setTasksQueueOptions({ queueMaxSize: 0.2 })).toThrowError( - new TypeError( - 'Invalid worker node tasks queue max size: must be an integer' + expect(() => pool.setTasksQueueOptions({ size: -1 })).toThrowError( + new RangeError( + 'Invalid worker node tasks queue size: -1 is a negative integer or zero' ) ) + expect(() => pool.setTasksQueueOptions({ size: 0.2 })).toThrowError( + new TypeError('Invalid worker node tasks queue size: must be an integer') + ) await pool.destroy() }) @@ -614,6 +754,7 @@ describe('Abstract pool test suite', () => { executing: 0, queued: 0, maxQueued: 0, + stolen: 0, failed: 0 }, runTime: { @@ -642,7 +783,7 @@ describe('Abstract pool test suite', () => { ) for (const workerNode of pool.workerNodes) { expect(workerNode.tasksQueue).toBeDefined() - expect(workerNode.tasksQueue).toBeInstanceOf(Queue) + expect(workerNode.tasksQueue).toBeInstanceOf(Deque) expect(workerNode.tasksQueue.size).toBe(0) expect(workerNode.tasksQueue.maxSize).toBe(0) } @@ -654,7 +795,7 @@ describe('Abstract pool test suite', () => { ) for (const workerNode of pool.workerNodes) { expect(workerNode.tasksQueue).toBeDefined() - expect(workerNode.tasksQueue).toBeInstanceOf(Queue) + expect(workerNode.tasksQueue).toBeInstanceOf(Deque) expect(workerNode.tasksQueue.size).toBe(0) expect(workerNode.tasksQueue.maxSize).toBe(0) } @@ -689,6 +830,29 @@ describe('Abstract pool test suite', () => { } }) + it('Verify that pool execute() arguments are checked', async () => { + const pool = new FixedClusterPool( + numberOfWorkers, + './tests/worker-files/cluster/testWorker.js' + ) + await expect(pool.execute(undefined, 0)).rejects.toThrowError( + new TypeError('name argument must be a string') + ) + await expect(pool.execute(undefined, '')).rejects.toThrowError( + new TypeError('name argument must not be an empty string') + ) + await expect(pool.execute(undefined, undefined, {})).rejects.toThrowError( + new TypeError('transferList argument must be an array') + ) + await expect(pool.execute(undefined, 'unknown')).rejects.toBe( + "Task function 'unknown' not found" + ) + await pool.destroy() + await expect(pool.execute(undefined, undefined, {})).rejects.toThrowError( + new Error('Cannot execute a task on destroyed pool') + ) + }) + it('Verify that pool worker tasks usage are computed', async () => { const pool = new FixedClusterPool( numberOfWorkers, @@ -706,6 +870,7 @@ describe('Abstract pool test suite', () => { executing: maxMultiplier, queued: 0, maxQueued: 0, + stolen: 0, failed: 0 }, runTime: { @@ -732,6 +897,7 @@ describe('Abstract pool test suite', () => { executing: 0, queued: 0, maxQueued: 0, + stolen: 0, failed: 0 }, runTime: { @@ -772,6 +938,7 @@ describe('Abstract pool test suite', () => { executing: 0, queued: 0, maxQueued: 0, + stolen: 0, failed: 0 }, runTime: { @@ -806,6 +973,7 @@ describe('Abstract pool test suite', () => { executing: 0, queued: 0, maxQueued: 0, + stolen: 0, failed: 0 }, runTime: { @@ -952,11 +1120,11 @@ describe('Abstract pool test suite', () => { ++poolBackPressure poolInfo = info }) - for (let i = 0; i < numberOfWorkers * 2; i++) { + for (let i = 0; i < numberOfWorkers + 1; i++) { promises.add(pool.execute()) } await Promise.all(promises) - expect(poolBackPressure).toBe(2) + expect(poolBackPressure).toBe(1) expect(poolInfo).toStrictEqual({ version, type: PoolTypes.fixed, @@ -973,6 +1141,7 @@ describe('Abstract pool test suite', () => { maxQueuedTasks: expect.any(Number), queuedTasks: expect.any(Number), backPressure: true, + stolenTasks: expect.any(Number), failedTasks: expect.any(Number) }) expect(pool.hasBackPressure.called).toBe(true) @@ -987,7 +1156,7 @@ describe('Abstract pool test suite', () => { ) await waitPoolEvents(dynamicThreadPool, PoolEvents.ready, 1) expect(dynamicThreadPool.listTaskFunctions()).toStrictEqual([ - 'default', + DEFAULT_TASK_NAME, 'jsonIntegerSerialization', 'factorial', 'fibonacci' @@ -998,11 +1167,13 @@ describe('Abstract pool test suite', () => { ) await waitPoolEvents(fixedClusterPool, PoolEvents.ready, 1) expect(fixedClusterPool.listTaskFunctions()).toStrictEqual([ - 'default', + DEFAULT_TASK_NAME, 'jsonIntegerSerialization', 'factorial', 'fibonacci' ]) + await dynamicThreadPool.destroy() + await fixedClusterPool.destroy() }) it('Verify that multiple task functions worker is working', async () => { @@ -1024,7 +1195,7 @@ describe('Abstract pool test suite', () => { expect(pool.info.executedTasks).toBe(4) for (const workerNode of pool.workerNodes) { expect(workerNode.info.taskFunctions).toStrictEqual([ - 'default', + DEFAULT_TASK_NAME, 'jsonIntegerSerialization', 'factorial', 'fibonacci' @@ -1036,7 +1207,8 @@ describe('Abstract pool test suite', () => { executed: expect.any(Number), executing: expect.any(Number), failed: 0, - queued: 0 + queued: 0, + stolen: 0 }, runTime: { history: expect.any(CircularArray) @@ -1058,5 +1230,6 @@ describe('Abstract pool test suite', () => { ).toBeGreaterThanOrEqual(0) } } + await pool.destroy() }) })