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 worker tasks usage map'
14 class StubPoolWithWorkerTasksUsageMapClear
extends FixedThreadPool
{
16 this.workersTasksUsage
.clear()
19 class StubPoolWithIsMainMethod
extends FixedThreadPool
{
25 it('Simulate pool creation from a non main thread/process', () => {
28 new StubPoolWithIsMainMethod(
30 './tests/worker-files/thread/testWorker.js',
32 errorHandler
: e
=> console
.error(e
)
35 ).toThrowError(new Error('Cannot start a pool from a worker!'))
38 it('Verify that filePath is checked', () => {
39 const expectedError
= new Error(
40 'Please specify a file with a worker implementation'
42 expect(() => new FixedThreadPool(numberOfWorkers
)).toThrowError(
45 expect(() => new FixedThreadPool(numberOfWorkers
, '')).toThrowError(
50 it('Verify that numberOfWorkers is checked', () => {
51 expect(() => new FixedThreadPool()).toThrowError(
53 'Cannot instantiate a pool without specifying the number of workers'
58 it('Verify that a negative number of workers is checked', () => {
61 new FixedClusterPool(-1, './tests/worker-files/cluster/testWorker.js')
63 new Error('Cannot instantiate a pool with a negative number of workers')
67 it('Verify that a non integer number of workers is checked', () => {
70 new FixedThreadPool(0.25, './tests/worker-files/thread/testWorker.js')
73 'Cannot instantiate a pool with a non integer number of workers'
78 it('Verify that pool options are checked', async () => {
79 let pool
= new FixedThreadPool(
81 './tests/worker-files/thread/testWorker.js'
83 expect(pool
.opts
.enableEvents
).toBe(true)
84 expect(pool
.emitter
).toBeDefined()
85 expect(pool
.opts
.workerChoiceStrategy
).toBe(
86 WorkerChoiceStrategies
.ROUND_ROBIN
88 expect(pool
.opts
.messageHandler
).toBeUndefined()
89 expect(pool
.opts
.errorHandler
).toBeUndefined()
90 expect(pool
.opts
.onlineHandler
).toBeUndefined()
91 expect(pool
.opts
.exitHandler
).toBeUndefined()
93 const testHandler
= () => console
.log('test handler executed')
94 pool
= new FixedThreadPool(
96 './tests/worker-files/thread/testWorker.js',
98 workerChoiceStrategy
: WorkerChoiceStrategies
.LESS_RECENTLY_USED
,
100 messageHandler
: testHandler
,
101 errorHandler
: testHandler
,
102 onlineHandler
: testHandler
,
103 exitHandler
: testHandler
106 expect(pool
.opts
.enableEvents
).toBe(false)
107 expect(pool
.emitter
).toBeUndefined()
108 expect(pool
.opts
.workerChoiceStrategy
).toBe(
109 WorkerChoiceStrategies
.LESS_RECENTLY_USED
111 expect(pool
.opts
.messageHandler
).toStrictEqual(testHandler
)
112 expect(pool
.opts
.errorHandler
).toStrictEqual(testHandler
)
113 expect(pool
.opts
.onlineHandler
).toStrictEqual(testHandler
)
114 expect(pool
.opts
.exitHandler
).toStrictEqual(testHandler
)
118 it('Simulate worker not found during increaseWorkerRunningTasks', async () => {
119 const pool
= new StubPoolWithWorkerTasksUsageMapClear(
121 './tests/worker-files/cluster/testWorker.js'
123 // Simulate worker not found.
124 pool
.removeAllWorker()
125 expect(() => pool
.increaseWorkerRunningTasks()).toThrowError(
126 workerNotFoundInTasksUsageMapError
131 it('Simulate worker not found during decreaseWorkerRunningTasks', async () => {
132 const pool
= new StubPoolWithWorkerTasksUsageMapClear(
134 './tests/worker-files/cluster/testWorker.js',
136 errorHandler
: e
=> console
.error(e
)
139 // Simulate worker not found.
140 pool
.removeAllWorker()
141 expect(() => pool
.decreaseWorkerRunningTasks()).toThrowError(
142 workerNotFoundInTasksUsageMapError
147 it('Simulate worker not found during stepWorkerRunTasks', async () => {
148 const pool
= new StubPoolWithWorkerTasksUsageMapClear(
150 './tests/worker-files/cluster/testWorker.js',
152 errorHandler
: e
=> console
.error(e
)
155 // Simulate worker not found.
156 pool
.removeAllWorker()
157 expect(() => pool
.stepWorkerRunTasks()).toThrowError(
158 workerNotFoundInTasksUsageMapError
163 it('Simulate worker not found during updateWorkerTasksRunTime with strategy not requiring it', async () => {
164 const pool
= new StubPoolWithWorkerTasksUsageMapClear(
166 './tests/worker-files/cluster/testWorker.js',
168 errorHandler
: e
=> console
.error(e
)
171 // Simulate worker not found.
172 pool
.removeAllWorker()
173 expect(() => pool
.updateWorkerTasksRunTime()).not
.toThrowError()
177 it('Simulate worker not found during updateWorkerTasksRunTime with strategy requiring it', async () => {
178 const pool
= new StubPoolWithWorkerTasksUsageMapClear(
180 './tests/worker-files/cluster/testWorker.js',
182 workerChoiceStrategy
: WorkerChoiceStrategies
.FAIR_SHARE
,
183 errorHandler
: e
=> console
.error(e
)
186 // Simulate worker not found.
187 pool
.removeAllWorker()
188 expect(() => pool
.updateWorkerTasksRunTime()).toThrowError(
189 workerNotFoundInTasksUsageMapError
194 it('Verify that worker pool tasks usage are initialized', async () => {
195 const pool
= new FixedClusterPool(
197 './tests/worker-files/cluster/testWorker.js'
199 for (const tasksUsage
of pool
.workersTasksUsage
.values()) {
200 expect(tasksUsage
).toBeDefined()
201 expect(tasksUsage
.run
).toBe(0)
202 expect(tasksUsage
.running
).toBe(0)
203 expect(tasksUsage
.runTime
).toBe(0)
204 expect(tasksUsage
.avgRunTime
).toBe(0)
209 it('Verify that worker pool tasks usage are computed', async () => {
210 const pool
= new FixedClusterPool(
212 './tests/worker-files/cluster/testWorker.js'
215 for (let i
= 0; i
< numberOfWorkers
* 2; i
++) {
216 promises
.push(pool
.execute())
218 for (const tasksUsage
of pool
.workersTasksUsage
.values()) {
219 expect(tasksUsage
).toBeDefined()
220 expect(tasksUsage
.run
).toBe(0)
221 expect(tasksUsage
.running
).toBe(numberOfWorkers
* 2)
222 expect(tasksUsage
.runTime
).toBe(0)
223 expect(tasksUsage
.avgRunTime
).toBe(0)
225 await Promise
.all(promises
)
226 for (const tasksUsage
of pool
.workersTasksUsage
.values()) {
227 expect(tasksUsage
).toBeDefined()
228 expect(tasksUsage
.run
).toBe(numberOfWorkers
* 2)
229 expect(tasksUsage
.running
).toBe(0)
230 expect(tasksUsage
.runTime
).toBeGreaterThanOrEqual(0)
231 expect(tasksUsage
.avgRunTime
).toBeGreaterThanOrEqual(0)
236 it('Verify that worker pool tasks usage are reset at worker choice strategy change', async () => {
237 let pool
= new FixedThreadPool(
239 './tests/worker-files/thread/testWorker.js'
242 for (let i
= 0; i
< numberOfWorkers
* 2; i
++) {
243 promises
.push(pool
.execute())
245 await Promise
.all(promises
)
246 for (const tasksUsage
of pool
.workersTasksUsage
.values()) {
247 expect(tasksUsage
).toBeDefined()
248 expect(tasksUsage
.run
).toBe(numberOfWorkers
* 2)
249 expect(tasksUsage
.running
).toBe(0)
250 expect(tasksUsage
.runTime
).toBeGreaterThanOrEqual(0)
251 expect(tasksUsage
.avgRunTime
).toBeGreaterThanOrEqual(0)
253 pool
.setWorkerChoiceStrategy(WorkerChoiceStrategies
.FAIR_SHARE
)
254 for (const tasksUsage
of pool
.workersTasksUsage
.values()) {
255 expect(tasksUsage
).toBeDefined()
256 expect(tasksUsage
.run
).toBe(0)
257 expect(tasksUsage
.running
).toBe(0)
258 expect(tasksUsage
.runTime
).toBe(0)
259 expect(tasksUsage
.avgRunTime
).toBe(0)
262 pool
= new DynamicThreadPool(
265 './tests/worker-files/thread/testWorker.js'
268 for (let i
= 0; i
< numberOfWorkers
* 2; i
++) {
269 promises
.push(pool
.execute())
271 await Promise
.all(promises
)
272 for (const tasksUsage
of pool
.workersTasksUsage
.values()) {
273 expect(tasksUsage
).toBeDefined()
274 expect(tasksUsage
.run
).toBe(numberOfWorkers
* 2)
275 expect(tasksUsage
.running
).toBe(0)
276 expect(tasksUsage
.runTime
).toBeGreaterThanOrEqual(0)
277 expect(tasksUsage
.avgRunTime
).toBeGreaterThanOrEqual(0)
279 pool
.setWorkerChoiceStrategy(WorkerChoiceStrategies
.FAIR_SHARE
)
280 for (const tasksUsage
of pool
.workersTasksUsage
.values()) {
281 expect(tasksUsage
).toBeDefined()
282 expect(tasksUsage
.run
).toBe(0)
283 expect(tasksUsage
.running
).toBe(0)
284 expect(tasksUsage
.runTime
).toBe(0)
285 expect(tasksUsage
.avgRunTime
).toBe(0)
290 it("Verify that pool event emitter 'busy' event can register a callback", async () => {
291 const pool
= new FixedThreadPool(
293 './tests/worker-files/thread/testWorker.js'
297 pool
.emitter
.on('busy', () => poolBusy
++)
298 for (let i
= 0; i
< numberOfWorkers
* 2; i
++) {
299 promises
.push(pool
.execute())
301 await Promise
.all(promises
)
302 // The `busy` event is triggered when the number of submitted tasks at once reach the number of fixed pool workers.
303 // So in total numberOfWorkers + 1 times for a loop submitting up to numberOfWorkers * 2 tasks to the fixed pool.
304 expect(poolBusy
).toBe(numberOfWorkers
+ 1)