1 const { expect
} = require('expect')
7 } = require('../../../lib/index')
9 describe('Abstract pool test suite', () => {
10 const numberOfWorkers
= 1
11 const workerNotFoundInTasksUsageMapError
= new Error(
12 'Worker could not be found in the pool'
14 class StubPoolWithRemoveAllWorker
extends FixedThreadPool
{
16 this.workers
= new Map()
17 this.promiseMap
.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_RECENTLY_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_RECENTLY_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 increaseWorkerRunningTasks', async () => {
122 const pool
= new StubPoolWithRemoveAllWorker(
124 './tests/worker-files/cluster/testWorker.js'
126 // Simulate worker not found.
127 pool
.removeAllWorker()
128 expect(() => pool
.increaseWorkerRunningTasks()).toThrowError(
129 workerNotFoundInTasksUsageMapError
134 it('Simulate worker not found during decreaseWorkerRunningTasks', async () => {
135 const pool
= new StubPoolWithRemoveAllWorker(
137 './tests/worker-files/cluster/testWorker.js',
139 errorHandler
: e
=> console
.error(e
)
142 // Simulate worker not found.
143 pool
.removeAllWorker()
144 expect(() => pool
.decreaseWorkerRunningTasks()).toThrowError(
145 workerNotFoundInTasksUsageMapError
150 it('Simulate worker not found during stepWorkerRunTasks', async () => {
151 const pool
= new StubPoolWithRemoveAllWorker(
153 './tests/worker-files/cluster/testWorker.js',
155 errorHandler
: e
=> console
.error(e
)
158 // Simulate worker not found.
159 pool
.removeAllWorker()
160 expect(() => pool
.stepWorkerRunTasks()).toThrowError(
161 workerNotFoundInTasksUsageMapError
166 it('Simulate worker not found during updateWorkerTasksRunTime with strategy not requiring it', async () => {
167 const pool
= new StubPoolWithRemoveAllWorker(
169 './tests/worker-files/cluster/testWorker.js',
171 errorHandler
: e
=> console
.error(e
)
174 // Simulate worker not found.
175 pool
.removeAllWorker()
176 expect(() => pool
.updateWorkerTasksRunTime()).not
.toThrowError()
180 it('Simulate worker not found during updateWorkerTasksRunTime with strategy requiring it', async () => {
181 const pool
= new StubPoolWithRemoveAllWorker(
183 './tests/worker-files/cluster/testWorker.js',
185 workerChoiceStrategy
: WorkerChoiceStrategies
.FAIR_SHARE
,
186 errorHandler
: e
=> console
.error(e
)
189 // Simulate worker not found.
190 pool
.removeAllWorker()
191 expect(() => pool
.updateWorkerTasksRunTime()).toThrowError(
192 workerNotFoundInTasksUsageMapError
197 it('Verify that worker pool tasks usage are initialized', async () => {
198 const pool
= new FixedClusterPool(
200 './tests/worker-files/cluster/testWorker.js'
202 for (const value
of pool
.workers
.values()) {
203 expect(value
.tasksUsage
).toBeDefined()
204 expect(value
.tasksUsage
.run
).toBe(0)
205 expect(value
.tasksUsage
.running
).toBe(0)
206 expect(value
.tasksUsage
.runTime
).toBe(0)
207 expect(value
.tasksUsage
.avgRunTime
).toBe(0)
212 it('Verify that worker pool tasks usage are computed', async () => {
213 const pool
= new FixedClusterPool(
215 './tests/worker-files/cluster/testWorker.js'
218 for (let i
= 0; i
< numberOfWorkers
* 2; i
++) {
219 promises
.push(pool
.execute())
221 for (const value
of pool
.workers
.values()) {
222 expect(value
.tasksUsage
).toBeDefined()
223 expect(value
.tasksUsage
.run
).toBe(0)
224 expect(value
.tasksUsage
.running
).toBe(numberOfWorkers
* 2)
225 expect(value
.tasksUsage
.runTime
).toBe(0)
226 expect(value
.tasksUsage
.avgRunTime
).toBe(0)
228 await Promise
.all(promises
)
229 for (const value
of pool
.workers
.values()) {
230 expect(value
.tasksUsage
).toBeDefined()
231 expect(value
.tasksUsage
.run
).toBe(numberOfWorkers
* 2)
232 expect(value
.tasksUsage
.running
).toBe(0)
233 expect(value
.tasksUsage
.runTime
).toBeGreaterThanOrEqual(0)
234 expect(value
.tasksUsage
.avgRunTime
).toBeGreaterThanOrEqual(0)
239 it('Verify that worker pool tasks usage are reset at worker choice strategy change', async () => {
240 const pool
= new DynamicThreadPool(
243 './tests/worker-files/thread/testWorker.js'
246 for (let i
= 0; i
< numberOfWorkers
* 2; i
++) {
247 promises
.push(pool
.execute())
249 await Promise
.all(promises
)
250 for (const value
of pool
.workers
.values()) {
251 expect(value
.tasksUsage
).toBeDefined()
252 expect(value
.tasksUsage
.run
).toBe(numberOfWorkers
* 2)
253 expect(value
.tasksUsage
.running
).toBe(0)
254 expect(value
.tasksUsage
.runTime
).toBeGreaterThanOrEqual(0)
255 expect(value
.tasksUsage
.avgRunTime
).toBeGreaterThanOrEqual(0)
257 pool
.setWorkerChoiceStrategy(WorkerChoiceStrategies
.FAIR_SHARE
)
258 for (const value
of pool
.workers
.values()) {
259 expect(value
.tasksUsage
).toBeDefined()
260 expect(value
.tasksUsage
.run
).toBe(0)
261 expect(value
.tasksUsage
.running
).toBe(0)
262 expect(value
.tasksUsage
.runTime
).toBe(0)
263 expect(value
.tasksUsage
.avgRunTime
).toBe(0)
268 it("Verify that pool event emitter 'busy' event can register a callback", async () => {
269 const pool
= new FixedThreadPool(
271 './tests/worker-files/thread/testWorker.js'
275 pool
.emitter
.on('busy', () => poolBusy
++)
276 for (let i
= 0; i
< numberOfWorkers
* 2; i
++) {
277 promises
.push(pool
.execute())
279 await Promise
.all(promises
)
280 // The `busy` event is triggered when the number of submitted tasks at once reach the number of fixed pool workers.
281 // So in total numberOfWorkers + 1 times for a loop submitting up to numberOfWorkers * 2 tasks to the fixed pool.
282 expect(poolBusy
).toBe(numberOfWorkers
+ 1)