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