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