feat: add statistics accounting to ELU fields
[poolifier.git] / tests / pools / abstract / abstract-pool.test.js
CommitLineData
a61a0724 1const { expect } = require('expect')
e843b904 2const {
70a4f5ea 3 DynamicClusterPool,
9e619829 4 DynamicThreadPool,
aee46736 5 FixedClusterPool,
e843b904 6 FixedThreadPool,
aee46736 7 PoolEvents,
6b27d407 8 WorkerChoiceStrategies,
184855e6
JB
9 PoolTypes,
10 WorkerTypes
cdace0e5 11} = require('../../../lib')
78099a15 12const { CircularArray } = require('../../../lib/circular-array')
29ee7e9a 13const { Queue } = require('../../../lib/queue')
e1ffb94f
JB
14
15describe('Abstract pool test suite', () => {
fc027381 16 const numberOfWorkers = 2
a8884ffd 17 class StubPoolWithRemoveAllWorker extends FixedThreadPool {
e1ffb94f 18 removeAllWorker () {
d4aeae5a 19 this.workerNodes = []
c923ce56 20 this.promiseResponseMap.clear()
e1ffb94f 21 }
3ec964d6 22 }
a8884ffd 23 class StubPoolWithIsMain extends FixedThreadPool {
e1ffb94f
JB
24 isMain () {
25 return false
26 }
3ec964d6 27 }
3ec964d6 28
3ec964d6 29 it('Simulate pool creation from a non main thread/process', () => {
8d3782fa
JB
30 expect(
31 () =>
a8884ffd 32 new StubPoolWithIsMain(
7c0ba920 33 numberOfWorkers,
8d3782fa
JB
34 './tests/worker-files/thread/testWorker.js',
35 {
36 errorHandler: e => console.error(e)
37 }
38 )
d4aeae5a 39 ).toThrowError('Cannot start a pool from a worker!')
3ec964d6 40 })
c510fea7
APA
41
42 it('Verify that filePath is checked', () => {
292ad316
JB
43 const expectedError = new Error(
44 'Please specify a file with a worker implementation'
45 )
7c0ba920 46 expect(() => new FixedThreadPool(numberOfWorkers)).toThrowError(
292ad316 47 expectedError
8d3782fa 48 )
7c0ba920 49 expect(() => new FixedThreadPool(numberOfWorkers, '')).toThrowError(
292ad316 50 expectedError
8d3782fa
JB
51 )
52 })
53
54 it('Verify that numberOfWorkers is checked', () => {
55 expect(() => new FixedThreadPool()).toThrowError(
d4aeae5a 56 'Cannot instantiate a pool without specifying the number of workers'
8d3782fa
JB
57 )
58 })
59
60 it('Verify that a negative number of workers is checked', () => {
61 expect(
62 () =>
63 new FixedClusterPool(-1, './tests/worker-files/cluster/testWorker.js')
64 ).toThrowError(
473c717a
JB
65 new RangeError(
66 'Cannot instantiate a pool with a negative number of workers'
67 )
8d3782fa
JB
68 )
69 })
70
71 it('Verify that a non integer number of workers is checked', () => {
72 expect(
73 () =>
74 new FixedThreadPool(0.25, './tests/worker-files/thread/testWorker.js')
75 ).toThrowError(
473c717a 76 new TypeError(
0d80593b 77 'Cannot instantiate a pool with a non safe integer number of workers'
8d3782fa
JB
78 )
79 )
c510fea7 80 })
7c0ba920 81
fd7ebd49 82 it('Verify that pool options are checked', async () => {
7c0ba920
JB
83 let pool = new FixedThreadPool(
84 numberOfWorkers,
85 './tests/worker-files/thread/testWorker.js'
86 )
7c0ba920 87 expect(pool.emitter).toBeDefined()
1f68cede
JB
88 expect(pool.opts.enableEvents).toBe(true)
89 expect(pool.opts.restartWorkerOnError).toBe(true)
ff733df7 90 expect(pool.opts.enableTasksQueue).toBe(false)
d4aeae5a 91 expect(pool.opts.tasksQueueOptions).toBeUndefined()
e843b904
JB
92 expect(pool.opts.workerChoiceStrategy).toBe(
93 WorkerChoiceStrategies.ROUND_ROBIN
94 )
da309861 95 expect(pool.opts.workerChoiceStrategyOptions).toStrictEqual({
932fc8be 96 runTime: { median: false },
5df69fab
JB
97 waitTime: { median: false },
98 elu: { median: false }
da309861 99 })
35cf1c03
JB
100 expect(pool.opts.messageHandler).toBeUndefined()
101 expect(pool.opts.errorHandler).toBeUndefined()
102 expect(pool.opts.onlineHandler).toBeUndefined()
103 expect(pool.opts.exitHandler).toBeUndefined()
fd7ebd49 104 await pool.destroy()
35cf1c03 105 const testHandler = () => console.log('test handler executed')
7c0ba920
JB
106 pool = new FixedThreadPool(
107 numberOfWorkers,
108 './tests/worker-files/thread/testWorker.js',
109 {
e4543b14 110 workerChoiceStrategy: WorkerChoiceStrategies.LEAST_USED,
49be33fe 111 workerChoiceStrategyOptions: {
932fc8be 112 runTime: { median: true },
fc027381 113 weights: { 0: 300, 1: 200 }
49be33fe 114 },
35cf1c03 115 enableEvents: false,
1f68cede 116 restartWorkerOnError: false,
ff733df7 117 enableTasksQueue: true,
d4aeae5a 118 tasksQueueOptions: { concurrency: 2 },
35cf1c03
JB
119 messageHandler: testHandler,
120 errorHandler: testHandler,
121 onlineHandler: testHandler,
122 exitHandler: testHandler
7c0ba920
JB
123 }
124 )
7c0ba920 125 expect(pool.emitter).toBeUndefined()
1f68cede
JB
126 expect(pool.opts.enableEvents).toBe(false)
127 expect(pool.opts.restartWorkerOnError).toBe(false)
ff733df7 128 expect(pool.opts.enableTasksQueue).toBe(true)
d4aeae5a 129 expect(pool.opts.tasksQueueOptions).toStrictEqual({ concurrency: 2 })
e843b904 130 expect(pool.opts.workerChoiceStrategy).toBe(
e4543b14 131 WorkerChoiceStrategies.LEAST_USED
e843b904 132 )
da309861 133 expect(pool.opts.workerChoiceStrategyOptions).toStrictEqual({
932fc8be 134 runTime: { median: true },
fc027381 135 weights: { 0: 300, 1: 200 }
da309861 136 })
35cf1c03
JB
137 expect(pool.opts.messageHandler).toStrictEqual(testHandler)
138 expect(pool.opts.errorHandler).toStrictEqual(testHandler)
139 expect(pool.opts.onlineHandler).toStrictEqual(testHandler)
140 expect(pool.opts.exitHandler).toStrictEqual(testHandler)
fd7ebd49 141 await pool.destroy()
7c0ba920
JB
142 })
143
a20f0ba5 144 it('Verify that pool options are validated', async () => {
d4aeae5a
JB
145 expect(
146 () =>
147 new FixedThreadPool(
148 numberOfWorkers,
149 './tests/worker-files/thread/testWorker.js',
150 {
151 enableTasksQueue: true,
152 tasksQueueOptions: { concurrency: 0 }
153 }
154 )
155 ).toThrowError("Invalid worker tasks concurrency '0'")
156 expect(
157 () =>
158 new FixedThreadPool(
159 numberOfWorkers,
160 './tests/worker-files/thread/testWorker.js',
161 {
162 workerChoiceStrategy: 'invalidStrategy'
163 }
164 )
165 ).toThrowError("Invalid worker choice strategy 'invalidStrategy'")
49be33fe
JB
166 expect(
167 () =>
168 new FixedThreadPool(
169 numberOfWorkers,
170 './tests/worker-files/thread/testWorker.js',
171 {
172 workerChoiceStrategyOptions: { weights: {} }
173 }
174 )
175 ).toThrowError(
176 'Invalid worker choice strategy options: must have a weight for each worker node'
177 )
d4aeae5a
JB
178 })
179
a20f0ba5
JB
180 it('Verify that worker choice strategy options can be set', async () => {
181 const pool = new FixedThreadPool(
182 numberOfWorkers,
183 './tests/worker-files/thread/testWorker.js',
184 { workerChoiceStrategy: WorkerChoiceStrategies.FAIR_SHARE }
185 )
186 expect(pool.opts.workerChoiceStrategyOptions).toStrictEqual({
932fc8be 187 runTime: { median: false },
5df69fab
JB
188 waitTime: { median: false },
189 elu: { median: false }
a20f0ba5
JB
190 })
191 for (const [, workerChoiceStrategy] of pool.workerChoiceStrategyContext
192 .workerChoiceStrategies) {
86bf340d 193 expect(workerChoiceStrategy.opts).toStrictEqual({
932fc8be 194 runTime: { median: false },
5df69fab
JB
195 waitTime: { median: false },
196 elu: { median: false }
86bf340d 197 })
a20f0ba5 198 }
87de9ff5
JB
199 expect(
200 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
201 ).toStrictEqual({
932fc8be
JB
202 runTime: {
203 aggregate: true,
204 average: true,
205 median: false
206 },
207 waitTime: {
208 aggregate: false,
209 average: false,
210 median: false
211 },
5df69fab
JB
212 elu: {
213 aggregate: false,
214 average: false,
215 median: false
216 }
86bf340d 217 })
932fc8be 218 pool.setWorkerChoiceStrategyOptions({ runTime: { median: true } })
a20f0ba5 219 expect(pool.opts.workerChoiceStrategyOptions).toStrictEqual({
932fc8be 220 runTime: { median: true }
a20f0ba5
JB
221 })
222 for (const [, workerChoiceStrategy] of pool.workerChoiceStrategyContext
223 .workerChoiceStrategies) {
932fc8be
JB
224 expect(workerChoiceStrategy.opts).toStrictEqual({
225 runTime: { median: true }
226 })
a20f0ba5 227 }
87de9ff5
JB
228 expect(
229 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
230 ).toStrictEqual({
932fc8be
JB
231 runTime: {
232 aggregate: true,
233 average: false,
234 median: true
235 },
236 waitTime: {
237 aggregate: false,
238 average: false,
239 median: false
240 },
5df69fab
JB
241 elu: {
242 aggregate: false,
243 average: false,
244 median: false
245 }
86bf340d 246 })
932fc8be 247 pool.setWorkerChoiceStrategyOptions({ runTime: { median: false } })
a20f0ba5 248 expect(pool.opts.workerChoiceStrategyOptions).toStrictEqual({
932fc8be 249 runTime: { median: false }
a20f0ba5
JB
250 })
251 for (const [, workerChoiceStrategy] of pool.workerChoiceStrategyContext
252 .workerChoiceStrategies) {
932fc8be
JB
253 expect(workerChoiceStrategy.opts).toStrictEqual({
254 runTime: { median: false }
255 })
a20f0ba5 256 }
87de9ff5
JB
257 expect(
258 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
259 ).toStrictEqual({
932fc8be
JB
260 runTime: {
261 aggregate: true,
262 average: true,
263 median: false
264 },
265 waitTime: {
266 aggregate: false,
267 average: false,
268 median: false
269 },
5df69fab
JB
270 elu: {
271 aggregate: false,
272 average: false,
273 median: false
274 }
86bf340d 275 })
a20f0ba5
JB
276 await pool.destroy()
277 })
278
279 it('Verify that tasks queue can be enabled/disabled', async () => {
280 const pool = new FixedThreadPool(
281 numberOfWorkers,
282 './tests/worker-files/thread/testWorker.js'
283 )
284 expect(pool.opts.enableTasksQueue).toBe(false)
285 expect(pool.opts.tasksQueueOptions).toBeUndefined()
286 pool.enableTasksQueue(true)
287 expect(pool.opts.enableTasksQueue).toBe(true)
288 expect(pool.opts.tasksQueueOptions).toStrictEqual({ concurrency: 1 })
289 pool.enableTasksQueue(true, { concurrency: 2 })
290 expect(pool.opts.enableTasksQueue).toBe(true)
291 expect(pool.opts.tasksQueueOptions).toStrictEqual({ concurrency: 2 })
292 pool.enableTasksQueue(false)
293 expect(pool.opts.enableTasksQueue).toBe(false)
294 expect(pool.opts.tasksQueueOptions).toBeUndefined()
295 await pool.destroy()
296 })
297
298 it('Verify that tasks queue options can be set', async () => {
299 const pool = new FixedThreadPool(
300 numberOfWorkers,
301 './tests/worker-files/thread/testWorker.js',
302 { enableTasksQueue: true }
303 )
304 expect(pool.opts.tasksQueueOptions).toStrictEqual({ concurrency: 1 })
305 pool.setTasksQueueOptions({ concurrency: 2 })
306 expect(pool.opts.tasksQueueOptions).toStrictEqual({ concurrency: 2 })
307 expect(() => pool.setTasksQueueOptions({ concurrency: 0 })).toThrowError(
308 "Invalid worker tasks concurrency '0'"
309 )
310 await pool.destroy()
311 })
312
6b27d407
JB
313 it('Verify that pool info is set', async () => {
314 let pool = new FixedThreadPool(
315 numberOfWorkers,
316 './tests/worker-files/thread/testWorker.js'
317 )
318 expect(pool.info).toStrictEqual({
319 type: PoolTypes.fixed,
184855e6 320 worker: WorkerTypes.thread,
6b27d407
JB
321 minSize: numberOfWorkers,
322 maxSize: numberOfWorkers,
323 workerNodes: numberOfWorkers,
324 idleWorkerNodes: numberOfWorkers,
325 busyWorkerNodes: 0,
a4e07f72
JB
326 executedTasks: 0,
327 executingTasks: 0,
6b27d407 328 queuedTasks: 0,
a4e07f72
JB
329 maxQueuedTasks: 0,
330 failedTasks: 0
6b27d407
JB
331 })
332 await pool.destroy()
333 pool = new DynamicClusterPool(
334 numberOfWorkers,
335 numberOfWorkers * 2,
336 './tests/worker-files/thread/testWorker.js'
337 )
338 expect(pool.info).toStrictEqual({
339 type: PoolTypes.dynamic,
184855e6 340 worker: WorkerTypes.cluster,
6b27d407
JB
341 minSize: numberOfWorkers,
342 maxSize: numberOfWorkers * 2,
343 workerNodes: numberOfWorkers,
344 idleWorkerNodes: numberOfWorkers,
345 busyWorkerNodes: 0,
a4e07f72
JB
346 executedTasks: 0,
347 executingTasks: 0,
6b27d407 348 queuedTasks: 0,
a4e07f72
JB
349 maxQueuedTasks: 0,
350 failedTasks: 0
6b27d407
JB
351 })
352 await pool.destroy()
353 })
354
9d16d33e 355 it('Simulate worker not found', async () => {
a8884ffd 356 const pool = new StubPoolWithRemoveAllWorker(
10fcfaf4
JB
357 numberOfWorkers,
358 './tests/worker-files/cluster/testWorker.js',
359 {
10fcfaf4
JB
360 errorHandler: e => console.error(e)
361 }
362 )
d4aeae5a 363 expect(pool.workerNodes.length).toBe(numberOfWorkers)
10fcfaf4
JB
364 // Simulate worker not found.
365 pool.removeAllWorker()
d4aeae5a 366 expect(pool.workerNodes.length).toBe(0)
fd7ebd49 367 await pool.destroy()
bf9549ae
JB
368 })
369
fd7ebd49 370 it('Verify that worker pool tasks usage are initialized', async () => {
bf9549ae
JB
371 const pool = new FixedClusterPool(
372 numberOfWorkers,
373 './tests/worker-files/cluster/testWorker.js'
374 )
f06e48d8 375 for (const workerNode of pool.workerNodes) {
a4e07f72
JB
376 expect(workerNode.workerUsage).toStrictEqual({
377 tasks: {
378 executed: 0,
379 executing: 0,
380 queued: 0,
381 failed: 0
382 },
383 runTime: {
932fc8be 384 aggregate: 0,
a4e07f72
JB
385 average: 0,
386 median: 0,
387 history: expect.any(CircularArray)
388 },
389 waitTime: {
932fc8be 390 aggregate: 0,
a4e07f72
JB
391 average: 0,
392 median: 0,
393 history: expect.any(CircularArray)
394 },
5df69fab
JB
395 elu: {
396 idle: {
397 aggregate: 0,
398 average: 0,
399 median: 0,
400 history: expect.any(CircularArray)
401 },
402 active: {
403 aggregate: 0,
404 average: 0,
405 median: 0,
406 history: expect.any(CircularArray)
407 },
408 utilization: 0
409 }
86bf340d 410 })
f06e48d8
JB
411 }
412 await pool.destroy()
413 })
414
415 it('Verify that worker pool tasks queue are initialized', async () => {
416 const pool = new FixedClusterPool(
417 numberOfWorkers,
418 './tests/worker-files/cluster/testWorker.js'
419 )
420 for (const workerNode of pool.workerNodes) {
421 expect(workerNode.tasksQueue).toBeDefined()
29ee7e9a 422 expect(workerNode.tasksQueue).toBeInstanceOf(Queue)
4d8bf9e4 423 expect(workerNode.tasksQueue.size).toBe(0)
bf9549ae 424 }
fd7ebd49 425 await pool.destroy()
bf9549ae
JB
426 })
427
428 it('Verify that worker pool tasks usage are computed', async () => {
429 const pool = new FixedClusterPool(
430 numberOfWorkers,
431 './tests/worker-files/cluster/testWorker.js'
432 )
09c2d0d3 433 const promises = new Set()
fc027381
JB
434 const maxMultiplier = 2
435 for (let i = 0; i < numberOfWorkers * maxMultiplier; i++) {
09c2d0d3 436 promises.add(pool.execute())
bf9549ae 437 }
f06e48d8 438 for (const workerNode of pool.workerNodes) {
a4e07f72
JB
439 expect(workerNode.workerUsage).toStrictEqual({
440 tasks: {
441 executed: 0,
442 executing: maxMultiplier,
443 queued: 0,
444 failed: 0
445 },
446 runTime: {
932fc8be 447 aggregate: 0,
a4e07f72
JB
448 average: 0,
449 median: 0,
450 history: expect.any(CircularArray)
451 },
452 waitTime: {
932fc8be 453 aggregate: 0,
a4e07f72
JB
454 average: 0,
455 median: 0,
456 history: expect.any(CircularArray)
457 },
5df69fab
JB
458 elu: {
459 idle: {
460 aggregate: 0,
461 average: 0,
462 median: 0,
463 history: expect.any(CircularArray)
464 },
465 active: {
466 aggregate: 0,
467 average: 0,
468 median: 0,
469 history: expect.any(CircularArray)
470 },
471 utilization: 0
472 }
86bf340d 473 })
bf9549ae
JB
474 }
475 await Promise.all(promises)
f06e48d8 476 for (const workerNode of pool.workerNodes) {
a4e07f72
JB
477 expect(workerNode.workerUsage).toStrictEqual({
478 tasks: {
479 executed: maxMultiplier,
480 executing: 0,
481 queued: 0,
482 failed: 0
483 },
484 runTime: {
932fc8be 485 aggregate: 0,
a4e07f72
JB
486 average: 0,
487 median: 0,
488 history: expect.any(CircularArray)
489 },
490 waitTime: {
932fc8be 491 aggregate: 0,
a4e07f72
JB
492 average: 0,
493 median: 0,
494 history: expect.any(CircularArray)
495 },
5df69fab
JB
496 elu: {
497 idle: {
498 aggregate: 0,
499 average: 0,
500 median: 0,
501 history: expect.any(CircularArray)
502 },
503 active: {
504 aggregate: 0,
505 average: 0,
506 median: 0,
507 history: expect.any(CircularArray)
508 },
509 utilization: 0
510 }
86bf340d 511 })
bf9549ae 512 }
fd7ebd49 513 await pool.destroy()
bf9549ae
JB
514 })
515
ee11a4a2 516 it('Verify that worker pool tasks usage are reset at worker choice strategy change', async () => {
7fd82a1c 517 const pool = new DynamicThreadPool(
9e619829 518 numberOfWorkers,
8f4878b7 519 numberOfWorkers,
9e619829
JB
520 './tests/worker-files/thread/testWorker.js'
521 )
09c2d0d3 522 const promises = new Set()
ee9f5295
JB
523 const maxMultiplier = 2
524 for (let i = 0; i < numberOfWorkers * maxMultiplier; i++) {
09c2d0d3 525 promises.add(pool.execute())
9e619829
JB
526 }
527 await Promise.all(promises)
f06e48d8 528 for (const workerNode of pool.workerNodes) {
a4e07f72
JB
529 expect(workerNode.workerUsage).toStrictEqual({
530 tasks: {
531 executed: expect.any(Number),
532 executing: 0,
533 queued: 0,
534 failed: 0
535 },
536 runTime: {
932fc8be 537 aggregate: 0,
a4e07f72
JB
538 average: 0,
539 median: 0,
540 history: expect.any(CircularArray)
541 },
542 waitTime: {
932fc8be 543 aggregate: 0,
a4e07f72
JB
544 average: 0,
545 median: 0,
546 history: expect.any(CircularArray)
547 },
5df69fab
JB
548 elu: {
549 idle: {
550 aggregate: 0,
551 average: 0,
552 median: 0,
553 history: expect.any(CircularArray)
554 },
555 active: {
556 aggregate: 0,
557 average: 0,
558 median: 0,
559 history: expect.any(CircularArray)
560 },
561 utilization: 0
562 }
86bf340d 563 })
a4e07f72
JB
564 expect(workerNode.workerUsage.tasks.executed).toBeGreaterThan(0)
565 expect(workerNode.workerUsage.tasks.executed).toBeLessThanOrEqual(
566 maxMultiplier
567 )
9e619829
JB
568 }
569 pool.setWorkerChoiceStrategy(WorkerChoiceStrategies.FAIR_SHARE)
f06e48d8 570 for (const workerNode of pool.workerNodes) {
a4e07f72
JB
571 expect(workerNode.workerUsage).toStrictEqual({
572 tasks: {
573 executed: 0,
574 executing: 0,
575 queued: 0,
576 failed: 0
577 },
578 runTime: {
932fc8be 579 aggregate: 0,
a4e07f72
JB
580 average: 0,
581 median: 0,
582 history: expect.any(CircularArray)
583 },
584 waitTime: {
932fc8be 585 aggregate: 0,
a4e07f72
JB
586 average: 0,
587 median: 0,
588 history: expect.any(CircularArray)
589 },
5df69fab
JB
590 elu: {
591 idle: {
592 aggregate: 0,
593 average: 0,
594 median: 0,
595 history: expect.any(CircularArray)
596 },
597 active: {
598 aggregate: 0,
599 average: 0,
600 median: 0,
601 history: expect.any(CircularArray)
602 },
603 utilization: 0
604 }
86bf340d 605 })
a4e07f72
JB
606 expect(workerNode.workerUsage.runTime.history.length).toBe(0)
607 expect(workerNode.workerUsage.waitTime.history.length).toBe(0)
ee11a4a2 608 }
fd7ebd49 609 await pool.destroy()
ee11a4a2
JB
610 })
611
164d950a
JB
612 it("Verify that pool event emitter 'full' event can register a callback", async () => {
613 const pool = new DynamicThreadPool(
614 numberOfWorkers,
615 numberOfWorkers,
616 './tests/worker-files/thread/testWorker.js'
617 )
09c2d0d3 618 const promises = new Set()
164d950a 619 let poolFull = 0
d46660cd
JB
620 let poolInfo
621 pool.emitter.on(PoolEvents.full, info => {
622 ++poolFull
623 poolInfo = info
624 })
164d950a 625 for (let i = 0; i < numberOfWorkers * 2; i++) {
f5d14e90 626 promises.add(pool.execute())
164d950a
JB
627 }
628 await Promise.all(promises)
594bfb84 629 // The `full` event is triggered when the number of submitted tasks at once reach the max number of workers in the dynamic pool.
fc027381
JB
630 // So in total numberOfWorkers * 2 times for a loop submitting up to numberOfWorkers * 2 tasks to the dynamic pool with min = max = numberOfWorkers.
631 expect(poolFull).toBe(numberOfWorkers * 2)
d46660cd
JB
632 expect(poolInfo).toStrictEqual({
633 type: PoolTypes.dynamic,
634 worker: WorkerTypes.thread,
635 minSize: expect.any(Number),
636 maxSize: expect.any(Number),
637 workerNodes: expect.any(Number),
638 idleWorkerNodes: expect.any(Number),
639 busyWorkerNodes: expect.any(Number),
a4e07f72
JB
640 executedTasks: expect.any(Number),
641 executingTasks: expect.any(Number),
d46660cd 642 queuedTasks: expect.any(Number),
a4e07f72
JB
643 maxQueuedTasks: expect.any(Number),
644 failedTasks: expect.any(Number)
d46660cd 645 })
164d950a
JB
646 await pool.destroy()
647 })
648
cf597bc5 649 it("Verify that pool event emitter 'busy' event can register a callback", async () => {
7c0ba920
JB
650 const pool = new FixedThreadPool(
651 numberOfWorkers,
652 './tests/worker-files/thread/testWorker.js'
653 )
09c2d0d3 654 const promises = new Set()
7c0ba920 655 let poolBusy = 0
d46660cd
JB
656 let poolInfo
657 pool.emitter.on(PoolEvents.busy, info => {
658 ++poolBusy
659 poolInfo = info
660 })
7c0ba920 661 for (let i = 0; i < numberOfWorkers * 2; i++) {
f5d14e90 662 promises.add(pool.execute())
7c0ba920 663 }
cf597bc5 664 await Promise.all(promises)
14916bf9
JB
665 // The `busy` event is triggered when the number of submitted tasks at once reach the number of fixed pool workers.
666 // So in total numberOfWorkers + 1 times for a loop submitting up to numberOfWorkers * 2 tasks to the fixed pool.
667 expect(poolBusy).toBe(numberOfWorkers + 1)
d46660cd
JB
668 expect(poolInfo).toStrictEqual({
669 type: PoolTypes.fixed,
670 worker: WorkerTypes.thread,
671 minSize: expect.any(Number),
672 maxSize: expect.any(Number),
673 workerNodes: expect.any(Number),
674 idleWorkerNodes: expect.any(Number),
675 busyWorkerNodes: expect.any(Number),
a4e07f72
JB
676 executedTasks: expect.any(Number),
677 executingTasks: expect.any(Number),
d46660cd 678 queuedTasks: expect.any(Number),
a4e07f72
JB
679 maxQueuedTasks: expect.any(Number),
680 failedTasks: expect.any(Number)
d46660cd 681 })
fd7ebd49 682 await pool.destroy()
7c0ba920 683 })
70a4f5ea
JB
684
685 it('Verify that multiple tasks worker is working', async () => {
686 const pool = new DynamicClusterPool(
687 numberOfWorkers,
688 numberOfWorkers * 2,
689 './tests/worker-files/cluster/testMultiTasksWorker.js'
690 )
691 const data = { n: 10 }
82888165
JB
692 const result0 = await pool.execute(data)
693 expect(result0).toBe(false)
70a4f5ea
JB
694 const result1 = await pool.execute(data, 'jsonIntegerSerialization')
695 expect(result1).toBe(false)
696 const result2 = await pool.execute(data, 'factorial')
697 expect(result2).toBe(3628800)
698 const result3 = await pool.execute(data, 'fibonacci')
699 expect(result3).toBe(89)
700 })
3ec964d6 701})