test: improve coverage
[poolifier.git] / tests / pools / abstract / abstract-pool.test.js
CommitLineData
a61a0724 1const { expect } = require('expect')
b1aae695 2const sinon = require('sinon')
e843b904 3const {
70a4f5ea 4 DynamicClusterPool,
9e619829 5 DynamicThreadPool,
aee46736 6 FixedClusterPool,
e843b904 7 FixedThreadPool,
aee46736 8 PoolEvents,
184855e6 9 PoolTypes,
3d6dd312 10 WorkerChoiceStrategies,
184855e6 11 WorkerTypes
cdace0e5 12} = require('../../../lib')
78099a15 13const { CircularArray } = require('../../../lib/circular-array')
574b351d 14const { Deque } = require('../../../lib/deque')
6cd5248f 15const { DEFAULT_TASK_NAME } = require('../../../lib/utils')
23ccf9d7 16const { version } = require('../../../package.json')
2431bdb4 17const { waitPoolEvents } = require('../../test-utils')
e1ffb94f
JB
18
19describe('Abstract pool test suite', () => {
fc027381 20 const numberOfWorkers = 2
a8884ffd 21 class StubPoolWithIsMain extends FixedThreadPool {
e1ffb94f
JB
22 isMain () {
23 return false
24 }
3ec964d6 25 }
3ec964d6 26
dc021bcc
JB
27 afterEach(() => {
28 sinon.restore()
29 })
30
3ec964d6 31 it('Simulate pool creation from a non main thread/process', () => {
8d3782fa
JB
32 expect(
33 () =>
a8884ffd 34 new StubPoolWithIsMain(
7c0ba920 35 numberOfWorkers,
8d3782fa
JB
36 './tests/worker-files/thread/testWorker.js',
37 {
8ebe6c30 38 errorHandler: (e) => console.error(e)
8d3782fa
JB
39 }
40 )
04f45163 41 ).toThrowError(
e695d66f
JB
42 new Error(
43 'Cannot start a pool from a worker with the same type as the pool'
44 )
04f45163 45 )
3ec964d6 46 })
c510fea7 47
bc61cfe6
JB
48 it('Verify that pool statuses properties are set', async () => {
49 const pool = new FixedThreadPool(
50 numberOfWorkers,
51 './tests/worker-files/thread/testWorker.js'
52 )
53 expect(pool.starting).toBe(false)
54 expect(pool.started).toBe(true)
55 await pool.destroy()
bc61cfe6
JB
56 })
57
c510fea7 58 it('Verify that filePath is checked', () => {
292ad316
JB
59 const expectedError = new Error(
60 'Please specify a file with a worker implementation'
61 )
7c0ba920 62 expect(() => new FixedThreadPool(numberOfWorkers)).toThrowError(
292ad316 63 expectedError
8d3782fa 64 )
7c0ba920 65 expect(() => new FixedThreadPool(numberOfWorkers, '')).toThrowError(
292ad316 66 expectedError
8d3782fa 67 )
3d6dd312
JB
68 expect(() => new FixedThreadPool(numberOfWorkers, 0)).toThrowError(
69 expectedError
70 )
71 expect(() => new FixedThreadPool(numberOfWorkers, true)).toThrowError(
72 expectedError
73 )
74 expect(
75 () => new FixedThreadPool(numberOfWorkers, './dummyWorker.ts')
76 ).toThrowError(new Error("Cannot find the worker file './dummyWorker.ts'"))
8d3782fa
JB
77 })
78
79 it('Verify that numberOfWorkers is checked', () => {
80 expect(() => new FixedThreadPool()).toThrowError(
e695d66f
JB
81 new Error(
82 'Cannot instantiate a pool without specifying the number of workers'
83 )
8d3782fa
JB
84 )
85 })
86
87 it('Verify that a negative number of workers is checked', () => {
88 expect(
89 () =>
90 new FixedClusterPool(-1, './tests/worker-files/cluster/testWorker.js')
91 ).toThrowError(
473c717a
JB
92 new RangeError(
93 'Cannot instantiate a pool with a negative number of workers'
94 )
8d3782fa
JB
95 )
96 })
97
98 it('Verify that a non integer number of workers is checked', () => {
99 expect(
100 () =>
101 new FixedThreadPool(0.25, './tests/worker-files/thread/testWorker.js')
102 ).toThrowError(
473c717a 103 new TypeError(
0d80593b 104 'Cannot instantiate a pool with a non safe integer number of workers'
8d3782fa
JB
105 )
106 )
c510fea7 107 })
7c0ba920 108
216541b6 109 it('Verify that dynamic pool sizing is checked', () => {
a5ed75b7
JB
110 expect(
111 () =>
112 new DynamicClusterPool(
113 1,
114 undefined,
115 './tests/worker-files/cluster/testWorker.js'
116 )
117 ).toThrowError(
118 new TypeError(
119 'Cannot instantiate a dynamic pool without specifying the maximum pool size'
120 )
121 )
2761efb4
JB
122 expect(
123 () =>
124 new DynamicThreadPool(
125 0.5,
126 1,
127 './tests/worker-files/thread/testWorker.js'
128 )
129 ).toThrowError(
130 new TypeError(
131 'Cannot instantiate a pool with a non safe integer number of workers'
132 )
133 )
134 expect(
135 () =>
136 new DynamicClusterPool(
137 0,
138 0.5,
a5ed75b7 139 './tests/worker-files/cluster/testWorker.js'
2761efb4
JB
140 )
141 ).toThrowError(
142 new TypeError(
143 'Cannot instantiate a dynamic pool with a non safe integer maximum pool size'
144 )
145 )
2431bdb4
JB
146 expect(
147 () =>
148 new DynamicThreadPool(2, 1, './tests/worker-files/thread/testWorker.js')
149 ).toThrowError(
150 new RangeError(
151 'Cannot instantiate a dynamic pool with a maximum pool size inferior to the minimum pool size'
152 )
153 )
154 expect(
155 () =>
213cbac6 156 new DynamicThreadPool(0, 0, './tests/worker-files/thread/testWorker.js')
2431bdb4
JB
157 ).toThrowError(
158 new RangeError(
213cbac6 159 'Cannot instantiate a dynamic pool with a maximum pool size equal to zero'
2431bdb4
JB
160 )
161 )
21f710aa
JB
162 expect(
163 () =>
213cbac6
JB
164 new DynamicClusterPool(
165 1,
166 1,
167 './tests/worker-files/cluster/testWorker.js'
168 )
21f710aa
JB
169 ).toThrowError(
170 new RangeError(
213cbac6 171 'Cannot instantiate a dynamic pool with a minimum pool size equal to the maximum pool size. Use a fixed pool instead'
21f710aa
JB
172 )
173 )
2431bdb4
JB
174 })
175
fd7ebd49 176 it('Verify that pool options are checked', async () => {
7c0ba920
JB
177 let pool = new FixedThreadPool(
178 numberOfWorkers,
179 './tests/worker-files/thread/testWorker.js'
180 )
7c0ba920 181 expect(pool.emitter).toBeDefined()
1f68cede
JB
182 expect(pool.opts.enableEvents).toBe(true)
183 expect(pool.opts.restartWorkerOnError).toBe(true)
ff733df7 184 expect(pool.opts.enableTasksQueue).toBe(false)
d4aeae5a 185 expect(pool.opts.tasksQueueOptions).toBeUndefined()
e843b904
JB
186 expect(pool.opts.workerChoiceStrategy).toBe(
187 WorkerChoiceStrategies.ROUND_ROBIN
188 )
da309861 189 expect(pool.opts.workerChoiceStrategyOptions).toStrictEqual({
8c0b113f 190 retries: 6,
8990357d
JB
191 runTime: { median: false },
192 waitTime: { median: false },
193 elu: { median: false }
194 })
195 expect(pool.workerChoiceStrategyContext.opts).toStrictEqual({
8c0b113f 196 retries: 6,
932fc8be 197 runTime: { median: false },
5df69fab
JB
198 waitTime: { median: false },
199 elu: { median: false }
da309861 200 })
999ef664
JB
201 for (const [, workerChoiceStrategy] of pool.workerChoiceStrategyContext
202 .workerChoiceStrategies) {
203 expect(workerChoiceStrategy.opts).toStrictEqual({
204 retries: 6,
205 runTime: { median: false },
206 waitTime: { median: false },
207 elu: { median: false }
208 })
209 }
35cf1c03
JB
210 expect(pool.opts.messageHandler).toBeUndefined()
211 expect(pool.opts.errorHandler).toBeUndefined()
212 expect(pool.opts.onlineHandler).toBeUndefined()
213 expect(pool.opts.exitHandler).toBeUndefined()
fd7ebd49 214 await pool.destroy()
73bfd59d 215 const testHandler = () => console.info('test handler executed')
7c0ba920
JB
216 pool = new FixedThreadPool(
217 numberOfWorkers,
218 './tests/worker-files/thread/testWorker.js',
219 {
e4543b14 220 workerChoiceStrategy: WorkerChoiceStrategies.LEAST_USED,
49be33fe 221 workerChoiceStrategyOptions: {
932fc8be 222 runTime: { median: true },
fc027381 223 weights: { 0: 300, 1: 200 }
49be33fe 224 },
35cf1c03 225 enableEvents: false,
1f68cede 226 restartWorkerOnError: false,
ff733df7 227 enableTasksQueue: true,
d4aeae5a 228 tasksQueueOptions: { concurrency: 2 },
35cf1c03
JB
229 messageHandler: testHandler,
230 errorHandler: testHandler,
231 onlineHandler: testHandler,
232 exitHandler: testHandler
7c0ba920
JB
233 }
234 )
7c0ba920 235 expect(pool.emitter).toBeUndefined()
1f68cede
JB
236 expect(pool.opts.enableEvents).toBe(false)
237 expect(pool.opts.restartWorkerOnError).toBe(false)
ff733df7 238 expect(pool.opts.enableTasksQueue).toBe(true)
20c6f652
JB
239 expect(pool.opts.tasksQueueOptions).toStrictEqual({
240 concurrency: 2,
ff3f866a 241 size: 4
20c6f652 242 })
e843b904 243 expect(pool.opts.workerChoiceStrategy).toBe(
e4543b14 244 WorkerChoiceStrategies.LEAST_USED
e843b904 245 )
da309861 246 expect(pool.opts.workerChoiceStrategyOptions).toStrictEqual({
8c0b113f 247 retries: 6,
932fc8be 248 runTime: { median: true },
8990357d
JB
249 waitTime: { median: false },
250 elu: { median: false },
251 weights: { 0: 300, 1: 200 }
252 })
253 expect(pool.workerChoiceStrategyContext.opts).toStrictEqual({
8c0b113f 254 retries: 6,
8990357d
JB
255 runTime: { median: true },
256 waitTime: { median: false },
257 elu: { median: false },
fc027381 258 weights: { 0: 300, 1: 200 }
da309861 259 })
999ef664
JB
260 for (const [, workerChoiceStrategy] of pool.workerChoiceStrategyContext
261 .workerChoiceStrategies) {
262 expect(workerChoiceStrategy.opts).toStrictEqual({
263 retries: 6,
264 runTime: { median: true },
265 waitTime: { median: false },
266 elu: { median: false },
267 weights: { 0: 300, 1: 200 }
268 })
269 }
35cf1c03
JB
270 expect(pool.opts.messageHandler).toStrictEqual(testHandler)
271 expect(pool.opts.errorHandler).toStrictEqual(testHandler)
272 expect(pool.opts.onlineHandler).toStrictEqual(testHandler)
273 expect(pool.opts.exitHandler).toStrictEqual(testHandler)
fd7ebd49 274 await pool.destroy()
7c0ba920
JB
275 })
276
a20f0ba5 277 it('Verify that pool options are validated', async () => {
d4aeae5a
JB
278 expect(
279 () =>
280 new FixedThreadPool(
281 numberOfWorkers,
282 './tests/worker-files/thread/testWorker.js',
283 {
f0d7f803 284 workerChoiceStrategy: 'invalidStrategy'
d4aeae5a
JB
285 }
286 )
8735b4e5
JB
287 ).toThrowError(
288 new Error("Invalid worker choice strategy 'invalidStrategy'")
289 )
7e653ee0
JB
290 expect(
291 () =>
292 new FixedThreadPool(
293 numberOfWorkers,
294 './tests/worker-files/thread/testWorker.js',
295 {
296 workerChoiceStrategyOptions: {
8c0b113f 297 retries: 'invalidChoiceRetries'
7e653ee0
JB
298 }
299 }
300 )
301 ).toThrowError(
302 new TypeError(
8c0b113f 303 'Invalid worker choice strategy options: retries must be an integer'
7e653ee0
JB
304 )
305 )
306 expect(
307 () =>
308 new FixedThreadPool(
309 numberOfWorkers,
310 './tests/worker-files/thread/testWorker.js',
311 {
312 workerChoiceStrategyOptions: {
8c0b113f 313 retries: -1
7e653ee0
JB
314 }
315 }
316 )
317 ).toThrowError(
318 new RangeError(
8c0b113f 319 "Invalid worker choice strategy options: retries '-1' must be greater or equal than zero"
7e653ee0
JB
320 )
321 )
49be33fe
JB
322 expect(
323 () =>
324 new FixedThreadPool(
325 numberOfWorkers,
326 './tests/worker-files/thread/testWorker.js',
327 {
328 workerChoiceStrategyOptions: { weights: {} }
329 }
330 )
331 ).toThrowError(
8735b4e5
JB
332 new Error(
333 'Invalid worker choice strategy options: must have a weight for each worker node'
334 )
49be33fe 335 )
f0d7f803
JB
336 expect(
337 () =>
338 new FixedThreadPool(
339 numberOfWorkers,
340 './tests/worker-files/thread/testWorker.js',
341 {
342 workerChoiceStrategyOptions: { measurement: 'invalidMeasurement' }
343 }
344 )
345 ).toThrowError(
8735b4e5
JB
346 new Error(
347 "Invalid worker choice strategy options: invalid measurement 'invalidMeasurement'"
348 )
f0d7f803 349 )
5c4c2dee
JB
350 expect(
351 () =>
352 new FixedThreadPool(
353 numberOfWorkers,
354 './tests/worker-files/thread/testWorker.js',
355 {
356 enableTasksQueue: true,
357 tasksQueueOptions: 'invalidTasksQueueOptions'
358 }
359 )
360 ).toThrowError(
361 new TypeError('Invalid tasks queue options: must be a plain object')
362 )
f0d7f803
JB
363 expect(
364 () =>
365 new FixedThreadPool(
366 numberOfWorkers,
367 './tests/worker-files/thread/testWorker.js',
368 {
369 enableTasksQueue: true,
370 tasksQueueOptions: { concurrency: 0 }
371 }
372 )
8735b4e5 373 ).toThrowError(
e695d66f 374 new RangeError(
20c6f652 375 'Invalid worker node tasks concurrency: 0 is a negative integer or zero'
8735b4e5
JB
376 )
377 )
f0d7f803
JB
378 expect(
379 () =>
380 new FixedThreadPool(
381 numberOfWorkers,
382 './tests/worker-files/thread/testWorker.js',
383 {
384 enableTasksQueue: true,
5c4c2dee 385 tasksQueueOptions: { concurrency: -1 }
f0d7f803
JB
386 }
387 )
8735b4e5 388 ).toThrowError(
5c4c2dee
JB
389 new RangeError(
390 'Invalid worker node tasks concurrency: -1 is a negative integer or zero'
391 )
8735b4e5 392 )
f0d7f803
JB
393 expect(
394 () =>
395 new FixedThreadPool(
396 numberOfWorkers,
397 './tests/worker-files/thread/testWorker.js',
398 {
399 enableTasksQueue: true,
400 tasksQueueOptions: { concurrency: 0.2 }
401 }
402 )
8735b4e5 403 ).toThrowError(
20c6f652 404 new TypeError('Invalid worker node tasks concurrency: must be an integer')
8735b4e5 405 )
5c4c2dee
JB
406 expect(
407 () =>
408 new FixedThreadPool(
409 numberOfWorkers,
410 './tests/worker-files/thread/testWorker.js',
411 {
412 enableTasksQueue: true,
413 tasksQueueOptions: { queueMaxSize: 2 }
414 }
415 )
416 ).toThrowError(
417 new Error(
418 'Invalid tasks queue options: queueMaxSize is deprecated, please use size instead'
419 )
420 )
421 expect(
422 () =>
423 new FixedThreadPool(
424 numberOfWorkers,
425 './tests/worker-files/thread/testWorker.js',
426 {
427 enableTasksQueue: true,
428 tasksQueueOptions: { size: 0 }
429 }
430 )
431 ).toThrowError(
432 new RangeError(
433 'Invalid worker node tasks queue size: 0 is a negative integer or zero'
434 )
435 )
436 expect(
437 () =>
438 new FixedThreadPool(
439 numberOfWorkers,
440 './tests/worker-files/thread/testWorker.js',
441 {
442 enableTasksQueue: true,
443 tasksQueueOptions: { size: -1 }
444 }
445 )
446 ).toThrowError(
447 new RangeError(
448 'Invalid worker node tasks queue size: -1 is a negative integer or zero'
449 )
450 )
451 expect(
452 () =>
453 new FixedThreadPool(
454 numberOfWorkers,
455 './tests/worker-files/thread/testWorker.js',
456 {
457 enableTasksQueue: true,
458 tasksQueueOptions: { size: 0.2 }
459 }
460 )
461 ).toThrowError(
462 new TypeError('Invalid worker node tasks queue size: must be an integer')
463 )
d4aeae5a
JB
464 })
465
2431bdb4 466 it('Verify that pool worker choice strategy options can be set', async () => {
a20f0ba5
JB
467 const pool = new FixedThreadPool(
468 numberOfWorkers,
469 './tests/worker-files/thread/testWorker.js',
470 { workerChoiceStrategy: WorkerChoiceStrategies.FAIR_SHARE }
471 )
472 expect(pool.opts.workerChoiceStrategyOptions).toStrictEqual({
8c0b113f 473 retries: 6,
8990357d
JB
474 runTime: { median: false },
475 waitTime: { median: false },
476 elu: { median: false }
477 })
478 expect(pool.workerChoiceStrategyContext.opts).toStrictEqual({
8c0b113f 479 retries: 6,
932fc8be 480 runTime: { median: false },
5df69fab
JB
481 waitTime: { median: false },
482 elu: { median: false }
a20f0ba5
JB
483 })
484 for (const [, workerChoiceStrategy] of pool.workerChoiceStrategyContext
485 .workerChoiceStrategies) {
86bf340d 486 expect(workerChoiceStrategy.opts).toStrictEqual({
8c0b113f 487 retries: 6,
932fc8be 488 runTime: { median: false },
5df69fab
JB
489 waitTime: { median: false },
490 elu: { median: false }
86bf340d 491 })
a20f0ba5 492 }
87de9ff5
JB
493 expect(
494 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
495 ).toStrictEqual({
932fc8be
JB
496 runTime: {
497 aggregate: true,
498 average: true,
499 median: false
500 },
501 waitTime: {
502 aggregate: false,
503 average: false,
504 median: false
505 },
5df69fab 506 elu: {
9adcefab
JB
507 aggregate: true,
508 average: true,
5df69fab
JB
509 median: false
510 }
86bf340d 511 })
9adcefab
JB
512 pool.setWorkerChoiceStrategyOptions({
513 runTime: { median: true },
514 elu: { median: true }
515 })
a20f0ba5 516 expect(pool.opts.workerChoiceStrategyOptions).toStrictEqual({
8c0b113f 517 retries: 6,
9adcefab 518 runTime: { median: true },
8990357d
JB
519 waitTime: { median: false },
520 elu: { median: true }
521 })
522 expect(pool.workerChoiceStrategyContext.opts).toStrictEqual({
8c0b113f 523 retries: 6,
8990357d
JB
524 runTime: { median: true },
525 waitTime: { median: false },
9adcefab 526 elu: { median: true }
a20f0ba5
JB
527 })
528 for (const [, workerChoiceStrategy] of pool.workerChoiceStrategyContext
529 .workerChoiceStrategies) {
932fc8be 530 expect(workerChoiceStrategy.opts).toStrictEqual({
8c0b113f 531 retries: 6,
9adcefab 532 runTime: { median: true },
8990357d 533 waitTime: { median: false },
9adcefab 534 elu: { median: true }
932fc8be 535 })
a20f0ba5 536 }
87de9ff5
JB
537 expect(
538 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
539 ).toStrictEqual({
932fc8be
JB
540 runTime: {
541 aggregate: true,
542 average: false,
543 median: true
544 },
545 waitTime: {
546 aggregate: false,
547 average: false,
548 median: false
549 },
5df69fab 550 elu: {
9adcefab 551 aggregate: true,
5df69fab 552 average: false,
9adcefab 553 median: true
5df69fab 554 }
86bf340d 555 })
9adcefab
JB
556 pool.setWorkerChoiceStrategyOptions({
557 runTime: { median: false },
558 elu: { median: false }
559 })
a20f0ba5 560 expect(pool.opts.workerChoiceStrategyOptions).toStrictEqual({
8c0b113f 561 retries: 6,
8990357d
JB
562 runTime: { median: false },
563 waitTime: { median: false },
564 elu: { median: false }
565 })
566 expect(pool.workerChoiceStrategyContext.opts).toStrictEqual({
8c0b113f 567 retries: 6,
9adcefab 568 runTime: { median: false },
8990357d 569 waitTime: { median: false },
9adcefab 570 elu: { median: false }
a20f0ba5
JB
571 })
572 for (const [, workerChoiceStrategy] of pool.workerChoiceStrategyContext
573 .workerChoiceStrategies) {
932fc8be 574 expect(workerChoiceStrategy.opts).toStrictEqual({
8c0b113f 575 retries: 6,
9adcefab 576 runTime: { median: false },
8990357d 577 waitTime: { median: false },
9adcefab 578 elu: { median: false }
932fc8be 579 })
a20f0ba5 580 }
87de9ff5
JB
581 expect(
582 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
583 ).toStrictEqual({
932fc8be
JB
584 runTime: {
585 aggregate: true,
586 average: true,
587 median: false
588 },
589 waitTime: {
590 aggregate: false,
591 average: false,
592 median: false
593 },
5df69fab 594 elu: {
9adcefab
JB
595 aggregate: true,
596 average: true,
5df69fab
JB
597 median: false
598 }
86bf340d 599 })
1f95d544
JB
600 expect(() =>
601 pool.setWorkerChoiceStrategyOptions('invalidWorkerChoiceStrategyOptions')
602 ).toThrowError(
8735b4e5
JB
603 new TypeError(
604 'Invalid worker choice strategy options: must be a plain object'
605 )
1f95d544 606 )
7e653ee0
JB
607 expect(() =>
608 pool.setWorkerChoiceStrategyOptions({
8c0b113f 609 retries: 'invalidChoiceRetries'
7e653ee0
JB
610 })
611 ).toThrowError(
612 new TypeError(
8c0b113f 613 'Invalid worker choice strategy options: retries must be an integer'
7e653ee0
JB
614 )
615 )
616 expect(() =>
8c0b113f 617 pool.setWorkerChoiceStrategyOptions({ retries: -1 })
7e653ee0
JB
618 ).toThrowError(
619 new RangeError(
8c0b113f 620 "Invalid worker choice strategy options: retries '-1' must be greater or equal than zero"
7e653ee0
JB
621 )
622 )
1f95d544
JB
623 expect(() =>
624 pool.setWorkerChoiceStrategyOptions({ weights: {} })
625 ).toThrowError(
8735b4e5
JB
626 new Error(
627 'Invalid worker choice strategy options: must have a weight for each worker node'
628 )
1f95d544
JB
629 )
630 expect(() =>
631 pool.setWorkerChoiceStrategyOptions({ measurement: 'invalidMeasurement' })
632 ).toThrowError(
8735b4e5
JB
633 new Error(
634 "Invalid worker choice strategy options: invalid measurement 'invalidMeasurement'"
635 )
1f95d544 636 )
a20f0ba5
JB
637 await pool.destroy()
638 })
639
2431bdb4 640 it('Verify that pool tasks queue can be enabled/disabled', async () => {
a20f0ba5
JB
641 const pool = new FixedThreadPool(
642 numberOfWorkers,
643 './tests/worker-files/thread/testWorker.js'
644 )
645 expect(pool.opts.enableTasksQueue).toBe(false)
646 expect(pool.opts.tasksQueueOptions).toBeUndefined()
647 pool.enableTasksQueue(true)
648 expect(pool.opts.enableTasksQueue).toBe(true)
20c6f652
JB
649 expect(pool.opts.tasksQueueOptions).toStrictEqual({
650 concurrency: 1,
ff3f866a 651 size: 4
20c6f652 652 })
a20f0ba5
JB
653 pool.enableTasksQueue(true, { concurrency: 2 })
654 expect(pool.opts.enableTasksQueue).toBe(true)
20c6f652
JB
655 expect(pool.opts.tasksQueueOptions).toStrictEqual({
656 concurrency: 2,
ff3f866a 657 size: 4
20c6f652 658 })
a20f0ba5
JB
659 pool.enableTasksQueue(false)
660 expect(pool.opts.enableTasksQueue).toBe(false)
661 expect(pool.opts.tasksQueueOptions).toBeUndefined()
662 await pool.destroy()
663 })
664
2431bdb4 665 it('Verify that pool tasks queue options can be set', async () => {
a20f0ba5
JB
666 const pool = new FixedThreadPool(
667 numberOfWorkers,
668 './tests/worker-files/thread/testWorker.js',
669 { enableTasksQueue: true }
670 )
20c6f652
JB
671 expect(pool.opts.tasksQueueOptions).toStrictEqual({
672 concurrency: 1,
ff3f866a 673 size: 4
20c6f652 674 })
a20f0ba5 675 pool.setTasksQueueOptions({ concurrency: 2 })
20c6f652
JB
676 expect(pool.opts.tasksQueueOptions).toStrictEqual({
677 concurrency: 2,
ff3f866a 678 size: 4
20c6f652 679 })
f0d7f803
JB
680 expect(() =>
681 pool.setTasksQueueOptions('invalidTasksQueueOptions')
8735b4e5
JB
682 ).toThrowError(
683 new TypeError('Invalid tasks queue options: must be a plain object')
684 )
a20f0ba5 685 expect(() => pool.setTasksQueueOptions({ concurrency: 0 })).toThrowError(
e695d66f 686 new RangeError(
20c6f652 687 'Invalid worker node tasks concurrency: 0 is a negative integer or zero'
8735b4e5
JB
688 )
689 )
690 expect(() => pool.setTasksQueueOptions({ concurrency: -1 })).toThrowError(
e695d66f 691 new RangeError(
20c6f652 692 'Invalid worker node tasks concurrency: -1 is a negative integer or zero'
8735b4e5 693 )
a20f0ba5 694 )
f0d7f803 695 expect(() => pool.setTasksQueueOptions({ concurrency: 0.2 })).toThrowError(
20c6f652
JB
696 new TypeError('Invalid worker node tasks concurrency: must be an integer')
697 )
68dbcdc0
JB
698 expect(() => pool.setTasksQueueOptions({ queueMaxSize: 2 })).toThrowError(
699 new Error(
700 'Invalid tasks queue options: queueMaxSize is deprecated, please use size instead'
701 )
702 )
ff3f866a 703 expect(() => pool.setTasksQueueOptions({ size: 0 })).toThrowError(
20c6f652 704 new RangeError(
68dbcdc0 705 'Invalid worker node tasks queue size: 0 is a negative integer or zero'
20c6f652
JB
706 )
707 )
ff3f866a 708 expect(() => pool.setTasksQueueOptions({ size: -1 })).toThrowError(
20c6f652 709 new RangeError(
68dbcdc0 710 'Invalid worker node tasks queue size: -1 is a negative integer or zero'
20c6f652
JB
711 )
712 )
ff3f866a 713 expect(() => pool.setTasksQueueOptions({ size: 0.2 })).toThrowError(
68dbcdc0 714 new TypeError('Invalid worker node tasks queue size: must be an integer')
f0d7f803 715 )
a20f0ba5
JB
716 await pool.destroy()
717 })
718
6b27d407
JB
719 it('Verify that pool info is set', async () => {
720 let pool = new FixedThreadPool(
721 numberOfWorkers,
722 './tests/worker-files/thread/testWorker.js'
723 )
2dca6cab
JB
724 expect(pool.info).toStrictEqual({
725 version,
726 type: PoolTypes.fixed,
727 worker: WorkerTypes.thread,
728 ready: true,
729 strategy: WorkerChoiceStrategies.ROUND_ROBIN,
730 minSize: numberOfWorkers,
731 maxSize: numberOfWorkers,
732 workerNodes: numberOfWorkers,
733 idleWorkerNodes: numberOfWorkers,
734 busyWorkerNodes: 0,
735 executedTasks: 0,
736 executingTasks: 0,
2dca6cab
JB
737 failedTasks: 0
738 })
6b27d407
JB
739 await pool.destroy()
740 pool = new DynamicClusterPool(
2431bdb4 741 Math.floor(numberOfWorkers / 2),
6b27d407 742 numberOfWorkers,
ecdfbdc0 743 './tests/worker-files/cluster/testWorker.js'
6b27d407 744 )
2dca6cab
JB
745 expect(pool.info).toStrictEqual({
746 version,
747 type: PoolTypes.dynamic,
748 worker: WorkerTypes.cluster,
749 ready: true,
750 strategy: WorkerChoiceStrategies.ROUND_ROBIN,
751 minSize: Math.floor(numberOfWorkers / 2),
752 maxSize: numberOfWorkers,
753 workerNodes: Math.floor(numberOfWorkers / 2),
754 idleWorkerNodes: Math.floor(numberOfWorkers / 2),
755 busyWorkerNodes: 0,
756 executedTasks: 0,
757 executingTasks: 0,
2dca6cab
JB
758 failedTasks: 0
759 })
6b27d407
JB
760 await pool.destroy()
761 })
762
2431bdb4 763 it('Verify that pool worker tasks usage are initialized', async () => {
bf9549ae
JB
764 const pool = new FixedClusterPool(
765 numberOfWorkers,
766 './tests/worker-files/cluster/testWorker.js'
767 )
f06e48d8 768 for (const workerNode of pool.workerNodes) {
465b2940 769 expect(workerNode.usage).toStrictEqual({
a4e07f72
JB
770 tasks: {
771 executed: 0,
772 executing: 0,
773 queued: 0,
df593701 774 maxQueued: 0,
68cbdc84 775 stolen: 0,
a4e07f72
JB
776 failed: 0
777 },
778 runTime: {
a4e07f72
JB
779 history: expect.any(CircularArray)
780 },
781 waitTime: {
a4e07f72
JB
782 history: expect.any(CircularArray)
783 },
5df69fab
JB
784 elu: {
785 idle: {
5df69fab
JB
786 history: expect.any(CircularArray)
787 },
788 active: {
5df69fab 789 history: expect.any(CircularArray)
f7510105 790 }
5df69fab 791 }
86bf340d 792 })
f06e48d8
JB
793 }
794 await pool.destroy()
795 })
796
2431bdb4
JB
797 it('Verify that pool worker tasks queue are initialized', async () => {
798 let pool = new FixedClusterPool(
f06e48d8
JB
799 numberOfWorkers,
800 './tests/worker-files/cluster/testWorker.js'
801 )
802 for (const workerNode of pool.workerNodes) {
803 expect(workerNode.tasksQueue).toBeDefined()
574b351d 804 expect(workerNode.tasksQueue).toBeInstanceOf(Deque)
4d8bf9e4 805 expect(workerNode.tasksQueue.size).toBe(0)
9c16fb4b 806 expect(workerNode.tasksQueue.maxSize).toBe(0)
bf9549ae 807 }
fd7ebd49 808 await pool.destroy()
2431bdb4
JB
809 pool = new DynamicThreadPool(
810 Math.floor(numberOfWorkers / 2),
811 numberOfWorkers,
812 './tests/worker-files/thread/testWorker.js'
813 )
814 for (const workerNode of pool.workerNodes) {
815 expect(workerNode.tasksQueue).toBeDefined()
574b351d 816 expect(workerNode.tasksQueue).toBeInstanceOf(Deque)
2431bdb4
JB
817 expect(workerNode.tasksQueue.size).toBe(0)
818 expect(workerNode.tasksQueue.maxSize).toBe(0)
819 }
213cbac6 820 await pool.destroy()
2431bdb4
JB
821 })
822
823 it('Verify that pool worker info are initialized', async () => {
824 let pool = new FixedClusterPool(
825 numberOfWorkers,
826 './tests/worker-files/cluster/testWorker.js'
827 )
2dca6cab
JB
828 for (const workerNode of pool.workerNodes) {
829 expect(workerNode.info).toStrictEqual({
830 id: expect.any(Number),
831 type: WorkerTypes.cluster,
832 dynamic: false,
833 ready: true
834 })
835 }
2431bdb4
JB
836 await pool.destroy()
837 pool = new DynamicThreadPool(
838 Math.floor(numberOfWorkers / 2),
839 numberOfWorkers,
840 './tests/worker-files/thread/testWorker.js'
841 )
2dca6cab
JB
842 for (const workerNode of pool.workerNodes) {
843 expect(workerNode.info).toStrictEqual({
844 id: expect.any(Number),
845 type: WorkerTypes.thread,
846 dynamic: false,
7884d183 847 ready: true
2dca6cab
JB
848 })
849 }
213cbac6 850 await pool.destroy()
bf9549ae
JB
851 })
852
9d2d0da1
JB
853 it('Verify that pool execute() arguments are checked', async () => {
854 const pool = new FixedClusterPool(
855 numberOfWorkers,
856 './tests/worker-files/cluster/testWorker.js'
857 )
858 await expect(pool.execute(undefined, 0)).rejects.toThrowError(
859 new TypeError('name argument must be a string')
860 )
861 await expect(pool.execute(undefined, '')).rejects.toThrowError(
862 new TypeError('name argument must not be an empty string')
863 )
864 await expect(pool.execute(undefined, undefined, {})).rejects.toThrowError(
865 new TypeError('transferList argument must be an array')
866 )
867 await expect(pool.execute(undefined, 'unknown')).rejects.toBe(
868 "Task function 'unknown' not found"
869 )
870 await pool.destroy()
871 await expect(pool.execute(undefined, undefined, {})).rejects.toThrowError(
872 new Error('Cannot execute a task on destroyed pool')
873 )
874 })
875
2431bdb4 876 it('Verify that pool worker tasks usage are computed', async () => {
bf9549ae
JB
877 const pool = new FixedClusterPool(
878 numberOfWorkers,
879 './tests/worker-files/cluster/testWorker.js'
880 )
09c2d0d3 881 const promises = new Set()
fc027381
JB
882 const maxMultiplier = 2
883 for (let i = 0; i < numberOfWorkers * maxMultiplier; i++) {
09c2d0d3 884 promises.add(pool.execute())
bf9549ae 885 }
f06e48d8 886 for (const workerNode of pool.workerNodes) {
465b2940 887 expect(workerNode.usage).toStrictEqual({
a4e07f72
JB
888 tasks: {
889 executed: 0,
890 executing: maxMultiplier,
891 queued: 0,
df593701 892 maxQueued: 0,
68cbdc84 893 stolen: 0,
a4e07f72
JB
894 failed: 0
895 },
896 runTime: {
a4e07f72
JB
897 history: expect.any(CircularArray)
898 },
899 waitTime: {
a4e07f72
JB
900 history: expect.any(CircularArray)
901 },
5df69fab
JB
902 elu: {
903 idle: {
5df69fab
JB
904 history: expect.any(CircularArray)
905 },
906 active: {
5df69fab 907 history: expect.any(CircularArray)
f7510105 908 }
5df69fab 909 }
86bf340d 910 })
bf9549ae
JB
911 }
912 await Promise.all(promises)
f06e48d8 913 for (const workerNode of pool.workerNodes) {
465b2940 914 expect(workerNode.usage).toStrictEqual({
a4e07f72
JB
915 tasks: {
916 executed: maxMultiplier,
917 executing: 0,
918 queued: 0,
df593701 919 maxQueued: 0,
68cbdc84 920 stolen: 0,
a4e07f72
JB
921 failed: 0
922 },
923 runTime: {
a4e07f72
JB
924 history: expect.any(CircularArray)
925 },
926 waitTime: {
a4e07f72
JB
927 history: expect.any(CircularArray)
928 },
5df69fab
JB
929 elu: {
930 idle: {
5df69fab
JB
931 history: expect.any(CircularArray)
932 },
933 active: {
5df69fab 934 history: expect.any(CircularArray)
f7510105 935 }
5df69fab 936 }
86bf340d 937 })
bf9549ae 938 }
fd7ebd49 939 await pool.destroy()
bf9549ae
JB
940 })
941
2431bdb4 942 it('Verify that pool worker tasks usage are reset at worker choice strategy change', async () => {
7fd82a1c 943 const pool = new DynamicThreadPool(
2431bdb4 944 Math.floor(numberOfWorkers / 2),
8f4878b7 945 numberOfWorkers,
9e619829
JB
946 './tests/worker-files/thread/testWorker.js'
947 )
09c2d0d3 948 const promises = new Set()
ee9f5295
JB
949 const maxMultiplier = 2
950 for (let i = 0; i < numberOfWorkers * maxMultiplier; i++) {
09c2d0d3 951 promises.add(pool.execute())
9e619829
JB
952 }
953 await Promise.all(promises)
f06e48d8 954 for (const workerNode of pool.workerNodes) {
465b2940 955 expect(workerNode.usage).toStrictEqual({
a4e07f72
JB
956 tasks: {
957 executed: expect.any(Number),
958 executing: 0,
959 queued: 0,
df593701 960 maxQueued: 0,
68cbdc84 961 stolen: 0,
a4e07f72
JB
962 failed: 0
963 },
964 runTime: {
a4e07f72
JB
965 history: expect.any(CircularArray)
966 },
967 waitTime: {
a4e07f72
JB
968 history: expect.any(CircularArray)
969 },
5df69fab
JB
970 elu: {
971 idle: {
5df69fab
JB
972 history: expect.any(CircularArray)
973 },
974 active: {
5df69fab 975 history: expect.any(CircularArray)
f7510105 976 }
5df69fab 977 }
86bf340d 978 })
465b2940 979 expect(workerNode.usage.tasks.executed).toBeGreaterThan(0)
94407def
JB
980 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
981 numberOfWorkers * maxMultiplier
982 )
b97d82d8
JB
983 expect(workerNode.usage.runTime.history.length).toBe(0)
984 expect(workerNode.usage.waitTime.history.length).toBe(0)
985 expect(workerNode.usage.elu.idle.history.length).toBe(0)
986 expect(workerNode.usage.elu.active.history.length).toBe(0)
9e619829
JB
987 }
988 pool.setWorkerChoiceStrategy(WorkerChoiceStrategies.FAIR_SHARE)
f06e48d8 989 for (const workerNode of pool.workerNodes) {
465b2940 990 expect(workerNode.usage).toStrictEqual({
a4e07f72
JB
991 tasks: {
992 executed: 0,
993 executing: 0,
994 queued: 0,
df593701 995 maxQueued: 0,
68cbdc84 996 stolen: 0,
a4e07f72
JB
997 failed: 0
998 },
999 runTime: {
a4e07f72
JB
1000 history: expect.any(CircularArray)
1001 },
1002 waitTime: {
a4e07f72
JB
1003 history: expect.any(CircularArray)
1004 },
5df69fab
JB
1005 elu: {
1006 idle: {
5df69fab
JB
1007 history: expect.any(CircularArray)
1008 },
1009 active: {
5df69fab 1010 history: expect.any(CircularArray)
f7510105 1011 }
5df69fab 1012 }
86bf340d 1013 })
465b2940
JB
1014 expect(workerNode.usage.runTime.history.length).toBe(0)
1015 expect(workerNode.usage.waitTime.history.length).toBe(0)
b97d82d8
JB
1016 expect(workerNode.usage.elu.idle.history.length).toBe(0)
1017 expect(workerNode.usage.elu.active.history.length).toBe(0)
ee11a4a2 1018 }
fd7ebd49 1019 await pool.destroy()
ee11a4a2
JB
1020 })
1021
a1763c54
JB
1022 it("Verify that pool event emitter 'ready' event can register a callback", async () => {
1023 const pool = new DynamicClusterPool(
2431bdb4 1024 Math.floor(numberOfWorkers / 2),
164d950a 1025 numberOfWorkers,
a1763c54 1026 './tests/worker-files/cluster/testWorker.js'
164d950a 1027 )
d46660cd 1028 let poolInfo
a1763c54
JB
1029 let poolReady = 0
1030 pool.emitter.on(PoolEvents.ready, (info) => {
1031 ++poolReady
d46660cd
JB
1032 poolInfo = info
1033 })
a1763c54
JB
1034 await waitPoolEvents(pool, PoolEvents.ready, 1)
1035 expect(poolReady).toBe(1)
d46660cd 1036 expect(poolInfo).toStrictEqual({
23ccf9d7 1037 version,
d46660cd 1038 type: PoolTypes.dynamic,
a1763c54
JB
1039 worker: WorkerTypes.cluster,
1040 ready: true,
2431bdb4
JB
1041 strategy: WorkerChoiceStrategies.ROUND_ROBIN,
1042 minSize: expect.any(Number),
1043 maxSize: expect.any(Number),
1044 workerNodes: expect.any(Number),
1045 idleWorkerNodes: expect.any(Number),
1046 busyWorkerNodes: expect.any(Number),
1047 executedTasks: expect.any(Number),
1048 executingTasks: expect.any(Number),
2431bdb4
JB
1049 failedTasks: expect.any(Number)
1050 })
1051 await pool.destroy()
1052 })
1053
a1763c54
JB
1054 it("Verify that pool event emitter 'busy' event can register a callback", async () => {
1055 const pool = new FixedThreadPool(
2431bdb4 1056 numberOfWorkers,
a1763c54 1057 './tests/worker-files/thread/testWorker.js'
2431bdb4 1058 )
a1763c54
JB
1059 const promises = new Set()
1060 let poolBusy = 0
2431bdb4 1061 let poolInfo
a1763c54
JB
1062 pool.emitter.on(PoolEvents.busy, (info) => {
1063 ++poolBusy
2431bdb4
JB
1064 poolInfo = info
1065 })
a1763c54
JB
1066 for (let i = 0; i < numberOfWorkers * 2; i++) {
1067 promises.add(pool.execute())
1068 }
1069 await Promise.all(promises)
1070 // The `busy` event is triggered when the number of submitted tasks at once reach the number of fixed pool workers.
1071 // So in total numberOfWorkers + 1 times for a loop submitting up to numberOfWorkers * 2 tasks to the fixed pool.
1072 expect(poolBusy).toBe(numberOfWorkers + 1)
2431bdb4
JB
1073 expect(poolInfo).toStrictEqual({
1074 version,
a1763c54
JB
1075 type: PoolTypes.fixed,
1076 worker: WorkerTypes.thread,
1077 ready: expect.any(Boolean),
2431bdb4 1078 strategy: WorkerChoiceStrategies.ROUND_ROBIN,
d46660cd
JB
1079 minSize: expect.any(Number),
1080 maxSize: expect.any(Number),
1081 workerNodes: expect.any(Number),
1082 idleWorkerNodes: expect.any(Number),
1083 busyWorkerNodes: expect.any(Number),
a4e07f72
JB
1084 executedTasks: expect.any(Number),
1085 executingTasks: expect.any(Number),
a4e07f72 1086 failedTasks: expect.any(Number)
d46660cd 1087 })
164d950a
JB
1088 await pool.destroy()
1089 })
1090
a1763c54
JB
1091 it("Verify that pool event emitter 'full' event can register a callback", async () => {
1092 const pool = new DynamicThreadPool(
1093 Math.floor(numberOfWorkers / 2),
7c0ba920
JB
1094 numberOfWorkers,
1095 './tests/worker-files/thread/testWorker.js'
1096 )
09c2d0d3 1097 const promises = new Set()
a1763c54 1098 let poolFull = 0
d46660cd 1099 let poolInfo
a1763c54
JB
1100 pool.emitter.on(PoolEvents.full, (info) => {
1101 ++poolFull
d46660cd
JB
1102 poolInfo = info
1103 })
7c0ba920 1104 for (let i = 0; i < numberOfWorkers * 2; i++) {
f5d14e90 1105 promises.add(pool.execute())
7c0ba920 1106 }
cf597bc5 1107 await Promise.all(promises)
33e6bb4c 1108 expect(poolFull).toBe(1)
d46660cd 1109 expect(poolInfo).toStrictEqual({
23ccf9d7 1110 version,
a1763c54 1111 type: PoolTypes.dynamic,
d46660cd 1112 worker: WorkerTypes.thread,
2431bdb4
JB
1113 ready: expect.any(Boolean),
1114 strategy: WorkerChoiceStrategies.ROUND_ROBIN,
8735b4e5
JB
1115 minSize: expect.any(Number),
1116 maxSize: expect.any(Number),
1117 workerNodes: expect.any(Number),
1118 idleWorkerNodes: expect.any(Number),
1119 busyWorkerNodes: expect.any(Number),
1120 executedTasks: expect.any(Number),
1121 executingTasks: expect.any(Number),
1122 failedTasks: expect.any(Number)
1123 })
1124 await pool.destroy()
1125 })
1126
3e8611a8 1127 it("Verify that pool event emitter 'backPressure' event can register a callback", async () => {
b1aae695 1128 const pool = new FixedThreadPool(
8735b4e5
JB
1129 numberOfWorkers,
1130 './tests/worker-files/thread/testWorker.js',
1131 {
1132 enableTasksQueue: true
1133 }
1134 )
3e8611a8 1135 sinon.stub(pool, 'hasBackPressure').returns(true)
8735b4e5
JB
1136 const promises = new Set()
1137 let poolBackPressure = 0
1138 let poolInfo
1139 pool.emitter.on(PoolEvents.backPressure, (info) => {
1140 ++poolBackPressure
1141 poolInfo = info
1142 })
033f1776 1143 for (let i = 0; i < numberOfWorkers + 1; i++) {
8735b4e5
JB
1144 promises.add(pool.execute())
1145 }
1146 await Promise.all(promises)
033f1776 1147 expect(poolBackPressure).toBe(1)
8735b4e5
JB
1148 expect(poolInfo).toStrictEqual({
1149 version,
3e8611a8 1150 type: PoolTypes.fixed,
8735b4e5
JB
1151 worker: WorkerTypes.thread,
1152 ready: expect.any(Boolean),
1153 strategy: WorkerChoiceStrategies.ROUND_ROBIN,
d46660cd
JB
1154 minSize: expect.any(Number),
1155 maxSize: expect.any(Number),
1156 workerNodes: expect.any(Number),
1157 idleWorkerNodes: expect.any(Number),
1158 busyWorkerNodes: expect.any(Number),
a4e07f72
JB
1159 executedTasks: expect.any(Number),
1160 executingTasks: expect.any(Number),
3e8611a8
JB
1161 maxQueuedTasks: expect.any(Number),
1162 queuedTasks: expect.any(Number),
1163 backPressure: true,
68cbdc84 1164 stolenTasks: expect.any(Number),
a4e07f72 1165 failedTasks: expect.any(Number)
d46660cd 1166 })
3e8611a8 1167 expect(pool.hasBackPressure.called).toBe(true)
fd7ebd49 1168 await pool.destroy()
7c0ba920 1169 })
70a4f5ea 1170
90d7d101
JB
1171 it('Verify that listTaskFunctions() is working', async () => {
1172 const dynamicThreadPool = new DynamicThreadPool(
1173 Math.floor(numberOfWorkers / 2),
1174 numberOfWorkers,
1175 './tests/worker-files/thread/testMultipleTaskFunctionsWorker.js'
1176 )
1177 await waitPoolEvents(dynamicThreadPool, PoolEvents.ready, 1)
1178 expect(dynamicThreadPool.listTaskFunctions()).toStrictEqual([
6cd5248f 1179 DEFAULT_TASK_NAME,
90d7d101
JB
1180 'jsonIntegerSerialization',
1181 'factorial',
1182 'fibonacci'
1183 ])
1184 const fixedClusterPool = new FixedClusterPool(
1185 numberOfWorkers,
1186 './tests/worker-files/cluster/testMultipleTaskFunctionsWorker.js'
1187 )
1188 await waitPoolEvents(fixedClusterPool, PoolEvents.ready, 1)
1189 expect(fixedClusterPool.listTaskFunctions()).toStrictEqual([
6cd5248f 1190 DEFAULT_TASK_NAME,
90d7d101
JB
1191 'jsonIntegerSerialization',
1192 'factorial',
1193 'fibonacci'
1194 ])
0fe39c97
JB
1195 await dynamicThreadPool.destroy()
1196 await fixedClusterPool.destroy()
90d7d101
JB
1197 })
1198
1199 it('Verify that multiple task functions worker is working', async () => {
70a4f5ea 1200 const pool = new DynamicClusterPool(
2431bdb4 1201 Math.floor(numberOfWorkers / 2),
70a4f5ea 1202 numberOfWorkers,
90d7d101 1203 './tests/worker-files/cluster/testMultipleTaskFunctionsWorker.js'
70a4f5ea
JB
1204 )
1205 const data = { n: 10 }
82888165 1206 const result0 = await pool.execute(data)
30b963d4 1207 expect(result0).toStrictEqual({ ok: 1 })
70a4f5ea 1208 const result1 = await pool.execute(data, 'jsonIntegerSerialization')
30b963d4 1209 expect(result1).toStrictEqual({ ok: 1 })
70a4f5ea
JB
1210 const result2 = await pool.execute(data, 'factorial')
1211 expect(result2).toBe(3628800)
1212 const result3 = await pool.execute(data, 'fibonacci')
024daf59 1213 expect(result3).toBe(55)
5bb5be17
JB
1214 expect(pool.info.executingTasks).toBe(0)
1215 expect(pool.info.executedTasks).toBe(4)
b414b84c
JB
1216 for (const workerNode of pool.workerNodes) {
1217 expect(workerNode.info.taskFunctions).toStrictEqual([
6cd5248f 1218 DEFAULT_TASK_NAME,
b414b84c
JB
1219 'jsonIntegerSerialization',
1220 'factorial',
1221 'fibonacci'
1222 ])
1223 expect(workerNode.taskFunctionsUsage.size).toBe(3)
1224 for (const name of pool.listTaskFunctions()) {
5bb5be17
JB
1225 expect(workerNode.getTaskFunctionWorkerUsage(name)).toStrictEqual({
1226 tasks: {
1227 executed: expect.any(Number),
1228 executing: expect.any(Number),
1229 failed: 0,
68cbdc84
JB
1230 queued: 0,
1231 stolen: 0
5bb5be17
JB
1232 },
1233 runTime: {
1234 history: expect.any(CircularArray)
1235 },
1236 waitTime: {
1237 history: expect.any(CircularArray)
1238 },
1239 elu: {
1240 idle: {
1241 history: expect.any(CircularArray)
1242 },
1243 active: {
1244 history: expect.any(CircularArray)
1245 }
1246 }
1247 })
1248 expect(
1249 workerNode.getTaskFunctionWorkerUsage(name).tasks.executing
1250 ).toBeGreaterThanOrEqual(0)
1251 }
1252 }
0fe39c97 1253 await pool.destroy()
70a4f5ea 1254 })
3ec964d6 1255})