1 const { expect
} = require('expect')
7 } = require('../../../lib/index')
9 describe('Abstract pool test suite', () => {
10 const numberOfWorkers
= 1
11 const workerNotFoundInPoolError
= new Error(
12 'Worker could not be found in the pool'
14 class StubPoolWithRemoveAllWorker
extends FixedThreadPool
{
17 this.promiseResponseMap
.clear()
20 class StubPoolWithIsMain
extends FixedThreadPool
{
26 it('Simulate pool creation from a non main thread/process', () => {
29 new StubPoolWithIsMain(
31 './tests/worker-files/thread/testWorker.js',
33 errorHandler
: e
=> console
.error(e
)
36 ).toThrowError(new Error('Cannot start a pool from a worker!'))
39 it('Verify that filePath is checked', () => {
40 const expectedError
= new Error(
41 'Please specify a file with a worker implementation'
43 expect(() => new FixedThreadPool(numberOfWorkers
)).toThrowError(
46 expect(() => new FixedThreadPool(numberOfWorkers
, '')).toThrowError(
51 it('Verify that numberOfWorkers is checked', () => {
52 expect(() => new FixedThreadPool()).toThrowError(
54 'Cannot instantiate a pool without specifying the number of workers'
59 it('Verify that a negative number of workers is checked', () => {
62 new FixedClusterPool(-1, './tests/worker-files/cluster/testWorker.js')
65 'Cannot instantiate a pool with a negative number of workers'
70 it('Verify that a non integer number of workers is checked', () => {
73 new FixedThreadPool(0.25, './tests/worker-files/thread/testWorker.js')
76 'Cannot instantiate a pool with a non integer number of workers'
81 it('Verify that pool options are checked', async () => {
82 let pool
= new FixedThreadPool(
84 './tests/worker-files/thread/testWorker.js'
86 expect(pool
.opts
.enableEvents
).toBe(true)
87 expect(pool
.emitter
).toBeDefined()
88 expect(pool
.opts
.workerChoiceStrategy
).toBe(
89 WorkerChoiceStrategies
.ROUND_ROBIN
91 expect(pool
.opts
.messageHandler
).toBeUndefined()
92 expect(pool
.opts
.errorHandler
).toBeUndefined()
93 expect(pool
.opts
.onlineHandler
).toBeUndefined()
94 expect(pool
.opts
.exitHandler
).toBeUndefined()
96 const testHandler
= () => console
.log('test handler executed')
97 pool
= new FixedThreadPool(
99 './tests/worker-files/thread/testWorker.js',
101 workerChoiceStrategy
: WorkerChoiceStrategies
.LESS_USED
,
103 messageHandler
: testHandler
,
104 errorHandler
: testHandler
,
105 onlineHandler
: testHandler
,
106 exitHandler
: testHandler
109 expect(pool
.opts
.enableEvents
).toBe(false)
110 expect(pool
.emitter
).toBeUndefined()
111 expect(pool
.opts
.workerChoiceStrategy
).toBe(
112 WorkerChoiceStrategies
.LESS_USED
114 expect(pool
.opts
.messageHandler
).toStrictEqual(testHandler
)
115 expect(pool
.opts
.errorHandler
).toStrictEqual(testHandler
)
116 expect(pool
.opts
.onlineHandler
).toStrictEqual(testHandler
)
117 expect(pool
.opts
.exitHandler
).toStrictEqual(testHandler
)
121 it('Simulate worker not found during getWorkerTasksUsage', async () => {
122 const pool
= new StubPoolWithRemoveAllWorker(
124 './tests/worker-files/cluster/testWorker.js',
126 errorHandler
: e
=> console
.error(e
)
129 // Simulate worker not found.
130 pool
.removeAllWorker()
131 expect(() => pool
.getWorkerTasksUsage()).toThrowError(
132 workerNotFoundInPoolError
137 it('Verify that worker pool tasks usage are initialized', async () => {
138 const pool
= new FixedClusterPool(
140 './tests/worker-files/cluster/testWorker.js'
142 for (const workerItem
of pool
.workers
) {
143 expect(workerItem
.tasksUsage
).toBeDefined()
144 expect(workerItem
.tasksUsage
.run
).toBe(0)
145 expect(workerItem
.tasksUsage
.running
).toBe(0)
146 expect(workerItem
.tasksUsage
.runTime
).toBe(0)
147 expect(workerItem
.tasksUsage
.avgRunTime
).toBe(0)
148 expect(workerItem
.tasksUsage
.error
).toBe(0)
153 it('Verify that worker pool tasks usage are computed', async () => {
154 const pool
= new FixedClusterPool(
156 './tests/worker-files/cluster/testWorker.js'
159 for (let i
= 0; i
< numberOfWorkers
* 2; i
++) {
160 promises
.push(pool
.execute())
162 for (const workerItem
of pool
.workers
) {
163 expect(workerItem
.tasksUsage
).toBeDefined()
164 expect(workerItem
.tasksUsage
.run
).toBe(0)
165 expect(workerItem
.tasksUsage
.running
).toBe(numberOfWorkers
* 2)
166 expect(workerItem
.tasksUsage
.runTime
).toBe(0)
167 expect(workerItem
.tasksUsage
.avgRunTime
).toBe(0)
168 expect(workerItem
.tasksUsage
.error
).toBe(0)
170 await Promise
.all(promises
)
171 for (const workerItem
of pool
.workers
) {
172 expect(workerItem
.tasksUsage
).toBeDefined()
173 expect(workerItem
.tasksUsage
.run
).toBe(numberOfWorkers
* 2)
174 expect(workerItem
.tasksUsage
.running
).toBe(0)
175 expect(workerItem
.tasksUsage
.runTime
).toBeGreaterThanOrEqual(0)
176 expect(workerItem
.tasksUsage
.avgRunTime
).toBeGreaterThanOrEqual(0)
177 expect(workerItem
.tasksUsage
.error
).toBe(0)
182 it('Verify that worker pool tasks usage are reset at worker choice strategy change', async () => {
183 const pool
= new DynamicThreadPool(
186 './tests/worker-files/thread/testWorker.js'
189 for (let i
= 0; i
< numberOfWorkers
* 2; i
++) {
190 promises
.push(pool
.execute())
192 await Promise
.all(promises
)
193 for (const workerItem
of pool
.workers
) {
194 expect(workerItem
.tasksUsage
).toBeDefined()
195 expect(workerItem
.tasksUsage
.run
).toBe(numberOfWorkers
* 2)
196 expect(workerItem
.tasksUsage
.running
).toBe(0)
197 expect(workerItem
.tasksUsage
.runTime
).toBeGreaterThanOrEqual(0)
198 expect(workerItem
.tasksUsage
.avgRunTime
).toBeGreaterThanOrEqual(0)
199 expect(workerItem
.tasksUsage
.error
).toBe(0)
201 pool
.setWorkerChoiceStrategy(WorkerChoiceStrategies
.FAIR_SHARE
)
202 for (const workerItem
of pool
.workers
) {
203 expect(workerItem
.tasksUsage
).toBeDefined()
204 expect(workerItem
.tasksUsage
.run
).toBe(0)
205 expect(workerItem
.tasksUsage
.running
).toBe(0)
206 expect(workerItem
.tasksUsage
.runTime
).toBe(0)
207 expect(workerItem
.tasksUsage
.avgRunTime
).toBe(0)
208 expect(workerItem
.tasksUsage
.error
).toBe(0)
213 it("Verify that pool event emitter 'full' event can register a callback", async () => {
214 const pool
= new DynamicThreadPool(
217 './tests/worker-files/thread/testWorker.js'
221 pool
.emitter
.on('full', () => ++poolFull
)
222 for (let i
= 0; i
< numberOfWorkers
* 2; i
++) {
223 promises
.push(pool
.execute())
225 await Promise
.all(promises
)
226 // The `full` event is triggered when the number of submitted tasks at once reach the number of dynamic pool workers.
227 // So in total numberOfWorkers + 1 times for a loop submitting up to numberOfWorkers * 2 tasks to the dynamic pool.
228 expect(poolFull
).toBe(numberOfWorkers
+ 1)
232 it("Verify that pool event emitter 'busy' event can register a callback", async () => {
233 const pool
= new FixedThreadPool(
235 './tests/worker-files/thread/testWorker.js'
239 pool
.emitter
.on('busy', () => ++poolBusy
)
240 for (let i
= 0; i
< numberOfWorkers
* 2; i
++) {
241 promises
.push(pool
.execute())
243 await Promise
.all(promises
)
244 // The `busy` event is triggered when the number of submitted tasks at once reach the number of fixed pool workers.
245 // So in total numberOfWorkers + 1 times for a loop submitting up to numberOfWorkers * 2 tasks to the fixed pool.
246 expect(poolBusy
).toBe(numberOfWorkers
+ 1)