feat: improve IWRR implementation
[poolifier.git] / tests / pools / selection-strategies / selection-strategies.test.js
1 const { expect } = require('expect')
2 const {
3 DynamicClusterPool,
4 DynamicThreadPool,
5 FixedClusterPool,
6 FixedThreadPool,
7 WorkerChoiceStrategies
8 } = require('../../../lib')
9 const { CircularArray } = require('../../../lib/circular-array')
10
11 describe('Selection strategies test suite', () => {
12 const min = 0
13 const max = 3
14
15 it('Verify that WorkerChoiceStrategies enumeration provides string values', () => {
16 expect(WorkerChoiceStrategies.ROUND_ROBIN).toBe('ROUND_ROBIN')
17 expect(WorkerChoiceStrategies.LEAST_USED).toBe('LEAST_USED')
18 expect(WorkerChoiceStrategies.LEAST_BUSY).toBe('LEAST_BUSY')
19 expect(WorkerChoiceStrategies.LEAST_ELU).toBe('LEAST_ELU')
20 expect(WorkerChoiceStrategies.FAIR_SHARE).toBe('FAIR_SHARE')
21 expect(WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN).toBe(
22 'WEIGHTED_ROUND_ROBIN'
23 )
24 expect(WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN).toBe(
25 'INTERLEAVED_WEIGHTED_ROUND_ROBIN'
26 )
27 })
28
29 it('Verify ROUND_ROBIN strategy is the default at pool creation', async () => {
30 const pool = new DynamicThreadPool(
31 min,
32 max,
33 './tests/worker-files/thread/testWorker.js'
34 )
35 expect(pool.opts.workerChoiceStrategy).toBe(
36 WorkerChoiceStrategies.ROUND_ROBIN
37 )
38 // We need to clean up the resources after our test
39 await pool.destroy()
40 })
41
42 it('Verify available strategies are taken at pool creation', async () => {
43 for (const workerChoiceStrategy of Object.values(WorkerChoiceStrategies)) {
44 const pool = new FixedThreadPool(
45 max,
46 './tests/worker-files/thread/testWorker.js',
47 { workerChoiceStrategy }
48 )
49 expect(pool.opts.workerChoiceStrategy).toBe(workerChoiceStrategy)
50 expect(pool.workerChoiceStrategyContext.workerChoiceStrategy).toBe(
51 workerChoiceStrategy
52 )
53 await pool.destroy()
54 }
55 })
56
57 it('Verify available strategies can be set after pool creation', async () => {
58 for (const workerChoiceStrategy of Object.values(WorkerChoiceStrategies)) {
59 const pool = new DynamicThreadPool(
60 min,
61 max,
62 './tests/worker-files/thread/testWorker.js'
63 )
64 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
65 expect(pool.opts.workerChoiceStrategy).toBe(workerChoiceStrategy)
66 expect(pool.workerChoiceStrategyContext.workerChoiceStrategy).toBe(
67 workerChoiceStrategy
68 )
69 expect(pool.opts.workerChoiceStrategyOptions).toStrictEqual({
70 retries: 6,
71 runTime: { median: false },
72 waitTime: { median: false },
73 elu: { median: false }
74 })
75 expect(pool.workerChoiceStrategyContext.opts).toStrictEqual({
76 retries: 6,
77 runTime: { median: false },
78 waitTime: { median: false },
79 elu: { median: false }
80 })
81 await pool.destroy()
82 }
83 for (const workerChoiceStrategy of Object.values(WorkerChoiceStrategies)) {
84 const pool = new DynamicClusterPool(
85 min,
86 max,
87 './tests/worker-files/cluster/testWorker.js'
88 )
89 pool.setWorkerChoiceStrategy(workerChoiceStrategy, { retries: 3 })
90 expect(pool.opts.workerChoiceStrategy).toBe(workerChoiceStrategy)
91 expect(pool.workerChoiceStrategyContext.workerChoiceStrategy).toBe(
92 workerChoiceStrategy
93 )
94 expect(pool.opts.workerChoiceStrategyOptions).toStrictEqual({
95 retries: 3,
96 runTime: { median: false },
97 waitTime: { median: false },
98 elu: { median: false }
99 })
100 expect(pool.workerChoiceStrategyContext.opts).toStrictEqual({
101 retries: 3,
102 runTime: { median: false },
103 waitTime: { median: false },
104 elu: { median: false }
105 })
106 await pool.destroy()
107 }
108 })
109
110 it('Verify available strategies default internals at pool creation', async () => {
111 const pool = new FixedThreadPool(
112 max,
113 './tests/worker-files/thread/testWorker.js'
114 )
115 for (const workerChoiceStrategy of Object.values(WorkerChoiceStrategies)) {
116 if (workerChoiceStrategy === WorkerChoiceStrategies.ROUND_ROBIN) {
117 expect(
118 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
119 workerChoiceStrategy
120 ).nextWorkerNodeKey
121 ).toBe(0)
122 } else if (workerChoiceStrategy === WorkerChoiceStrategies.FAIR_SHARE) {
123 expect(
124 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
125 workerChoiceStrategy
126 ).workersVirtualTaskEndTimestamp
127 ).toBeInstanceOf(Array)
128 expect(
129 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
130 workerChoiceStrategy
131 ).workersVirtualTaskEndTimestamp.length
132 ).toBe(0)
133 } else if (
134 workerChoiceStrategy === WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
135 ) {
136 expect(
137 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
138 workerChoiceStrategy
139 ).nextWorkerNodeKey
140 ).toBe(0)
141 expect(
142 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
143 workerChoiceStrategy
144 ).defaultWorkerWeight
145 ).toBeGreaterThan(0)
146 expect(
147 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
148 workerChoiceStrategy
149 ).workerVirtualTaskRunTime
150 ).toBe(0)
151 }
152 }
153 await pool.destroy()
154 })
155
156 it('Verify ROUND_ROBIN strategy default policy', async () => {
157 const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN
158 let pool = new FixedThreadPool(
159 max,
160 './tests/worker-files/thread/testWorker.js',
161 { workerChoiceStrategy }
162 )
163 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
164 dynamicWorkerUsage: false,
165 dynamicWorkerReady: true
166 })
167 await pool.destroy()
168 pool = new DynamicThreadPool(
169 min,
170 max,
171 './tests/worker-files/thread/testWorker.js',
172 { workerChoiceStrategy }
173 )
174 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
175 dynamicWorkerUsage: false,
176 dynamicWorkerReady: true
177 })
178 // We need to clean up the resources after our test
179 await pool.destroy()
180 })
181
182 it('Verify ROUND_ROBIN strategy default tasks statistics requirements', async () => {
183 const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN
184 let pool = new FixedThreadPool(
185 max,
186 './tests/worker-files/thread/testWorker.js',
187 { workerChoiceStrategy }
188 )
189 expect(
190 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
191 ).toStrictEqual({
192 runTime: {
193 aggregate: false,
194 average: false,
195 median: false
196 },
197 waitTime: {
198 aggregate: false,
199 average: false,
200 median: false
201 },
202 elu: {
203 aggregate: false,
204 average: false,
205 median: false
206 }
207 })
208 await pool.destroy()
209 pool = new DynamicThreadPool(
210 min,
211 max,
212 './tests/worker-files/thread/testWorker.js',
213 { workerChoiceStrategy }
214 )
215 expect(
216 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
217 ).toStrictEqual({
218 runTime: {
219 aggregate: false,
220 average: false,
221 median: false
222 },
223 waitTime: {
224 aggregate: false,
225 average: false,
226 median: false
227 },
228 elu: {
229 aggregate: false,
230 average: false,
231 median: false
232 }
233 })
234 // We need to clean up the resources after our test
235 await pool.destroy()
236 })
237
238 it('Verify ROUND_ROBIN strategy can be run in a fixed pool', async () => {
239 const pool = new FixedThreadPool(
240 max,
241 './tests/worker-files/thread/testWorker.js',
242 { workerChoiceStrategy: WorkerChoiceStrategies.ROUND_ROBIN }
243 )
244 // TODO: Create a better test to cover `RoundRobinWorkerChoiceStrategy#choose`
245 const promises = new Set()
246 const maxMultiplier = 2
247 for (let i = 0; i < max * maxMultiplier; i++) {
248 promises.add(pool.execute())
249 }
250 await Promise.all(promises)
251 for (const workerNode of pool.workerNodes) {
252 expect(workerNode.usage).toStrictEqual({
253 tasks: {
254 executed: maxMultiplier,
255 executing: 0,
256 queued: 0,
257 maxQueued: 0,
258 stolen: 0,
259 failed: 0
260 },
261 runTime: {
262 history: new CircularArray()
263 },
264 waitTime: {
265 history: new CircularArray()
266 },
267 elu: {
268 idle: {
269 history: new CircularArray()
270 },
271 active: {
272 history: new CircularArray()
273 }
274 }
275 })
276 }
277 expect(
278 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
279 WorkerChoiceStrategies.ROUND_ROBIN
280 ).nextWorkerNodeKey
281 ).toBe(0)
282 // We need to clean up the resources after our test
283 await pool.destroy()
284 })
285
286 it('Verify ROUND_ROBIN strategy can be run in a dynamic pool', async () => {
287 const pool = new DynamicThreadPool(
288 min,
289 max,
290 './tests/worker-files/thread/testWorker.js',
291 { workerChoiceStrategy: WorkerChoiceStrategies.ROUND_ROBIN }
292 )
293 // TODO: Create a better test to cover `RoundRobinWorkerChoiceStrategy#choose`
294 const promises = new Set()
295 const maxMultiplier = 2
296 for (let i = 0; i < max * maxMultiplier; i++) {
297 promises.add(pool.execute())
298 }
299 await Promise.all(promises)
300 for (const workerNode of pool.workerNodes) {
301 expect(workerNode.usage).toStrictEqual({
302 tasks: {
303 executed: expect.any(Number),
304 executing: 0,
305 queued: 0,
306 maxQueued: 0,
307 stolen: 0,
308 failed: 0
309 },
310 runTime: {
311 history: new CircularArray()
312 },
313 waitTime: {
314 history: new CircularArray()
315 },
316 elu: {
317 idle: {
318 history: new CircularArray()
319 },
320 active: {
321 history: new CircularArray()
322 }
323 }
324 })
325 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
326 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
327 max * maxMultiplier
328 )
329 }
330 expect(
331 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
332 WorkerChoiceStrategies.ROUND_ROBIN
333 ).nextWorkerNodeKey
334 ).toBe(0)
335 // We need to clean up the resources after our test
336 await pool.destroy()
337 })
338
339 it('Verify ROUND_ROBIN strategy runtime behavior', async () => {
340 const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN
341 let pool = new FixedClusterPool(
342 max,
343 './tests/worker-files/cluster/testWorker.js',
344 { workerChoiceStrategy }
345 )
346 let results = new Set()
347 for (let i = 0; i < max; i++) {
348 results.add(pool.workerNodes[pool.chooseWorkerNode()].worker.id)
349 }
350 expect(results.size).toBe(max)
351 await pool.destroy()
352 pool = new FixedThreadPool(
353 max,
354 './tests/worker-files/thread/testWorker.js',
355 { workerChoiceStrategy }
356 )
357 results = new Set()
358 for (let i = 0; i < max; i++) {
359 results.add(pool.workerNodes[pool.chooseWorkerNode()].worker.threadId)
360 }
361 expect(results.size).toBe(max)
362 await pool.destroy()
363 })
364
365 it('Verify ROUND_ROBIN strategy internals are resets after setting it', async () => {
366 const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN
367 let pool = new FixedThreadPool(
368 max,
369 './tests/worker-files/thread/testWorker.js',
370 { workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN }
371 )
372 expect(
373 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
374 workerChoiceStrategy
375 ).nextWorkerNodeKey
376 ).toBeDefined()
377 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
378 expect(
379 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
380 pool.workerChoiceStrategyContext.workerChoiceStrategy
381 ).nextWorkerNodeKey
382 ).toBe(0)
383 await pool.destroy()
384 pool = new DynamicThreadPool(
385 min,
386 max,
387 './tests/worker-files/thread/testWorker.js',
388 { workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN }
389 )
390 expect(
391 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
392 workerChoiceStrategy
393 ).nextWorkerNodeKey
394 ).toBeDefined()
395 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
396 expect(
397 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
398 pool.workerChoiceStrategyContext.workerChoiceStrategy
399 ).nextWorkerNodeKey
400 ).toBe(0)
401 // We need to clean up the resources after our test
402 await pool.destroy()
403 })
404
405 it('Verify LEAST_USED strategy default policy', async () => {
406 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_USED
407 let pool = new FixedThreadPool(
408 max,
409 './tests/worker-files/thread/testWorker.js',
410 { workerChoiceStrategy }
411 )
412 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
413 dynamicWorkerUsage: false,
414 dynamicWorkerReady: true
415 })
416 await pool.destroy()
417 pool = new DynamicThreadPool(
418 min,
419 max,
420 './tests/worker-files/thread/testWorker.js',
421 { workerChoiceStrategy }
422 )
423 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
424 dynamicWorkerUsage: false,
425 dynamicWorkerReady: true
426 })
427 // We need to clean up the resources after our test
428 await pool.destroy()
429 })
430
431 it('Verify LEAST_USED strategy default tasks statistics requirements', async () => {
432 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_USED
433 let pool = new FixedThreadPool(
434 max,
435 './tests/worker-files/thread/testWorker.js',
436 { workerChoiceStrategy }
437 )
438 expect(
439 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
440 ).toStrictEqual({
441 runTime: {
442 aggregate: false,
443 average: false,
444 median: false
445 },
446 waitTime: {
447 aggregate: false,
448 average: false,
449 median: false
450 },
451 elu: {
452 aggregate: false,
453 average: false,
454 median: false
455 }
456 })
457 await pool.destroy()
458 pool = new DynamicThreadPool(
459 min,
460 max,
461 './tests/worker-files/thread/testWorker.js',
462 { workerChoiceStrategy }
463 )
464 expect(
465 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
466 ).toStrictEqual({
467 runTime: {
468 aggregate: false,
469 average: false,
470 median: false
471 },
472 waitTime: {
473 aggregate: false,
474 average: false,
475 median: false
476 },
477 elu: {
478 aggregate: false,
479 average: false,
480 median: false
481 }
482 })
483 // We need to clean up the resources after our test
484 await pool.destroy()
485 })
486
487 it('Verify LEAST_USED strategy can be run in a fixed pool', async () => {
488 const pool = new FixedThreadPool(
489 max,
490 './tests/worker-files/thread/testWorker.js',
491 { workerChoiceStrategy: WorkerChoiceStrategies.LEAST_USED }
492 )
493 // TODO: Create a better test to cover `LeastUsedWorkerChoiceStrategy#choose`
494 const promises = new Set()
495 const maxMultiplier = 2
496 for (let i = 0; i < max * maxMultiplier; i++) {
497 promises.add(pool.execute())
498 }
499 await Promise.all(promises)
500 for (const workerNode of pool.workerNodes) {
501 expect(workerNode.usage).toStrictEqual({
502 tasks: {
503 executed: expect.any(Number),
504 executing: 0,
505 queued: 0,
506 maxQueued: 0,
507 stolen: 0,
508 failed: 0
509 },
510 runTime: {
511 history: new CircularArray()
512 },
513 waitTime: {
514 history: new CircularArray()
515 },
516 elu: {
517 idle: {
518 history: new CircularArray()
519 },
520 active: {
521 history: new CircularArray()
522 }
523 }
524 })
525 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
526 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
527 max * maxMultiplier
528 )
529 }
530 // We need to clean up the resources after our test
531 await pool.destroy()
532 })
533
534 it('Verify LEAST_USED strategy can be run in a dynamic pool', async () => {
535 const pool = new DynamicThreadPool(
536 min,
537 max,
538 './tests/worker-files/thread/testWorker.js',
539 { workerChoiceStrategy: WorkerChoiceStrategies.LEAST_USED }
540 )
541 // TODO: Create a better test to cover `LeastUsedWorkerChoiceStrategy#choose`
542 const promises = new Set()
543 const maxMultiplier = 2
544 for (let i = 0; i < max * maxMultiplier; i++) {
545 promises.add(pool.execute())
546 }
547 await Promise.all(promises)
548 for (const workerNode of pool.workerNodes) {
549 expect(workerNode.usage).toStrictEqual({
550 tasks: {
551 executed: expect.any(Number),
552 executing: 0,
553 queued: 0,
554 maxQueued: 0,
555 stolen: 0,
556 failed: 0
557 },
558 runTime: {
559 history: new CircularArray()
560 },
561 waitTime: {
562 history: new CircularArray()
563 },
564 elu: {
565 idle: {
566 history: new CircularArray()
567 },
568 active: {
569 history: new CircularArray()
570 }
571 }
572 })
573 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
574 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
575 max * maxMultiplier
576 )
577 }
578 // We need to clean up the resources after our test
579 await pool.destroy()
580 })
581
582 it('Verify LEAST_BUSY strategy default policy', async () => {
583 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_BUSY
584 let pool = new FixedThreadPool(
585 max,
586 './tests/worker-files/thread/testWorker.js',
587 { workerChoiceStrategy }
588 )
589 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
590 dynamicWorkerUsage: false,
591 dynamicWorkerReady: true
592 })
593 await pool.destroy()
594 pool = new DynamicThreadPool(
595 min,
596 max,
597 './tests/worker-files/thread/testWorker.js',
598 { workerChoiceStrategy }
599 )
600 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
601 dynamicWorkerUsage: false,
602 dynamicWorkerReady: true
603 })
604 // We need to clean up the resources after our test
605 await pool.destroy()
606 })
607
608 it('Verify LEAST_BUSY strategy default tasks statistics requirements', async () => {
609 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_BUSY
610 let pool = new FixedThreadPool(
611 max,
612 './tests/worker-files/thread/testWorker.js',
613 { workerChoiceStrategy }
614 )
615 expect(
616 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
617 ).toStrictEqual({
618 runTime: {
619 aggregate: true,
620 average: false,
621 median: false
622 },
623 waitTime: {
624 aggregate: true,
625 average: false,
626 median: false
627 },
628 elu: {
629 aggregate: false,
630 average: false,
631 median: false
632 }
633 })
634 await pool.destroy()
635 pool = new DynamicThreadPool(
636 min,
637 max,
638 './tests/worker-files/thread/testWorker.js',
639 { workerChoiceStrategy }
640 )
641 expect(
642 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
643 ).toStrictEqual({
644 runTime: {
645 aggregate: true,
646 average: false,
647 median: false
648 },
649 waitTime: {
650 aggregate: true,
651 average: false,
652 median: false
653 },
654 elu: {
655 aggregate: false,
656 average: false,
657 median: false
658 }
659 })
660 // We need to clean up the resources after our test
661 await pool.destroy()
662 })
663
664 it('Verify LEAST_BUSY strategy can be run in a fixed pool', async () => {
665 const pool = new FixedThreadPool(
666 max,
667 './tests/worker-files/thread/testWorker.js',
668 { workerChoiceStrategy: WorkerChoiceStrategies.LEAST_BUSY }
669 )
670 // TODO: Create a better test to cover `LeastBusyWorkerChoiceStrategy#choose`
671 const promises = new Set()
672 const maxMultiplier = 2
673 for (let i = 0; i < max * maxMultiplier; i++) {
674 promises.add(pool.execute())
675 }
676 await Promise.all(promises)
677 for (const workerNode of pool.workerNodes) {
678 expect(workerNode.usage).toStrictEqual({
679 tasks: {
680 executed: expect.any(Number),
681 executing: 0,
682 queued: 0,
683 maxQueued: 0,
684 stolen: 0,
685 failed: 0
686 },
687 runTime: expect.objectContaining({
688 history: expect.any(CircularArray)
689 }),
690 waitTime: expect.objectContaining({
691 history: expect.any(CircularArray)
692 }),
693 elu: {
694 idle: {
695 history: new CircularArray()
696 },
697 active: {
698 history: new CircularArray()
699 }
700 }
701 })
702 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
703 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
704 max * maxMultiplier
705 )
706 if (workerNode.usage.runTime.aggregate == null) {
707 expect(workerNode.usage.runTime.aggregate).toBeUndefined()
708 } else {
709 expect(workerNode.usage.runTime.aggregate).toBeGreaterThan(0)
710 }
711 if (workerNode.usage.waitTime.aggregate == null) {
712 expect(workerNode.usage.waitTime.aggregate).toBeUndefined()
713 } else {
714 expect(workerNode.usage.waitTime.aggregate).toBeGreaterThan(0)
715 }
716 }
717 // We need to clean up the resources after our test
718 await pool.destroy()
719 })
720
721 it('Verify LEAST_BUSY strategy can be run in a dynamic pool', async () => {
722 const pool = new DynamicThreadPool(
723 min,
724 max,
725 './tests/worker-files/thread/testWorker.js',
726 { workerChoiceStrategy: WorkerChoiceStrategies.LEAST_BUSY }
727 )
728 // TODO: Create a better test to cover `LeastBusyWorkerChoiceStrategy#choose`
729 const promises = new Set()
730 const maxMultiplier = 2
731 for (let i = 0; i < max * maxMultiplier; i++) {
732 promises.add(pool.execute())
733 }
734 await Promise.all(promises)
735 for (const workerNode of pool.workerNodes) {
736 expect(workerNode.usage).toStrictEqual({
737 tasks: {
738 executed: expect.any(Number),
739 executing: 0,
740 queued: 0,
741 maxQueued: 0,
742 stolen: 0,
743 failed: 0
744 },
745 runTime: expect.objectContaining({
746 history: expect.any(CircularArray)
747 }),
748 waitTime: expect.objectContaining({
749 history: expect.any(CircularArray)
750 }),
751 elu: {
752 idle: {
753 history: new CircularArray()
754 },
755 active: {
756 history: new CircularArray()
757 }
758 }
759 })
760 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
761 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
762 max * maxMultiplier
763 )
764 if (workerNode.usage.runTime.aggregate == null) {
765 expect(workerNode.usage.runTime.aggregate).toBeUndefined()
766 } else {
767 expect(workerNode.usage.runTime.aggregate).toBeGreaterThan(0)
768 }
769 if (workerNode.usage.waitTime.aggregate == null) {
770 expect(workerNode.usage.waitTime.aggregate).toBeUndefined()
771 } else {
772 expect(workerNode.usage.waitTime.aggregate).toBeGreaterThan(0)
773 }
774 }
775 // We need to clean up the resources after our test
776 await pool.destroy()
777 })
778
779 it('Verify LEAST_ELU strategy default policy', async () => {
780 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_ELU
781 let pool = new FixedThreadPool(
782 max,
783 './tests/worker-files/thread/testWorker.js',
784 { workerChoiceStrategy }
785 )
786 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
787 dynamicWorkerUsage: false,
788 dynamicWorkerReady: true
789 })
790 await pool.destroy()
791 pool = new DynamicThreadPool(
792 min,
793 max,
794 './tests/worker-files/thread/testWorker.js',
795 { workerChoiceStrategy }
796 )
797 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
798 dynamicWorkerUsage: false,
799 dynamicWorkerReady: true
800 })
801 // We need to clean up the resources after our test
802 await pool.destroy()
803 })
804
805 it('Verify LEAST_ELU strategy default tasks statistics requirements', async () => {
806 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_ELU
807 let pool = new FixedThreadPool(
808 max,
809 './tests/worker-files/thread/testWorker.js',
810 { workerChoiceStrategy }
811 )
812 expect(
813 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
814 ).toStrictEqual({
815 runTime: {
816 aggregate: false,
817 average: false,
818 median: false
819 },
820 waitTime: {
821 aggregate: false,
822 average: false,
823 median: false
824 },
825 elu: {
826 aggregate: true,
827 average: false,
828 median: false
829 }
830 })
831 await pool.destroy()
832 pool = new DynamicThreadPool(
833 min,
834 max,
835 './tests/worker-files/thread/testWorker.js',
836 { workerChoiceStrategy }
837 )
838 expect(
839 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
840 ).toStrictEqual({
841 runTime: {
842 aggregate: false,
843 average: false,
844 median: false
845 },
846 waitTime: {
847 aggregate: false,
848 average: false,
849 median: false
850 },
851 elu: {
852 aggregate: true,
853 average: false,
854 median: false
855 }
856 })
857 // We need to clean up the resources after our test
858 await pool.destroy()
859 })
860
861 it('Verify LEAST_ELU strategy can be run in a fixed pool', async () => {
862 const pool = new FixedThreadPool(
863 max,
864 './tests/worker-files/thread/testWorker.js',
865 { workerChoiceStrategy: WorkerChoiceStrategies.LEAST_ELU }
866 )
867 // TODO: Create a better test to cover `LeastEluWorkerChoiceStrategy#choose`
868 const promises = new Set()
869 const maxMultiplier = 2
870 for (let i = 0; i < max * maxMultiplier; i++) {
871 promises.add(pool.execute())
872 }
873 await Promise.all(promises)
874 for (const workerNode of pool.workerNodes) {
875 expect(workerNode.usage).toStrictEqual({
876 tasks: {
877 executed: expect.any(Number),
878 executing: 0,
879 queued: 0,
880 maxQueued: 0,
881 stolen: 0,
882 failed: 0
883 },
884 runTime: {
885 history: new CircularArray()
886 },
887 waitTime: {
888 history: new CircularArray()
889 },
890 elu: expect.objectContaining({
891 idle: expect.objectContaining({
892 history: expect.any(CircularArray)
893 }),
894 active: expect.objectContaining({
895 history: expect.any(CircularArray)
896 })
897 })
898 })
899 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
900 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
901 max * maxMultiplier
902 )
903 if (workerNode.usage.elu.active.aggregate == null) {
904 expect(workerNode.usage.elu.active.aggregate).toBeUndefined()
905 } else {
906 expect(workerNode.usage.elu.active.aggregate).toBeGreaterThan(0)
907 }
908 if (workerNode.usage.elu.idle.aggregate == null) {
909 expect(workerNode.usage.elu.idle.aggregate).toBeUndefined()
910 } else {
911 expect(workerNode.usage.elu.idle.aggregate).toBeGreaterThanOrEqual(0)
912 }
913 if (workerNode.usage.elu.utilization == null) {
914 expect(workerNode.usage.elu.utilization).toBeUndefined()
915 } else {
916 expect(workerNode.usage.elu.utilization).toBeGreaterThanOrEqual(0)
917 expect(workerNode.usage.elu.utilization).toBeLessThanOrEqual(1)
918 }
919 }
920 // We need to clean up the resources after our test
921 await pool.destroy()
922 })
923
924 it('Verify LEAST_ELU strategy can be run in a dynamic pool', async () => {
925 const pool = new DynamicThreadPool(
926 min,
927 max,
928 './tests/worker-files/thread/testWorker.js',
929 { workerChoiceStrategy: WorkerChoiceStrategies.LEAST_ELU }
930 )
931 // TODO: Create a better test to cover `LeastEluWorkerChoiceStrategy#choose`
932 const promises = new Set()
933 const maxMultiplier = 2
934 for (let i = 0; i < max * maxMultiplier; i++) {
935 promises.add(pool.execute())
936 }
937 await Promise.all(promises)
938 for (const workerNode of pool.workerNodes) {
939 expect(workerNode.usage).toStrictEqual({
940 tasks: {
941 executed: expect.any(Number),
942 executing: 0,
943 queued: 0,
944 maxQueued: 0,
945 stolen: 0,
946 failed: 0
947 },
948 runTime: {
949 history: new CircularArray()
950 },
951 waitTime: {
952 history: new CircularArray()
953 },
954 elu: expect.objectContaining({
955 idle: expect.objectContaining({
956 history: expect.any(CircularArray)
957 }),
958 active: expect.objectContaining({
959 history: expect.any(CircularArray)
960 })
961 })
962 })
963 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
964 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
965 max * maxMultiplier
966 )
967 if (workerNode.usage.elu.active.aggregate == null) {
968 expect(workerNode.usage.elu.active.aggregate).toBeUndefined()
969 } else {
970 expect(workerNode.usage.elu.active.aggregate).toBeGreaterThan(0)
971 }
972 if (workerNode.usage.elu.idle.aggregate == null) {
973 expect(workerNode.usage.elu.idle.aggregate).toBeUndefined()
974 } else {
975 expect(workerNode.usage.elu.idle.aggregate).toBeGreaterThanOrEqual(0)
976 }
977 if (workerNode.usage.elu.utilization == null) {
978 expect(workerNode.usage.elu.utilization).toBeUndefined()
979 } else {
980 expect(workerNode.usage.elu.utilization).toBeGreaterThanOrEqual(0)
981 expect(workerNode.usage.elu.utilization).toBeLessThanOrEqual(1)
982 }
983 }
984 // We need to clean up the resources after our test
985 await pool.destroy()
986 })
987
988 it('Verify FAIR_SHARE strategy default policy', async () => {
989 const workerChoiceStrategy = WorkerChoiceStrategies.FAIR_SHARE
990 let pool = new FixedThreadPool(
991 max,
992 './tests/worker-files/thread/testWorker.js',
993 { workerChoiceStrategy }
994 )
995 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
996 dynamicWorkerUsage: false,
997 dynamicWorkerReady: true
998 })
999 await pool.destroy()
1000 pool = new DynamicThreadPool(
1001 min,
1002 max,
1003 './tests/worker-files/thread/testWorker.js',
1004 { workerChoiceStrategy }
1005 )
1006 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
1007 dynamicWorkerUsage: false,
1008 dynamicWorkerReady: true
1009 })
1010 // We need to clean up the resources after our test
1011 await pool.destroy()
1012 })
1013
1014 it('Verify FAIR_SHARE strategy default tasks statistics requirements', async () => {
1015 const workerChoiceStrategy = WorkerChoiceStrategies.FAIR_SHARE
1016 let pool = new FixedThreadPool(
1017 max,
1018 './tests/worker-files/thread/testWorker.js',
1019 { workerChoiceStrategy }
1020 )
1021 expect(
1022 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
1023 ).toStrictEqual({
1024 runTime: {
1025 aggregate: true,
1026 average: true,
1027 median: false
1028 },
1029 waitTime: {
1030 aggregate: false,
1031 average: false,
1032 median: false
1033 },
1034 elu: {
1035 aggregate: true,
1036 average: true,
1037 median: false
1038 }
1039 })
1040 await pool.destroy()
1041 pool = new DynamicThreadPool(
1042 min,
1043 max,
1044 './tests/worker-files/thread/testWorker.js',
1045 { workerChoiceStrategy }
1046 )
1047 expect(
1048 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
1049 ).toStrictEqual({
1050 runTime: {
1051 aggregate: true,
1052 average: true,
1053 median: false
1054 },
1055 waitTime: {
1056 aggregate: false,
1057 average: false,
1058 median: false
1059 },
1060 elu: {
1061 aggregate: true,
1062 average: true,
1063 median: false
1064 }
1065 })
1066 // We need to clean up the resources after our test
1067 await pool.destroy()
1068 })
1069
1070 it('Verify FAIR_SHARE strategy can be run in a fixed pool', async () => {
1071 const pool = new FixedThreadPool(
1072 max,
1073 './tests/worker-files/thread/testWorker.js',
1074 { workerChoiceStrategy: WorkerChoiceStrategies.FAIR_SHARE }
1075 )
1076 // TODO: Create a better test to cover `FairShareChoiceStrategy#choose`
1077 const promises = new Set()
1078 const maxMultiplier = 2
1079 for (let i = 0; i < max * maxMultiplier; i++) {
1080 promises.add(pool.execute())
1081 }
1082 await Promise.all(promises)
1083 for (const workerNode of pool.workerNodes) {
1084 expect(workerNode.usage).toStrictEqual({
1085 tasks: {
1086 executed: expect.any(Number),
1087 executing: 0,
1088 queued: 0,
1089 maxQueued: 0,
1090 stolen: 0,
1091 failed: 0
1092 },
1093 runTime: expect.objectContaining({
1094 history: expect.any(CircularArray)
1095 }),
1096 waitTime: {
1097 history: new CircularArray()
1098 },
1099 elu: expect.objectContaining({
1100 idle: expect.objectContaining({
1101 history: expect.any(CircularArray)
1102 }),
1103 active: expect.objectContaining({
1104 history: expect.any(CircularArray)
1105 })
1106 })
1107 })
1108 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
1109 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
1110 max * maxMultiplier
1111 )
1112 if (workerNode.usage.runTime.aggregate == null) {
1113 expect(workerNode.usage.runTime.aggregate).toBeUndefined()
1114 } else {
1115 expect(workerNode.usage.runTime.aggregate).toBeGreaterThan(0)
1116 }
1117 if (workerNode.usage.runTime.average == null) {
1118 expect(workerNode.usage.runTime.average).toBeUndefined()
1119 } else {
1120 expect(workerNode.usage.runTime.average).toBeGreaterThan(0)
1121 }
1122 if (workerNode.usage.elu.active.aggregate == null) {
1123 expect(workerNode.usage.elu.active.aggregate).toBeUndefined()
1124 } else {
1125 expect(workerNode.usage.elu.active.aggregate).toBeGreaterThan(0)
1126 }
1127 if (workerNode.usage.elu.idle.aggregate == null) {
1128 expect(workerNode.usage.elu.idle.aggregate).toBeUndefined()
1129 } else {
1130 expect(workerNode.usage.elu.idle.aggregate).toBeGreaterThanOrEqual(0)
1131 }
1132 if (workerNode.usage.elu.utilization == null) {
1133 expect(workerNode.usage.elu.utilization).toBeUndefined()
1134 } else {
1135 expect(workerNode.usage.elu.utilization).toBeGreaterThanOrEqual(0)
1136 expect(workerNode.usage.elu.utilization).toBeLessThanOrEqual(1)
1137 }
1138 }
1139 expect(
1140 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1141 pool.workerChoiceStrategyContext.workerChoiceStrategy
1142 ).workersVirtualTaskEndTimestamp.length
1143 ).toBe(pool.workerNodes.length)
1144 // We need to clean up the resources after our test
1145 await pool.destroy()
1146 })
1147
1148 it('Verify FAIR_SHARE strategy can be run in a dynamic pool', async () => {
1149 const pool = new DynamicThreadPool(
1150 min,
1151 max,
1152 './tests/worker-files/thread/testWorker.js',
1153 { workerChoiceStrategy: WorkerChoiceStrategies.FAIR_SHARE }
1154 )
1155 // TODO: Create a better test to cover `FairShareChoiceStrategy#choose`
1156 const promises = new Set()
1157 const maxMultiplier = 2
1158 for (let i = 0; i < max * maxMultiplier; i++) {
1159 promises.add(pool.execute())
1160 }
1161 await Promise.all(promises)
1162 for (const workerNode of pool.workerNodes) {
1163 expect(workerNode.usage).toStrictEqual({
1164 tasks: {
1165 executed: expect.any(Number),
1166 executing: 0,
1167 queued: 0,
1168 maxQueued: 0,
1169 stolen: 0,
1170 failed: 0
1171 },
1172 runTime: expect.objectContaining({
1173 history: expect.any(CircularArray)
1174 }),
1175 waitTime: {
1176 history: new CircularArray()
1177 },
1178 elu: expect.objectContaining({
1179 idle: expect.objectContaining({
1180 history: expect.any(CircularArray)
1181 }),
1182 active: expect.objectContaining({
1183 history: expect.any(CircularArray)
1184 })
1185 })
1186 })
1187 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
1188 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
1189 max * maxMultiplier
1190 )
1191 if (workerNode.usage.runTime.aggregate == null) {
1192 expect(workerNode.usage.runTime.aggregate).toBeUndefined()
1193 } else {
1194 expect(workerNode.usage.runTime.aggregate).toBeGreaterThan(0)
1195 }
1196 if (workerNode.usage.runTime.average == null) {
1197 expect(workerNode.usage.runTime.average).toBeUndefined()
1198 } else {
1199 expect(workerNode.usage.runTime.average).toBeGreaterThan(0)
1200 }
1201 if (workerNode.usage.elu.active.aggregate == null) {
1202 expect(workerNode.usage.elu.active.aggregate).toBeUndefined()
1203 } else {
1204 expect(workerNode.usage.elu.active.aggregate).toBeGreaterThan(0)
1205 }
1206 if (workerNode.usage.elu.idle.aggregate == null) {
1207 expect(workerNode.usage.elu.idle.aggregate).toBeUndefined()
1208 } else {
1209 expect(workerNode.usage.elu.idle.aggregate).toBeGreaterThanOrEqual(0)
1210 }
1211 if (workerNode.usage.elu.utilization == null) {
1212 expect(workerNode.usage.elu.utilization).toBeUndefined()
1213 } else {
1214 expect(workerNode.usage.elu.utilization).toBeGreaterThanOrEqual(0)
1215 expect(workerNode.usage.elu.utilization).toBeLessThanOrEqual(1)
1216 }
1217 }
1218 expect(
1219 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1220 pool.workerChoiceStrategyContext.workerChoiceStrategy
1221 ).workersVirtualTaskEndTimestamp.length
1222 ).toBe(pool.workerNodes.length)
1223 // We need to clean up the resources after our test
1224 await pool.destroy()
1225 })
1226
1227 it('Verify FAIR_SHARE strategy can be run in a dynamic pool with median runtime statistic', async () => {
1228 const pool = new DynamicThreadPool(
1229 min,
1230 max,
1231 './tests/worker-files/thread/testWorker.js',
1232 {
1233 workerChoiceStrategy: WorkerChoiceStrategies.FAIR_SHARE,
1234 workerChoiceStrategyOptions: {
1235 runTime: { median: true }
1236 }
1237 }
1238 )
1239 // TODO: Create a better test to cover `FairShareChoiceStrategy#choose`
1240 const promises = new Set()
1241 const maxMultiplier = 2
1242 for (let i = 0; i < max * maxMultiplier; i++) {
1243 promises.add(pool.execute())
1244 }
1245 await Promise.all(promises)
1246 for (const workerNode of pool.workerNodes) {
1247 expect(workerNode.usage).toStrictEqual({
1248 tasks: {
1249 executed: expect.any(Number),
1250 executing: 0,
1251 queued: 0,
1252 maxQueued: 0,
1253 stolen: 0,
1254 failed: 0
1255 },
1256 runTime: expect.objectContaining({
1257 history: expect.any(CircularArray)
1258 }),
1259 waitTime: {
1260 history: new CircularArray()
1261 },
1262 elu: expect.objectContaining({
1263 idle: expect.objectContaining({
1264 history: expect.any(CircularArray)
1265 }),
1266 active: expect.objectContaining({
1267 history: expect.any(CircularArray)
1268 })
1269 })
1270 })
1271 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
1272 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
1273 max * maxMultiplier
1274 )
1275 if (workerNode.usage.runTime.aggregate == null) {
1276 expect(workerNode.usage.runTime.aggregate).toBeUndefined()
1277 } else {
1278 expect(workerNode.usage.runTime.aggregate).toBeGreaterThan(0)
1279 }
1280 if (workerNode.usage.runTime.median == null) {
1281 expect(workerNode.usage.runTime.median).toBeUndefined()
1282 } else {
1283 expect(workerNode.usage.runTime.median).toBeGreaterThan(0)
1284 }
1285 if (workerNode.usage.elu.active.aggregate == null) {
1286 expect(workerNode.usage.elu.active.aggregate).toBeUndefined()
1287 } else {
1288 expect(workerNode.usage.elu.active.aggregate).toBeGreaterThan(0)
1289 }
1290 if (workerNode.usage.elu.idle.aggregate == null) {
1291 expect(workerNode.usage.elu.idle.aggregate).toBeUndefined()
1292 } else {
1293 expect(workerNode.usage.elu.idle.aggregate).toBeGreaterThanOrEqual(0)
1294 }
1295 if (workerNode.usage.elu.utilization == null) {
1296 expect(workerNode.usage.elu.utilization).toBeUndefined()
1297 } else {
1298 expect(workerNode.usage.elu.utilization).toBeGreaterThanOrEqual(0)
1299 expect(workerNode.usage.elu.utilization).toBeLessThanOrEqual(1)
1300 }
1301 }
1302 expect(
1303 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1304 pool.workerChoiceStrategyContext.workerChoiceStrategy
1305 ).workersVirtualTaskEndTimestamp.length
1306 ).toBe(pool.workerNodes.length)
1307 // We need to clean up the resources after our test
1308 await pool.destroy()
1309 })
1310
1311 it('Verify FAIR_SHARE strategy internals are resets after setting it', async () => {
1312 const workerChoiceStrategy = WorkerChoiceStrategies.FAIR_SHARE
1313 let pool = new FixedThreadPool(
1314 max,
1315 './tests/worker-files/thread/testWorker.js'
1316 )
1317 expect(
1318 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1319 workerChoiceStrategy
1320 ).workersVirtualTaskEndTimestamp
1321 ).toBeInstanceOf(Array)
1322 expect(
1323 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1324 workerChoiceStrategy
1325 ).workersVirtualTaskEndTimestamp.length
1326 ).toBe(0)
1327 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1328 workerChoiceStrategy
1329 ).workersVirtualTaskEndTimestamp[0] = performance.now()
1330 expect(
1331 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1332 workerChoiceStrategy
1333 ).workersVirtualTaskEndTimestamp.length
1334 ).toBe(1)
1335 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
1336 expect(
1337 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1338 workerChoiceStrategy
1339 ).workersVirtualTaskEndTimestamp
1340 ).toBeInstanceOf(Array)
1341 expect(
1342 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1343 workerChoiceStrategy
1344 ).workersVirtualTaskEndTimestamp.length
1345 ).toBe(0)
1346 await pool.destroy()
1347 pool = new DynamicThreadPool(
1348 min,
1349 max,
1350 './tests/worker-files/thread/testWorker.js'
1351 )
1352 expect(
1353 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1354 workerChoiceStrategy
1355 ).workersVirtualTaskEndTimestamp
1356 ).toBeInstanceOf(Array)
1357 expect(
1358 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1359 workerChoiceStrategy
1360 ).workersVirtualTaskEndTimestamp.length
1361 ).toBe(0)
1362 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1363 workerChoiceStrategy
1364 ).workersVirtualTaskEndTimestamp[0] = performance.now()
1365 expect(
1366 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1367 workerChoiceStrategy
1368 ).workersVirtualTaskEndTimestamp.length
1369 ).toBe(1)
1370 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
1371 expect(
1372 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1373 workerChoiceStrategy
1374 ).workersVirtualTaskEndTimestamp
1375 ).toBeInstanceOf(Array)
1376 expect(
1377 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1378 workerChoiceStrategy
1379 ).workersVirtualTaskEndTimestamp.length
1380 ).toBe(0)
1381 // We need to clean up the resources after our test
1382 await pool.destroy()
1383 })
1384
1385 it('Verify WEIGHTED_ROUND_ROBIN strategy default policy', async () => {
1386 const workerChoiceStrategy = WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
1387 let pool = new FixedThreadPool(
1388 max,
1389 './tests/worker-files/thread/testWorker.js',
1390 { workerChoiceStrategy }
1391 )
1392 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
1393 dynamicWorkerUsage: false,
1394 dynamicWorkerReady: true
1395 })
1396 await pool.destroy()
1397 pool = new DynamicThreadPool(
1398 min,
1399 max,
1400 './tests/worker-files/thread/testWorker.js',
1401 { workerChoiceStrategy }
1402 )
1403 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
1404 dynamicWorkerUsage: false,
1405 dynamicWorkerReady: true
1406 })
1407 // We need to clean up the resources after our test
1408 await pool.destroy()
1409 })
1410
1411 it('Verify WEIGHTED_ROUND_ROBIN strategy default tasks statistics requirements', async () => {
1412 const workerChoiceStrategy = WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
1413 let pool = new FixedThreadPool(
1414 max,
1415 './tests/worker-files/thread/testWorker.js',
1416 { workerChoiceStrategy }
1417 )
1418 expect(
1419 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
1420 ).toStrictEqual({
1421 runTime: {
1422 aggregate: true,
1423 average: true,
1424 median: false
1425 },
1426 waitTime: {
1427 aggregate: false,
1428 average: false,
1429 median: false
1430 },
1431 elu: {
1432 aggregate: false,
1433 average: false,
1434 median: false
1435 }
1436 })
1437 await pool.destroy()
1438 pool = new DynamicThreadPool(
1439 min,
1440 max,
1441 './tests/worker-files/thread/testWorker.js',
1442 { workerChoiceStrategy }
1443 )
1444 expect(
1445 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
1446 ).toStrictEqual({
1447 runTime: {
1448 aggregate: true,
1449 average: true,
1450 median: false
1451 },
1452 waitTime: {
1453 aggregate: false,
1454 average: false,
1455 median: false
1456 },
1457 elu: {
1458 aggregate: false,
1459 average: false,
1460 median: false
1461 }
1462 })
1463 // We need to clean up the resources after our test
1464 await pool.destroy()
1465 })
1466
1467 it('Verify WEIGHTED_ROUND_ROBIN strategy can be run in a fixed pool', async () => {
1468 const pool = new FixedThreadPool(
1469 max,
1470 './tests/worker-files/thread/testWorker.js',
1471 { workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN }
1472 )
1473 // TODO: Create a better test to cover `WeightedRoundRobinWorkerChoiceStrategy#choose`
1474 const promises = new Set()
1475 const maxMultiplier = 2
1476 for (let i = 0; i < max * maxMultiplier; i++) {
1477 promises.add(pool.execute())
1478 }
1479 await Promise.all(promises)
1480 for (const workerNode of pool.workerNodes) {
1481 expect(workerNode.usage).toStrictEqual({
1482 tasks: {
1483 executed: expect.any(Number),
1484 executing: 0,
1485 queued: 0,
1486 maxQueued: 0,
1487 stolen: 0,
1488 failed: 0
1489 },
1490 runTime: expect.objectContaining({
1491 history: expect.any(CircularArray)
1492 }),
1493 waitTime: {
1494 history: new CircularArray()
1495 },
1496 elu: {
1497 idle: {
1498 history: new CircularArray()
1499 },
1500 active: {
1501 history: new CircularArray()
1502 }
1503 }
1504 })
1505 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
1506 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
1507 max * maxMultiplier
1508 )
1509 if (workerNode.usage.runTime.aggregate == null) {
1510 expect(workerNode.usage.runTime.aggregate).toBeUndefined()
1511 } else {
1512 expect(workerNode.usage.runTime.aggregate).toBeGreaterThan(0)
1513 }
1514 if (workerNode.usage.runTime.average == null) {
1515 expect(workerNode.usage.runTime.average).toBeUndefined()
1516 } else {
1517 expect(workerNode.usage.runTime.average).toBeGreaterThan(0)
1518 }
1519 }
1520 expect(
1521 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1522 pool.workerChoiceStrategyContext.workerChoiceStrategy
1523 ).defaultWorkerWeight
1524 ).toBeGreaterThan(0)
1525 expect(
1526 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1527 pool.workerChoiceStrategyContext.workerChoiceStrategy
1528 ).workerVirtualTaskRunTime
1529 ).toBeGreaterThanOrEqual(0)
1530 // We need to clean up the resources after our test
1531 await pool.destroy()
1532 })
1533
1534 it('Verify WEIGHTED_ROUND_ROBIN strategy can be run in a dynamic pool', async () => {
1535 const pool = new DynamicThreadPool(
1536 min,
1537 max,
1538 './tests/worker-files/thread/testWorker.js',
1539 { workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN }
1540 )
1541 // TODO: Create a better test to cover `WeightedRoundRobinWorkerChoiceStrategy#choose`
1542 const promises = new Set()
1543 const maxMultiplier = 2
1544 for (let i = 0; i < max * maxMultiplier; i++) {
1545 promises.add(pool.execute())
1546 }
1547 await Promise.all(promises)
1548 for (const workerNode of pool.workerNodes) {
1549 expect(workerNode.usage).toStrictEqual({
1550 tasks: {
1551 executed: expect.any(Number),
1552 executing: 0,
1553 queued: 0,
1554 maxQueued: 0,
1555 stolen: 0,
1556 failed: 0
1557 },
1558 runTime: expect.objectContaining({
1559 history: expect.any(CircularArray)
1560 }),
1561 waitTime: {
1562 history: new CircularArray()
1563 },
1564 elu: {
1565 idle: {
1566 history: new CircularArray()
1567 },
1568 active: {
1569 history: new CircularArray()
1570 }
1571 }
1572 })
1573 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
1574 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
1575 max * maxMultiplier
1576 )
1577 if (workerNode.usage.runTime.aggregate == null) {
1578 expect(workerNode.usage.runTime.aggregate).toBeUndefined()
1579 } else {
1580 expect(workerNode.usage.runTime.aggregate).toBeGreaterThan(0)
1581 }
1582 if (workerNode.usage.runTime.average == null) {
1583 expect(workerNode.usage.runTime.average).toBeUndefined()
1584 } else {
1585 expect(workerNode.usage.runTime.average).toBeGreaterThan(0)
1586 }
1587 }
1588 expect(
1589 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1590 pool.workerChoiceStrategyContext.workerChoiceStrategy
1591 ).defaultWorkerWeight
1592 ).toBeGreaterThan(0)
1593 expect(
1594 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1595 pool.workerChoiceStrategyContext.workerChoiceStrategy
1596 ).workerVirtualTaskRunTime
1597 ).toBeGreaterThanOrEqual(0)
1598 // We need to clean up the resources after our test
1599 await pool.destroy()
1600 })
1601
1602 it('Verify WEIGHTED_ROUND_ROBIN strategy can be run in a dynamic pool with median runtime statistic', async () => {
1603 const pool = new DynamicThreadPool(
1604 min,
1605 max,
1606 './tests/worker-files/thread/testWorker.js',
1607 {
1608 workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN,
1609 workerChoiceStrategyOptions: {
1610 runTime: { median: true }
1611 }
1612 }
1613 )
1614 // TODO: Create a better test to cover `WeightedRoundRobinWorkerChoiceStrategy#choose`
1615 const promises = new Set()
1616 const maxMultiplier = 2
1617 for (let i = 0; i < max * maxMultiplier; i++) {
1618 promises.add(pool.execute())
1619 }
1620 await Promise.all(promises)
1621 for (const workerNode of pool.workerNodes) {
1622 expect(workerNode.usage).toStrictEqual({
1623 tasks: {
1624 executed: expect.any(Number),
1625 executing: 0,
1626 queued: 0,
1627 maxQueued: 0,
1628 stolen: 0,
1629 failed: 0
1630 },
1631 runTime: expect.objectContaining({
1632 history: expect.any(CircularArray)
1633 }),
1634 waitTime: {
1635 history: new CircularArray()
1636 },
1637 elu: {
1638 idle: {
1639 history: new CircularArray()
1640 },
1641 active: {
1642 history: new CircularArray()
1643 }
1644 }
1645 })
1646 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
1647 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
1648 max * maxMultiplier
1649 )
1650 if (workerNode.usage.runTime.aggregate == null) {
1651 expect(workerNode.usage.runTime.aggregate).toBeUndefined()
1652 } else {
1653 expect(workerNode.usage.runTime.aggregate).toBeGreaterThan(0)
1654 }
1655 if (workerNode.usage.runTime.median == null) {
1656 expect(workerNode.usage.runTime.median).toBeUndefined()
1657 } else {
1658 expect(workerNode.usage.runTime.median).toBeGreaterThan(0)
1659 }
1660 }
1661 expect(
1662 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1663 pool.workerChoiceStrategyContext.workerChoiceStrategy
1664 ).defaultWorkerWeight
1665 ).toBeGreaterThan(0)
1666 expect(
1667 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1668 pool.workerChoiceStrategyContext.workerChoiceStrategy
1669 ).workerVirtualTaskRunTime
1670 ).toBeGreaterThanOrEqual(0)
1671 // We need to clean up the resources after our test
1672 await pool.destroy()
1673 })
1674
1675 it('Verify WEIGHTED_ROUND_ROBIN strategy internals are resets after setting it', async () => {
1676 const workerChoiceStrategy = WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
1677 let pool = new FixedThreadPool(
1678 max,
1679 './tests/worker-files/thread/testWorker.js'
1680 )
1681 expect(
1682 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1683 workerChoiceStrategy
1684 ).nextWorkerNodeKey
1685 ).toBeDefined()
1686 expect(
1687 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1688 workerChoiceStrategy
1689 ).defaultWorkerWeight
1690 ).toBeDefined()
1691 expect(
1692 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1693 workerChoiceStrategy
1694 ).workerVirtualTaskRunTime
1695 ).toBeDefined()
1696 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
1697 expect(
1698 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1699 pool.workerChoiceStrategyContext.workerChoiceStrategy
1700 ).nextWorkerNodeKey
1701 ).toBe(0)
1702 expect(
1703 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1704 pool.workerChoiceStrategyContext.workerChoiceStrategy
1705 ).defaultWorkerWeight
1706 ).toBeGreaterThan(0)
1707 expect(
1708 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1709 workerChoiceStrategy
1710 ).workerVirtualTaskRunTime
1711 ).toBe(0)
1712 await pool.destroy()
1713 pool = new DynamicThreadPool(
1714 min,
1715 max,
1716 './tests/worker-files/thread/testWorker.js'
1717 )
1718 expect(
1719 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1720 workerChoiceStrategy
1721 ).nextWorkerNodeKey
1722 ).toBeDefined()
1723 expect(
1724 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1725 workerChoiceStrategy
1726 ).defaultWorkerWeight
1727 ).toBeDefined()
1728 expect(
1729 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1730 workerChoiceStrategy
1731 ).workerVirtualTaskRunTime
1732 ).toBeDefined()
1733 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
1734 expect(
1735 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1736 pool.workerChoiceStrategyContext.workerChoiceStrategy
1737 ).nextWorkerNodeKey
1738 ).toBe(0)
1739 expect(
1740 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1741 pool.workerChoiceStrategyContext.workerChoiceStrategy
1742 ).defaultWorkerWeight
1743 ).toBeGreaterThan(0)
1744 expect(
1745 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1746 workerChoiceStrategy
1747 ).workerVirtualTaskRunTime
1748 ).toBe(0)
1749 // We need to clean up the resources after our test
1750 await pool.destroy()
1751 })
1752
1753 it('Verify INTERLEAVED_WEIGHTED_ROUND_ROBIN strategy default policy', async () => {
1754 const workerChoiceStrategy =
1755 WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
1756 let pool = new FixedThreadPool(
1757 max,
1758 './tests/worker-files/thread/testWorker.js',
1759 { workerChoiceStrategy }
1760 )
1761 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
1762 dynamicWorkerUsage: false,
1763 dynamicWorkerReady: true
1764 })
1765 await pool.destroy()
1766 pool = new DynamicThreadPool(
1767 min,
1768 max,
1769 './tests/worker-files/thread/testWorker.js',
1770 { workerChoiceStrategy }
1771 )
1772 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
1773 dynamicWorkerUsage: false,
1774 dynamicWorkerReady: true
1775 })
1776 // We need to clean up the resources after our test
1777 await pool.destroy()
1778 })
1779
1780 it('Verify INTERLEAVED_WEIGHTED_ROUND_ROBIN strategy default tasks statistics requirements', async () => {
1781 const workerChoiceStrategy =
1782 WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
1783 let pool = new FixedThreadPool(
1784 max,
1785 './tests/worker-files/thread/testWorker.js',
1786 { workerChoiceStrategy }
1787 )
1788 expect(
1789 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
1790 ).toStrictEqual({
1791 runTime: {
1792 aggregate: true,
1793 average: true,
1794 median: false
1795 },
1796 waitTime: {
1797 aggregate: false,
1798 average: false,
1799 median: false
1800 },
1801 elu: {
1802 aggregate: false,
1803 average: false,
1804 median: false
1805 }
1806 })
1807 await pool.destroy()
1808 pool = new DynamicThreadPool(
1809 min,
1810 max,
1811 './tests/worker-files/thread/testWorker.js',
1812 { workerChoiceStrategy }
1813 )
1814 expect(
1815 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
1816 ).toStrictEqual({
1817 runTime: {
1818 aggregate: true,
1819 average: true,
1820 median: false
1821 },
1822 waitTime: {
1823 aggregate: false,
1824 average: false,
1825 median: false
1826 },
1827 elu: {
1828 aggregate: false,
1829 average: false,
1830 median: false
1831 }
1832 })
1833 // We need to clean up the resources after our test
1834 await pool.destroy()
1835 })
1836
1837 it('Verify INTERLEAVED_WEIGHTED_ROUND_ROBIN strategy can be run in a fixed pool', async () => {
1838 const pool = new FixedThreadPool(
1839 max,
1840 './tests/worker-files/thread/testWorker.js',
1841 {
1842 workerChoiceStrategy:
1843 WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
1844 }
1845 )
1846 // TODO: Create a better test to cover `InterleavedWeightedRoundRobinWorkerChoiceStrategy#choose`
1847 const promises = new Set()
1848 const maxMultiplier = 2
1849 for (let i = 0; i < max * maxMultiplier; i++) {
1850 promises.add(pool.execute())
1851 }
1852 await Promise.all(promises)
1853 for (const workerNode of pool.workerNodes) {
1854 expect(workerNode.usage).toStrictEqual({
1855 tasks: {
1856 executed: expect.any(Number),
1857 executing: 0,
1858 queued: 0,
1859 maxQueued: 0,
1860 stolen: 0,
1861 failed: 0
1862 },
1863 runTime: expect.objectContaining({
1864 history: expect.any(CircularArray)
1865 }),
1866 waitTime: {
1867 history: new CircularArray()
1868 },
1869 elu: {
1870 idle: {
1871 history: new CircularArray()
1872 },
1873 active: {
1874 history: new CircularArray()
1875 }
1876 }
1877 })
1878 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
1879 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
1880 max * maxMultiplier
1881 )
1882 }
1883 expect(
1884 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1885 pool.workerChoiceStrategyContext.workerChoiceStrategy
1886 ).defaultWorkerWeight
1887 ).toBeGreaterThan(0)
1888 expect(
1889 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1890 pool.workerChoiceStrategyContext.workerChoiceStrategy
1891 ).roundId
1892 ).toBe(0)
1893 expect(
1894 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1895 pool.workerChoiceStrategyContext.workerChoiceStrategy
1896 ).workerNodeId
1897 ).toBe(0)
1898 expect(
1899 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1900 pool.workerChoiceStrategyContext.workerChoiceStrategy
1901 ).nextWorkerNodeKey
1902 ).toBe(0)
1903 expect(
1904 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1905 pool.workerChoiceStrategyContext.workerChoiceStrategy
1906 ).roundWeights
1907 ).toStrictEqual([
1908 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1909 pool.workerChoiceStrategyContext.workerChoiceStrategy
1910 ).defaultWorkerWeight
1911 ])
1912 // We need to clean up the resources after our test
1913 await pool.destroy()
1914 })
1915
1916 it('Verify INTERLEAVED_WEIGHTED_ROUND_ROBIN strategy can be run in a dynamic pool', async () => {
1917 const pool = new DynamicThreadPool(
1918 min,
1919 max,
1920 './tests/worker-files/thread/testWorker.js',
1921 {
1922 workerChoiceStrategy:
1923 WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
1924 }
1925 )
1926 // TODO: Create a better test to cover `InterleavedWeightedRoundRobinWorkerChoiceStrategy#choose`
1927 const promises = new Set()
1928 const maxMultiplier = 2
1929 for (let i = 0; i < max * maxMultiplier; i++) {
1930 promises.add(pool.execute())
1931 }
1932 await Promise.all(promises)
1933 for (const workerNode of pool.workerNodes) {
1934 expect(workerNode.usage).toStrictEqual({
1935 tasks: {
1936 executed: expect.any(Number),
1937 executing: 0,
1938 queued: 0,
1939 maxQueued: 0,
1940 stolen: 0,
1941 failed: 0
1942 },
1943 runTime: expect.objectContaining({
1944 history: expect.any(CircularArray)
1945 }),
1946 waitTime: {
1947 history: new CircularArray()
1948 },
1949 elu: {
1950 idle: {
1951 history: new CircularArray()
1952 },
1953 active: {
1954 history: new CircularArray()
1955 }
1956 }
1957 })
1958 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
1959 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
1960 max * maxMultiplier
1961 )
1962 }
1963 expect(
1964 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1965 pool.workerChoiceStrategyContext.workerChoiceStrategy
1966 ).defaultWorkerWeight
1967 ).toBeGreaterThan(0)
1968 expect(
1969 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1970 pool.workerChoiceStrategyContext.workerChoiceStrategy
1971 ).roundId
1972 ).toBe(0)
1973 expect(
1974 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1975 pool.workerChoiceStrategyContext.workerChoiceStrategy
1976 ).workerNodeId
1977 ).toBe(0)
1978 expect(
1979 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1980 pool.workerChoiceStrategyContext.workerChoiceStrategy
1981 ).nextWorkerNodeKey
1982 ).toBe(0)
1983 expect(
1984 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1985 pool.workerChoiceStrategyContext.workerChoiceStrategy
1986 ).roundWeights
1987 ).toStrictEqual([
1988 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1989 pool.workerChoiceStrategyContext.workerChoiceStrategy
1990 ).defaultWorkerWeight
1991 ])
1992 // We need to clean up the resources after our test
1993 await pool.destroy()
1994 })
1995
1996 it('Verify INTERLEAVED_WEIGHTED_ROUND_ROBIN strategy internals are resets after setting it', async () => {
1997 const workerChoiceStrategy =
1998 WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
1999 let pool = new FixedThreadPool(
2000 max,
2001 './tests/worker-files/thread/testWorker.js'
2002 )
2003 expect(
2004 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2005 workerChoiceStrategy
2006 ).roundId
2007 ).toBeDefined()
2008 expect(
2009 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2010 workerChoiceStrategy
2011 ).nextWorkerNodeKey
2012 ).toBeDefined()
2013 expect(
2014 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2015 workerChoiceStrategy
2016 ).defaultWorkerWeight
2017 ).toBeDefined()
2018 expect(
2019 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2020 workerChoiceStrategy
2021 ).roundWeights
2022 ).toBeDefined()
2023 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
2024 expect(
2025 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2026 workerChoiceStrategy
2027 ).roundId
2028 ).toBe(0)
2029 expect(
2030 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2031 pool.workerChoiceStrategyContext.workerChoiceStrategy
2032 ).nextWorkerNodeKey
2033 ).toBe(0)
2034 expect(
2035 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2036 pool.workerChoiceStrategyContext.workerChoiceStrategy
2037 ).defaultWorkerWeight
2038 ).toBeGreaterThan(0)
2039 expect(
2040 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2041 workerChoiceStrategy
2042 ).roundWeights
2043 ).toStrictEqual([
2044 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2045 pool.workerChoiceStrategyContext.workerChoiceStrategy
2046 ).defaultWorkerWeight
2047 ])
2048 await pool.destroy()
2049 pool = new DynamicThreadPool(
2050 min,
2051 max,
2052 './tests/worker-files/thread/testWorker.js'
2053 )
2054 expect(
2055 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2056 workerChoiceStrategy
2057 ).roundId
2058 ).toBeDefined()
2059 expect(
2060 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2061 workerChoiceStrategy
2062 ).nextWorkerNodeKey
2063 ).toBeDefined()
2064 expect(
2065 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2066 workerChoiceStrategy
2067 ).defaultWorkerWeight
2068 ).toBeDefined()
2069 expect(
2070 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2071 workerChoiceStrategy
2072 ).roundWeights
2073 ).toBeDefined()
2074 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
2075 expect(
2076 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2077 pool.workerChoiceStrategyContext.workerChoiceStrategy
2078 ).nextWorkerNodeKey
2079 ).toBe(0)
2080 expect(
2081 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2082 pool.workerChoiceStrategyContext.workerChoiceStrategy
2083 ).defaultWorkerWeight
2084 ).toBeGreaterThan(0)
2085 expect(
2086 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2087 workerChoiceStrategy
2088 ).roundWeights
2089 ).toStrictEqual([
2090 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2091 pool.workerChoiceStrategyContext.workerChoiceStrategy
2092 ).defaultWorkerWeight
2093 ])
2094 // We need to clean up the resources after our test
2095 await pool.destroy()
2096 })
2097
2098 it('Verify unknown strategy throw error', () => {
2099 expect(
2100 () =>
2101 new DynamicThreadPool(
2102 min,
2103 max,
2104 './tests/worker-files/thread/testWorker.js',
2105 { workerChoiceStrategy: 'UNKNOWN_STRATEGY' }
2106 )
2107 ).toThrowError("Invalid worker choice strategy 'UNKNOWN_STRATEGY'")
2108 })
2109 })