test: add least elu strategy test with dynamic pool
[poolifier.git] / tests / pools / selection-strategies / selection-strategies.test.js
1 const { expect } = require('expect')
2 const {
3 WorkerChoiceStrategies,
4 DynamicThreadPool,
5 FixedThreadPool,
6 FixedClusterPool
7 } = require('../../../lib')
8 const { CircularArray } = require('../../../lib/circular-array')
9 const TestUtils = require('../../test-utils')
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 await pool.destroy()
70 }
71 })
72
73 it('Verify available strategies default internals at pool creation', async () => {
74 const pool = new FixedThreadPool(
75 max,
76 './tests/worker-files/thread/testWorker.js'
77 )
78 for (const workerChoiceStrategy of Object.values(WorkerChoiceStrategies)) {
79 if (workerChoiceStrategy === WorkerChoiceStrategies.ROUND_ROBIN) {
80 expect(
81 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
82 workerChoiceStrategy
83 ).nextWorkerNodeId
84 ).toBe(0)
85 } else if (workerChoiceStrategy === WorkerChoiceStrategies.FAIR_SHARE) {
86 expect(
87 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
88 workerChoiceStrategy
89 ).workersVirtualTaskEndTimestamp
90 ).toBeInstanceOf(Array)
91 expect(
92 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
93 workerChoiceStrategy
94 ).workersVirtualTaskEndTimestamp.length
95 ).toBe(0)
96 } else if (
97 workerChoiceStrategy === WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
98 ) {
99 expect(
100 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
101 workerChoiceStrategy
102 ).currentWorkerNodeId
103 ).toBe(0)
104 expect(
105 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
106 workerChoiceStrategy
107 ).defaultWorkerWeight
108 ).toBeGreaterThan(0)
109 expect(
110 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
111 workerChoiceStrategy
112 ).workerVirtualTaskRunTime
113 ).toBe(0)
114 }
115 }
116 await pool.destroy()
117 })
118
119 it('Verify ROUND_ROBIN strategy default tasks usage statistics requirements', async () => {
120 const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN
121 let pool = new FixedThreadPool(
122 max,
123 './tests/worker-files/thread/testWorker.js',
124 { workerChoiceStrategy }
125 )
126 expect(
127 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
128 ).toStrictEqual({
129 runTime: {
130 aggregate: false,
131 average: false,
132 median: false
133 },
134 waitTime: {
135 aggregate: false,
136 average: false,
137 median: false
138 },
139 elu: false
140 })
141 await pool.destroy()
142 pool = new DynamicThreadPool(
143 min,
144 max,
145 './tests/worker-files/thread/testWorker.js',
146 { workerChoiceStrategy }
147 )
148 expect(
149 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
150 ).toStrictEqual({
151 runTime: {
152 aggregate: false,
153 average: false,
154 median: false
155 },
156 waitTime: {
157 aggregate: false,
158 average: false,
159 median: false
160 },
161 elu: false
162 })
163 // We need to clean up the resources after our test
164 await pool.destroy()
165 })
166
167 it('Verify ROUND_ROBIN strategy can be run in a fixed pool', async () => {
168 const pool = new FixedThreadPool(
169 max,
170 './tests/worker-files/thread/testWorker.js',
171 { workerChoiceStrategy: WorkerChoiceStrategies.ROUND_ROBIN }
172 )
173 // TODO: Create a better test to cover `RoundRobinWorkerChoiceStrategy#choose`
174 const promises = new Set()
175 const maxMultiplier = 2
176 for (let i = 0; i < max * maxMultiplier; i++) {
177 promises.add(pool.execute())
178 }
179 await Promise.all(promises)
180 for (const workerNode of pool.workerNodes) {
181 expect(workerNode.workerUsage).toStrictEqual({
182 tasks: {
183 executed: maxMultiplier,
184 executing: 0,
185 queued: 0,
186 failed: 0
187 },
188 runTime: {
189 aggregate: 0,
190 average: 0,
191 median: 0,
192 history: expect.any(CircularArray)
193 },
194 waitTime: {
195 aggregate: 0,
196 average: 0,
197 median: 0,
198 history: expect.any(CircularArray)
199 },
200 elu: undefined
201 })
202 }
203 expect(
204 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
205 WorkerChoiceStrategies.ROUND_ROBIN
206 ).nextWorkerNodeId
207 ).toBe(0)
208 // We need to clean up the resources after our test
209 await pool.destroy()
210 })
211
212 it('Verify ROUND_ROBIN strategy can be run in a dynamic pool', async () => {
213 const pool = new DynamicThreadPool(
214 min,
215 max,
216 './tests/worker-files/thread/testWorker.js',
217 { workerChoiceStrategy: WorkerChoiceStrategies.ROUND_ROBIN }
218 )
219 // TODO: Create a better test to cover `RoundRobinWorkerChoiceStrategy#choose`
220 const promises = new Set()
221 const maxMultiplier = 2
222 for (let i = 0; i < max * maxMultiplier; i++) {
223 promises.add(pool.execute())
224 }
225 await Promise.all(promises)
226 for (const workerNode of pool.workerNodes) {
227 expect(workerNode.workerUsage).toStrictEqual({
228 tasks: {
229 executed: maxMultiplier,
230 executing: 0,
231 queued: 0,
232 failed: 0
233 },
234 runTime: {
235 aggregate: 0,
236 average: 0,
237 median: 0,
238 history: expect.any(CircularArray)
239 },
240 waitTime: {
241 aggregate: 0,
242 average: 0,
243 median: 0,
244 history: expect.any(CircularArray)
245 },
246 elu: undefined
247 })
248 }
249 expect(
250 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
251 WorkerChoiceStrategies.ROUND_ROBIN
252 ).nextWorkerNodeId
253 ).toBe(0)
254 // We need to clean up the resources after our test
255 await pool.destroy()
256 })
257
258 it('Verify ROUND_ROBIN strategy runtime behavior', async () => {
259 const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN
260 let pool = new FixedClusterPool(
261 max,
262 './tests/worker-files/cluster/testWorker.js',
263 { workerChoiceStrategy }
264 )
265 let results = new Set()
266 for (let i = 0; i < max; i++) {
267 results.add(pool.workerNodes[pool.chooseWorkerNode()].worker.id)
268 }
269 expect(results.size).toBe(max)
270 await pool.destroy()
271 pool = new FixedThreadPool(
272 max,
273 './tests/worker-files/thread/testWorker.js',
274 { workerChoiceStrategy }
275 )
276 results = new Set()
277 for (let i = 0; i < max; i++) {
278 results.add(pool.workerNodes[pool.chooseWorkerNode()].worker.threadId)
279 }
280 expect(results.size).toBe(max)
281 await pool.destroy()
282 })
283
284 it('Verify ROUND_ROBIN strategy internals are resets after setting it', async () => {
285 const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN
286 let pool = new FixedThreadPool(
287 max,
288 './tests/worker-files/thread/testWorker.js',
289 { workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN }
290 )
291 expect(
292 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
293 workerChoiceStrategy
294 ).nextWorkerNodeId
295 ).toBeDefined()
296 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
297 expect(
298 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
299 pool.workerChoiceStrategyContext.workerChoiceStrategy
300 ).nextWorkerNodeId
301 ).toBe(0)
302 await pool.destroy()
303 pool = new DynamicThreadPool(
304 min,
305 max,
306 './tests/worker-files/thread/testWorker.js',
307 { workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN }
308 )
309 expect(
310 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
311 workerChoiceStrategy
312 ).nextWorkerNodeId
313 ).toBeDefined()
314 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
315 expect(
316 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
317 pool.workerChoiceStrategyContext.workerChoiceStrategy
318 ).nextWorkerNodeId
319 ).toBe(0)
320 // We need to clean up the resources after our test
321 await pool.destroy()
322 })
323
324 it('Verify LEAST_USED strategy default tasks usage statistics requirements', async () => {
325 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_USED
326 let pool = new FixedThreadPool(
327 max,
328 './tests/worker-files/thread/testWorker.js',
329 { workerChoiceStrategy }
330 )
331 expect(
332 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
333 ).toStrictEqual({
334 runTime: {
335 aggregate: false,
336 average: false,
337 median: false
338 },
339 waitTime: {
340 aggregate: false,
341 average: false,
342 median: false
343 },
344 elu: false
345 })
346 await pool.destroy()
347 pool = new DynamicThreadPool(
348 min,
349 max,
350 './tests/worker-files/thread/testWorker.js',
351 { workerChoiceStrategy }
352 )
353 expect(
354 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
355 ).toStrictEqual({
356 runTime: {
357 aggregate: false,
358 average: false,
359 median: false
360 },
361 waitTime: {
362 aggregate: false,
363 average: false,
364 median: false
365 },
366 elu: false
367 })
368 // We need to clean up the resources after our test
369 await pool.destroy()
370 })
371
372 it('Verify LEAST_USED strategy can be run in a fixed pool', async () => {
373 const pool = new FixedThreadPool(
374 max,
375 './tests/worker-files/thread/testWorker.js',
376 { workerChoiceStrategy: WorkerChoiceStrategies.LEAST_USED }
377 )
378 // TODO: Create a better test to cover `LeastUsedWorkerChoiceStrategy#choose`
379 const promises = new Set()
380 const maxMultiplier = 2
381 for (let i = 0; i < max * maxMultiplier; i++) {
382 promises.add(pool.execute())
383 }
384 await Promise.all(promises)
385 for (const workerNode of pool.workerNodes) {
386 expect(workerNode.workerUsage).toStrictEqual({
387 tasks: {
388 executed: maxMultiplier,
389 executing: 0,
390 queued: 0,
391 failed: 0
392 },
393 runTime: {
394 aggregate: 0,
395 average: 0,
396 median: 0,
397 history: expect.any(CircularArray)
398 },
399 waitTime: {
400 aggregate: 0,
401 average: 0,
402 median: 0,
403 history: expect.any(CircularArray)
404 },
405 elu: undefined
406 })
407 }
408 // We need to clean up the resources after our test
409 await pool.destroy()
410 })
411
412 it('Verify LEAST_USED strategy can be run in a dynamic pool', async () => {
413 const pool = new DynamicThreadPool(
414 min,
415 max,
416 './tests/worker-files/thread/testWorker.js',
417 { workerChoiceStrategy: WorkerChoiceStrategies.LEAST_USED }
418 )
419 // TODO: Create a better test to cover `LeastUsedWorkerChoiceStrategy#choose`
420 const promises = new Set()
421 const maxMultiplier = 2
422 for (let i = 0; i < max * maxMultiplier; i++) {
423 promises.add(pool.execute())
424 }
425 await Promise.all(promises)
426 for (const workerNode of pool.workerNodes) {
427 expect(workerNode.workerUsage).toStrictEqual({
428 tasks: {
429 executed: maxMultiplier,
430 executing: 0,
431 queued: 0,
432 failed: 0
433 },
434 runTime: {
435 aggregate: 0,
436 average: 0,
437 median: 0,
438 history: expect.any(CircularArray)
439 },
440 waitTime: {
441 aggregate: 0,
442 average: 0,
443 median: 0,
444 history: expect.any(CircularArray)
445 },
446
447 elu: undefined
448 })
449 }
450 // We need to clean up the resources after our test
451 await pool.destroy()
452 })
453
454 it('Verify LEAST_BUSY strategy default tasks usage statistics requirements', async () => {
455 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_BUSY
456 let pool = new FixedThreadPool(
457 max,
458 './tests/worker-files/thread/testWorker.js',
459 { workerChoiceStrategy }
460 )
461 expect(
462 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
463 ).toStrictEqual({
464 runTime: {
465 aggregate: true,
466 average: false,
467 median: false
468 },
469 waitTime: {
470 aggregate: true,
471 average: false,
472 median: false
473 },
474 elu: false
475 })
476 await pool.destroy()
477 pool = new DynamicThreadPool(
478 min,
479 max,
480 './tests/worker-files/thread/testWorker.js',
481 { workerChoiceStrategy }
482 )
483 expect(
484 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
485 ).toStrictEqual({
486 runTime: {
487 aggregate: true,
488 average: false,
489 median: false
490 },
491 waitTime: {
492 aggregate: true,
493 average: false,
494 median: false
495 },
496 elu: false
497 })
498 // We need to clean up the resources after our test
499 await pool.destroy()
500 })
501
502 it('Verify LEAST_BUSY strategy can be run in a fixed pool', async () => {
503 const pool = new FixedThreadPool(
504 max,
505 './tests/worker-files/thread/testWorker.js',
506 { workerChoiceStrategy: WorkerChoiceStrategies.LEAST_BUSY }
507 )
508 // TODO: Create a better test to cover `LeastBusyWorkerChoiceStrategy#choose`
509 const promises = new Set()
510 const maxMultiplier = 2
511 for (let i = 0; i < max * maxMultiplier; i++) {
512 promises.add(pool.execute())
513 }
514 await Promise.all(promises)
515 for (const workerNode of pool.workerNodes) {
516 expect(workerNode.workerUsage).toStrictEqual({
517 tasks: {
518 executed: expect.any(Number),
519 executing: 0,
520 queued: 0,
521 failed: 0
522 },
523 runTime: {
524 aggregate: expect.any(Number),
525 average: 0,
526 median: 0,
527 history: expect.any(CircularArray)
528 },
529 waitTime: {
530 aggregate: expect.any(Number),
531 average: 0,
532 median: 0,
533 history: expect.any(CircularArray)
534 },
535 elu: undefined
536 })
537 expect(workerNode.workerUsage.tasks.executed).toBeGreaterThanOrEqual(0)
538 expect(workerNode.workerUsage.tasks.executed).toBeLessThanOrEqual(
539 max * maxMultiplier
540 )
541 expect(workerNode.workerUsage.runTime.aggregate).toBeGreaterThanOrEqual(0)
542 expect(workerNode.workerUsage.waitTime.aggregate).toBeGreaterThanOrEqual(
543 0
544 )
545 }
546 // We need to clean up the resources after our test
547 await pool.destroy()
548 })
549
550 it('Verify LEAST_BUSY strategy can be run in a dynamic pool', async () => {
551 const pool = new DynamicThreadPool(
552 min,
553 max,
554 './tests/worker-files/thread/testWorker.js',
555 { workerChoiceStrategy: WorkerChoiceStrategies.LEAST_BUSY }
556 )
557 // TODO: Create a better test to cover `LeastBusyWorkerChoiceStrategy#choose`
558 const promises = new Set()
559 const maxMultiplier = 2
560 for (let i = 0; i < max * maxMultiplier; i++) {
561 promises.add(pool.execute())
562 }
563 await Promise.all(promises)
564 for (const workerNode of pool.workerNodes) {
565 expect(workerNode.workerUsage).toStrictEqual({
566 tasks: {
567 executed: expect.any(Number),
568 executing: 0,
569 queued: 0,
570 failed: 0
571 },
572 runTime: {
573 aggregate: expect.any(Number),
574 average: 0,
575 median: 0,
576 history: expect.any(CircularArray)
577 },
578 waitTime: {
579 aggregate: expect.any(Number),
580 average: 0,
581 median: 0,
582 history: expect.any(CircularArray)
583 },
584 elu: undefined
585 })
586 expect(workerNode.workerUsage.tasks.executed).toBeGreaterThan(0)
587 expect(workerNode.workerUsage.tasks.executed).toBeLessThanOrEqual(
588 max * maxMultiplier
589 )
590 expect(workerNode.workerUsage.runTime.aggregate).toBeGreaterThan(0)
591 expect(workerNode.workerUsage.waitTime.aggregate).toBeGreaterThan(0)
592 }
593 // We need to clean up the resources after our test
594 await pool.destroy()
595 })
596
597 it('Verify LEAST_ELU strategy default tasks usage statistics requirements', async () => {
598 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_ELU
599 let pool = new FixedThreadPool(
600 max,
601 './tests/worker-files/thread/testWorker.js',
602 { workerChoiceStrategy }
603 )
604 expect(
605 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
606 ).toStrictEqual({
607 runTime: {
608 aggregate: false,
609 average: false,
610 median: false
611 },
612 waitTime: {
613 aggregate: false,
614 average: false,
615 median: false
616 },
617 elu: true
618 })
619 await pool.destroy()
620 pool = new DynamicThreadPool(
621 min,
622 max,
623 './tests/worker-files/thread/testWorker.js',
624 { workerChoiceStrategy }
625 )
626 expect(
627 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
628 ).toStrictEqual({
629 runTime: {
630 aggregate: false,
631 average: false,
632 median: false
633 },
634 waitTime: {
635 aggregate: false,
636 average: false,
637 median: false
638 },
639 elu: true
640 })
641 // We need to clean up the resources after our test
642 await pool.destroy()
643 })
644
645 it('Verify LEAST_ELU strategy can be run in a fixed pool', async () => {
646 const pool = new FixedThreadPool(
647 max,
648 './tests/worker-files/thread/testWorker.js',
649 { workerChoiceStrategy: WorkerChoiceStrategies.LEAST_ELU }
650 )
651 // TODO: Create a better test to cover `LeastEluWorkerChoiceStrategy#choose`
652 const maxMultiplier = 2
653 for (let i = 0; i < max * maxMultiplier; i++) {
654 await pool.execute()
655 if (i !== max * maxMultiplier - 1) await TestUtils.sleep(500)
656 }
657 for (const workerNode of pool.workerNodes) {
658 const expectedWorkerUsage = {
659 tasks: {
660 executed: expect.any(Number),
661 executing: 0,
662 queued: 0,
663 failed: 0
664 },
665 runTime: {
666 aggregate: 0,
667 average: 0,
668 median: 0,
669 history: expect.any(CircularArray)
670 },
671 waitTime: {
672 aggregate: 0,
673 average: 0,
674 median: 0,
675 history: expect.any(CircularArray)
676 }
677 }
678 if (workerNode.workerUsage.elu === undefined) {
679 expect(workerNode.workerUsage).toStrictEqual({
680 ...expectedWorkerUsage,
681 elu: undefined
682 })
683 } else {
684 expect(workerNode.workerUsage).toStrictEqual({
685 ...expectedWorkerUsage,
686 elu: {
687 active: expect.any(Number),
688 idle: 0,
689 utilization: 1
690 }
691 })
692 }
693 expect(workerNode.workerUsage.tasks.executed).toBeGreaterThanOrEqual(0)
694 expect(workerNode.workerUsage.tasks.executed).toBeLessThanOrEqual(
695 max * maxMultiplier
696 )
697 }
698 // We need to clean up the resources after our test
699 await pool.destroy()
700 })
701
702 it('Verify LEAST_ELU strategy can be run in a dynamic pool', async () => {
703 const pool = new DynamicThreadPool(
704 min,
705 max,
706 './tests/worker-files/thread/testWorker.js',
707 { workerChoiceStrategy: WorkerChoiceStrategies.LEAST_ELU }
708 )
709 // TODO: Create a better test to cover `LeastEluWorkerChoiceStrategy#choose`
710 const maxMultiplier = 2
711 for (let i = 0; i < max * maxMultiplier; i++) {
712 await pool.execute()
713 if (i !== max * maxMultiplier - 1) await TestUtils.sleep(500)
714 }
715 for (const workerNode of pool.workerNodes) {
716 const expectedWorkerUsage = {
717 tasks: {
718 executed: expect.any(Number),
719 executing: 0,
720 queued: 0,
721 failed: 0
722 },
723 runTime: {
724 aggregate: 0,
725 average: 0,
726 median: 0,
727 history: expect.any(CircularArray)
728 },
729 waitTime: {
730 aggregate: 0,
731 average: 0,
732 median: 0,
733 history: expect.any(CircularArray)
734 }
735 }
736 if (workerNode.workerUsage.elu === undefined) {
737 expect(workerNode.workerUsage).toStrictEqual({
738 ...expectedWorkerUsage,
739 elu: undefined
740 })
741 } else {
742 expect(workerNode.workerUsage).toStrictEqual({
743 ...expectedWorkerUsage,
744 elu: {
745 active: expect.any(Number),
746 idle: 0,
747 utilization: 1
748 }
749 })
750 }
751 expect(workerNode.workerUsage.tasks.executed).toBeGreaterThanOrEqual(0)
752 expect(workerNode.workerUsage.tasks.executed).toBeLessThanOrEqual(
753 max * maxMultiplier
754 )
755 }
756 // We need to clean up the resources after our test
757 await pool.destroy()
758 })
759
760 it('Verify FAIR_SHARE strategy default tasks usage statistics requirements', async () => {
761 const workerChoiceStrategy = WorkerChoiceStrategies.FAIR_SHARE
762 let pool = new FixedThreadPool(
763 max,
764 './tests/worker-files/thread/testWorker.js',
765 { workerChoiceStrategy }
766 )
767 expect(
768 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
769 ).toStrictEqual({
770 runTime: {
771 aggregate: true,
772 average: true,
773 median: false
774 },
775 waitTime: {
776 aggregate: false,
777 average: false,
778 median: false
779 },
780 elu: false
781 })
782 await pool.destroy()
783 pool = new DynamicThreadPool(
784 min,
785 max,
786 './tests/worker-files/thread/testWorker.js',
787 { workerChoiceStrategy }
788 )
789 expect(
790 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
791 ).toStrictEqual({
792 runTime: {
793 aggregate: true,
794 average: true,
795 median: false
796 },
797 waitTime: {
798 aggregate: false,
799 average: false,
800 median: false
801 },
802 elu: false
803 })
804 // We need to clean up the resources after our test
805 await pool.destroy()
806 })
807
808 it('Verify FAIR_SHARE strategy can be run in a fixed pool', async () => {
809 const pool = new FixedThreadPool(
810 max,
811 './tests/worker-files/thread/testWorker.js',
812 { workerChoiceStrategy: WorkerChoiceStrategies.FAIR_SHARE }
813 )
814 // TODO: Create a better test to cover `FairShareChoiceStrategy#choose`
815 const promises = new Set()
816 const maxMultiplier = 2
817 for (let i = 0; i < max * maxMultiplier; i++) {
818 promises.add(pool.execute())
819 }
820 await Promise.all(promises)
821 for (const workerNode of pool.workerNodes) {
822 expect(workerNode.workerUsage).toStrictEqual({
823 tasks: {
824 executed: maxMultiplier,
825 executing: 0,
826 queued: 0,
827 failed: 0
828 },
829 runTime: {
830 aggregate: expect.any(Number),
831 average: expect.any(Number),
832 median: 0,
833 history: expect.any(CircularArray)
834 },
835 waitTime: {
836 aggregate: 0,
837 average: 0,
838 median: 0,
839 history: expect.any(CircularArray)
840 },
841 elu: undefined
842 })
843 expect(workerNode.workerUsage.runTime.aggregate).toBeGreaterThan(0)
844 expect(workerNode.workerUsage.runTime.average).toBeGreaterThan(0)
845 }
846 expect(
847 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
848 pool.workerChoiceStrategyContext.workerChoiceStrategy
849 ).workersVirtualTaskEndTimestamp.length
850 ).toBe(pool.workerNodes.length)
851 // We need to clean up the resources after our test
852 await pool.destroy()
853 })
854
855 it('Verify FAIR_SHARE strategy can be run in a dynamic pool', async () => {
856 const pool = new DynamicThreadPool(
857 min,
858 max,
859 './tests/worker-files/thread/testWorker.js',
860 { workerChoiceStrategy: WorkerChoiceStrategies.FAIR_SHARE }
861 )
862 // TODO: Create a better test to cover `FairShareChoiceStrategy#choose`
863 const promises = new Set()
864 const maxMultiplier = 2
865 for (let i = 0; i < max * maxMultiplier; i++) {
866 promises.add(pool.execute())
867 }
868 await Promise.all(promises)
869 for (const workerNode of pool.workerNodes) {
870 expect(workerNode.workerUsage).toStrictEqual({
871 tasks: {
872 executed: maxMultiplier,
873 executing: 0,
874 queued: 0,
875 failed: 0
876 },
877 runTime: {
878 aggregate: expect.any(Number),
879 average: expect.any(Number),
880 median: 0,
881 history: expect.any(CircularArray)
882 },
883 waitTime: {
884 aggregate: 0,
885 average: 0,
886 median: 0,
887 history: expect.any(CircularArray)
888 },
889 elu: undefined
890 })
891 expect(workerNode.workerUsage.runTime.aggregate).toBeGreaterThan(0)
892 expect(workerNode.workerUsage.runTime.average).toBeGreaterThan(0)
893 }
894 expect(
895 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
896 pool.workerChoiceStrategyContext.workerChoiceStrategy
897 ).workersVirtualTaskEndTimestamp.length
898 ).toBe(pool.workerNodes.length)
899 // We need to clean up the resources after our test
900 await pool.destroy()
901 })
902
903 it('Verify FAIR_SHARE strategy can be run in a dynamic pool with median runtime statistic', async () => {
904 const pool = new DynamicThreadPool(
905 min,
906 max,
907 './tests/worker-files/thread/testWorker.js',
908 {
909 workerChoiceStrategy: WorkerChoiceStrategies.FAIR_SHARE,
910 workerChoiceStrategyOptions: {
911 runTime: { median: true }
912 }
913 }
914 )
915 // TODO: Create a better test to cover `FairShareChoiceStrategy#choose`
916 const promises = new Set()
917 const maxMultiplier = 2
918 for (let i = 0; i < max * maxMultiplier; i++) {
919 promises.add(pool.execute())
920 }
921 await Promise.all(promises)
922 for (const workerNode of pool.workerNodes) {
923 expect(workerNode.workerUsage).toStrictEqual({
924 tasks: {
925 executed: maxMultiplier,
926 executing: 0,
927 queued: 0,
928 failed: 0
929 },
930 runTime: {
931 aggregate: expect.any(Number),
932 average: 0,
933 median: expect.any(Number),
934 history: expect.any(CircularArray)
935 },
936 waitTime: {
937 aggregate: 0,
938 average: 0,
939 median: 0,
940 history: expect.any(CircularArray)
941 },
942 elu: undefined
943 })
944 expect(workerNode.workerUsage.runTime.aggregate).toBeGreaterThan(0)
945 expect(workerNode.workerUsage.runTime.median).toBeGreaterThan(0)
946 }
947 expect(
948 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
949 pool.workerChoiceStrategyContext.workerChoiceStrategy
950 ).workersVirtualTaskEndTimestamp.length
951 ).toBe(pool.workerNodes.length)
952 // We need to clean up the resources after our test
953 await pool.destroy()
954 })
955
956 it('Verify FAIR_SHARE strategy internals are resets after setting it', async () => {
957 const workerChoiceStrategy = WorkerChoiceStrategies.FAIR_SHARE
958 let pool = new FixedThreadPool(
959 max,
960 './tests/worker-files/thread/testWorker.js'
961 )
962 expect(
963 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
964 workerChoiceStrategy
965 ).workersVirtualTaskEndTimestamp
966 ).toBeInstanceOf(Array)
967 expect(
968 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
969 workerChoiceStrategy
970 ).workersVirtualTaskEndTimestamp.length
971 ).toBe(0)
972 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
973 workerChoiceStrategy
974 ).workersVirtualTaskEndTimestamp[0] = performance.now()
975 expect(
976 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
977 workerChoiceStrategy
978 ).workersVirtualTaskEndTimestamp.length
979 ).toBe(1)
980 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
981 expect(
982 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
983 workerChoiceStrategy
984 ).workersVirtualTaskEndTimestamp
985 ).toBeInstanceOf(Array)
986 expect(
987 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
988 workerChoiceStrategy
989 ).workersVirtualTaskEndTimestamp.length
990 ).toBe(0)
991 await pool.destroy()
992 pool = new DynamicThreadPool(
993 min,
994 max,
995 './tests/worker-files/thread/testWorker.js'
996 )
997 expect(
998 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
999 workerChoiceStrategy
1000 ).workersVirtualTaskEndTimestamp
1001 ).toBeInstanceOf(Array)
1002 expect(
1003 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1004 workerChoiceStrategy
1005 ).workersVirtualTaskEndTimestamp.length
1006 ).toBe(0)
1007 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1008 workerChoiceStrategy
1009 ).workersVirtualTaskEndTimestamp[0] = performance.now()
1010 expect(
1011 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1012 workerChoiceStrategy
1013 ).workersVirtualTaskEndTimestamp.length
1014 ).toBe(1)
1015 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
1016 expect(
1017 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1018 workerChoiceStrategy
1019 ).workersVirtualTaskEndTimestamp
1020 ).toBeInstanceOf(Array)
1021 expect(
1022 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1023 workerChoiceStrategy
1024 ).workersVirtualTaskEndTimestamp.length
1025 ).toBe(0)
1026 // We need to clean up the resources after our test
1027 await pool.destroy()
1028 })
1029
1030 it('Verify WEIGHTED_ROUND_ROBIN strategy default tasks usage statistics requirements', async () => {
1031 const workerChoiceStrategy = WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
1032 let pool = new FixedThreadPool(
1033 max,
1034 './tests/worker-files/thread/testWorker.js',
1035 { workerChoiceStrategy }
1036 )
1037 expect(
1038 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
1039 ).toStrictEqual({
1040 runTime: {
1041 aggregate: true,
1042 average: true,
1043 median: false
1044 },
1045 waitTime: {
1046 aggregate: false,
1047 average: false,
1048 median: false
1049 },
1050 elu: false
1051 })
1052 await pool.destroy()
1053 pool = new DynamicThreadPool(
1054 min,
1055 max,
1056 './tests/worker-files/thread/testWorker.js',
1057 { workerChoiceStrategy }
1058 )
1059 expect(
1060 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
1061 ).toStrictEqual({
1062 runTime: {
1063 aggregate: true,
1064 average: true,
1065 median: false
1066 },
1067 waitTime: {
1068 aggregate: false,
1069 average: false,
1070 median: false
1071 },
1072 elu: false
1073 })
1074 // We need to clean up the resources after our test
1075 await pool.destroy()
1076 })
1077
1078 it('Verify WEIGHTED_ROUND_ROBIN strategy can be run in a fixed pool', async () => {
1079 const pool = new FixedThreadPool(
1080 max,
1081 './tests/worker-files/thread/testWorker.js',
1082 { workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN }
1083 )
1084 // TODO: Create a better test to cover `WeightedRoundRobinWorkerChoiceStrategy#choose`
1085 const promises = new Set()
1086 const maxMultiplier = 2
1087 for (let i = 0; i < max * maxMultiplier; i++) {
1088 promises.add(pool.execute())
1089 }
1090 await Promise.all(promises)
1091 for (const workerNode of pool.workerNodes) {
1092 expect(workerNode.workerUsage).toStrictEqual({
1093 tasks: {
1094 executed: expect.any(Number),
1095 executing: 0,
1096 queued: 0,
1097 failed: 0
1098 },
1099 runTime: {
1100 aggregate: expect.any(Number),
1101 average: expect.any(Number),
1102 median: 0,
1103 history: expect.any(CircularArray)
1104 },
1105 waitTime: {
1106 aggregate: 0,
1107 average: 0,
1108 median: 0,
1109 history: expect.any(CircularArray)
1110 },
1111 elu: undefined
1112 })
1113 expect(workerNode.workerUsage.tasks.executed).toBeGreaterThanOrEqual(0)
1114 expect(workerNode.workerUsage.tasks.executed).toBeLessThanOrEqual(
1115 max * maxMultiplier
1116 )
1117 expect(workerNode.workerUsage.runTime.aggregate).toBeGreaterThanOrEqual(0)
1118 expect(workerNode.workerUsage.runTime.average).toBeGreaterThanOrEqual(0)
1119 }
1120 expect(
1121 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1122 pool.workerChoiceStrategyContext.workerChoiceStrategy
1123 ).defaultWorkerWeight
1124 ).toBeGreaterThan(0)
1125 expect(
1126 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1127 pool.workerChoiceStrategyContext.workerChoiceStrategy
1128 ).workerVirtualTaskRunTime
1129 ).toBeGreaterThanOrEqual(0)
1130 // We need to clean up the resources after our test
1131 await pool.destroy()
1132 })
1133
1134 it('Verify WEIGHTED_ROUND_ROBIN strategy can be run in a dynamic pool', async () => {
1135 const pool = new DynamicThreadPool(
1136 min,
1137 max,
1138 './tests/worker-files/thread/testWorker.js',
1139 { workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN }
1140 )
1141 // TODO: Create a better test to cover `WeightedRoundRobinWorkerChoiceStrategy#choose`
1142 const promises = new Set()
1143 const maxMultiplier = 2
1144 for (let i = 0; i < max * maxMultiplier; i++) {
1145 promises.add(pool.execute())
1146 }
1147 await Promise.all(promises)
1148 for (const workerNode of pool.workerNodes) {
1149 expect(workerNode.workerUsage).toStrictEqual({
1150 tasks: {
1151 executed: expect.any(Number),
1152 executing: 0,
1153 queued: 0,
1154 failed: 0
1155 },
1156 runTime: {
1157 aggregate: expect.any(Number),
1158 average: expect.any(Number),
1159 median: 0,
1160 history: expect.any(CircularArray)
1161 },
1162 waitTime: {
1163 aggregate: 0,
1164 average: 0,
1165 median: 0,
1166 history: expect.any(CircularArray)
1167 },
1168 elu: undefined
1169 })
1170 expect(workerNode.workerUsage.tasks.executed).toBeGreaterThan(0)
1171 expect(workerNode.workerUsage.tasks.executed).toBeLessThanOrEqual(
1172 max * maxMultiplier
1173 )
1174 expect(workerNode.workerUsage.runTime.aggregate).toBeGreaterThan(0)
1175 expect(workerNode.workerUsage.runTime.average).toBeGreaterThan(0)
1176 }
1177 expect(
1178 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1179 pool.workerChoiceStrategyContext.workerChoiceStrategy
1180 ).defaultWorkerWeight
1181 ).toBeGreaterThan(0)
1182 expect(
1183 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1184 pool.workerChoiceStrategyContext.workerChoiceStrategy
1185 ).workerVirtualTaskRunTime
1186 ).toBeGreaterThanOrEqual(0)
1187 // We need to clean up the resources after our test
1188 await pool.destroy()
1189 })
1190
1191 it('Verify WEIGHTED_ROUND_ROBIN strategy can be run in a dynamic pool with median runtime statistic', async () => {
1192 const pool = new DynamicThreadPool(
1193 min,
1194 max,
1195 './tests/worker-files/thread/testWorker.js',
1196 {
1197 workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN,
1198 workerChoiceStrategyOptions: {
1199 runTime: { median: true }
1200 }
1201 }
1202 )
1203 // TODO: Create a better test to cover `WeightedRoundRobinWorkerChoiceStrategy#choose`
1204 const promises = new Set()
1205 const maxMultiplier = 2
1206 for (let i = 0; i < max * maxMultiplier; i++) {
1207 promises.add(pool.execute())
1208 }
1209 await Promise.all(promises)
1210 for (const workerNode of pool.workerNodes) {
1211 expect(workerNode.workerUsage).toStrictEqual({
1212 tasks: {
1213 executed: expect.any(Number),
1214 executing: 0,
1215 queued: 0,
1216 failed: 0
1217 },
1218 runTime: {
1219 aggregate: expect.any(Number),
1220 average: 0,
1221 median: expect.any(Number),
1222 history: expect.any(CircularArray)
1223 },
1224 waitTime: {
1225 aggregate: 0,
1226 average: 0,
1227 median: 0,
1228 history: expect.any(CircularArray)
1229 },
1230 elu: undefined
1231 })
1232 expect(workerNode.workerUsage.tasks.executed).toBeGreaterThan(0)
1233 expect(workerNode.workerUsage.tasks.executed).toBeLessThanOrEqual(
1234 max * maxMultiplier
1235 )
1236 expect(workerNode.workerUsage.runTime.aggregate).toBeGreaterThan(0)
1237 expect(workerNode.workerUsage.runTime.median).toBeGreaterThan(0)
1238 }
1239 expect(
1240 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1241 pool.workerChoiceStrategyContext.workerChoiceStrategy
1242 ).defaultWorkerWeight
1243 ).toBeGreaterThan(0)
1244 expect(
1245 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1246 pool.workerChoiceStrategyContext.workerChoiceStrategy
1247 ).workerVirtualTaskRunTime
1248 ).toBeGreaterThanOrEqual(0)
1249 // We need to clean up the resources after our test
1250 await pool.destroy()
1251 })
1252
1253 it('Verify WEIGHTED_ROUND_ROBIN strategy internals are resets after setting it', async () => {
1254 const workerChoiceStrategy = WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
1255 let pool = new FixedThreadPool(
1256 max,
1257 './tests/worker-files/thread/testWorker.js'
1258 )
1259 expect(
1260 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1261 workerChoiceStrategy
1262 ).currentWorkerNodeId
1263 ).toBeDefined()
1264 expect(
1265 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1266 workerChoiceStrategy
1267 ).defaultWorkerWeight
1268 ).toBeDefined()
1269 expect(
1270 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1271 workerChoiceStrategy
1272 ).workerVirtualTaskRunTime
1273 ).toBeDefined()
1274 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
1275 expect(
1276 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1277 pool.workerChoiceStrategyContext.workerChoiceStrategy
1278 ).currentWorkerNodeId
1279 ).toBe(0)
1280 expect(
1281 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1282 pool.workerChoiceStrategyContext.workerChoiceStrategy
1283 ).defaultWorkerWeight
1284 ).toBeGreaterThan(0)
1285 expect(
1286 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1287 workerChoiceStrategy
1288 ).workerVirtualTaskRunTime
1289 ).toBe(0)
1290 await pool.destroy()
1291 pool = new DynamicThreadPool(
1292 min,
1293 max,
1294 './tests/worker-files/thread/testWorker.js'
1295 )
1296 expect(
1297 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1298 workerChoiceStrategy
1299 ).currentWorkerNodeId
1300 ).toBeDefined()
1301 expect(
1302 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1303 workerChoiceStrategy
1304 ).defaultWorkerWeight
1305 ).toBeDefined()
1306 expect(
1307 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1308 workerChoiceStrategy
1309 ).workerVirtualTaskRunTime
1310 ).toBeDefined()
1311 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
1312 expect(
1313 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1314 pool.workerChoiceStrategyContext.workerChoiceStrategy
1315 ).currentWorkerNodeId
1316 ).toBe(0)
1317 expect(
1318 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1319 pool.workerChoiceStrategyContext.workerChoiceStrategy
1320 ).defaultWorkerWeight
1321 ).toBeGreaterThan(0)
1322 expect(
1323 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1324 workerChoiceStrategy
1325 ).workerVirtualTaskRunTime
1326 ).toBe(0)
1327 // We need to clean up the resources after our test
1328 await pool.destroy()
1329 })
1330
1331 it('Verify INTERLEAVED_WEIGHTED_ROUND_ROBIN strategy default tasks usage statistics requirements', async () => {
1332 const workerChoiceStrategy =
1333 WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
1334 let pool = new FixedThreadPool(
1335 max,
1336 './tests/worker-files/thread/testWorker.js',
1337 { workerChoiceStrategy }
1338 )
1339 expect(
1340 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
1341 ).toStrictEqual({
1342 runTime: {
1343 aggregate: false,
1344 average: false,
1345 median: false
1346 },
1347 waitTime: {
1348 aggregate: false,
1349 average: false,
1350 median: false
1351 },
1352 elu: false
1353 })
1354 await pool.destroy()
1355 pool = new DynamicThreadPool(
1356 min,
1357 max,
1358 './tests/worker-files/thread/testWorker.js',
1359 { workerChoiceStrategy }
1360 )
1361 expect(
1362 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
1363 ).toStrictEqual({
1364 runTime: {
1365 aggregate: false,
1366 average: false,
1367 median: false
1368 },
1369 waitTime: {
1370 aggregate: false,
1371 average: false,
1372 median: false
1373 },
1374 elu: false
1375 })
1376 // We need to clean up the resources after our test
1377 await pool.destroy()
1378 })
1379
1380 it('Verify INTERLEAVED_WEIGHTED_ROUND_ROBIN strategy can be run in a fixed pool', async () => {
1381 const pool = new FixedThreadPool(
1382 max,
1383 './tests/worker-files/thread/testWorker.js',
1384 {
1385 workerChoiceStrategy:
1386 WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
1387 }
1388 )
1389 // TODO: Create a better test to cover `InterleavedWeightedRoundRobinWorkerChoiceStrategy#choose`
1390 const promises = new Set()
1391 const maxMultiplier = 2
1392 for (let i = 0; i < max * maxMultiplier; i++) {
1393 promises.add(pool.execute())
1394 }
1395 await Promise.all(promises)
1396 for (const workerNode of pool.workerNodes) {
1397 expect(workerNode.workerUsage).toStrictEqual({
1398 tasks: {
1399 executed: maxMultiplier,
1400 executing: 0,
1401 queued: 0,
1402 failed: 0
1403 },
1404 runTime: {
1405 aggregate: 0,
1406 average: 0,
1407 median: 0,
1408 history: expect.any(CircularArray)
1409 },
1410 waitTime: {
1411 aggregate: 0,
1412 average: 0,
1413 median: 0,
1414 history: expect.any(CircularArray)
1415 },
1416 elu: undefined
1417 })
1418 }
1419 expect(
1420 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1421 pool.workerChoiceStrategyContext.workerChoiceStrategy
1422 ).defaultWorkerWeight
1423 ).toBeGreaterThan(0)
1424 expect(
1425 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1426 pool.workerChoiceStrategyContext.workerChoiceStrategy
1427 ).currentRoundId
1428 ).toBe(0)
1429 expect(
1430 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1431 pool.workerChoiceStrategyContext.workerChoiceStrategy
1432 ).currentWorkerNodeId
1433 ).toBe(0)
1434 expect(
1435 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1436 pool.workerChoiceStrategyContext.workerChoiceStrategy
1437 ).roundWeights
1438 ).toStrictEqual([
1439 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1440 pool.workerChoiceStrategyContext.workerChoiceStrategy
1441 ).defaultWorkerWeight
1442 ])
1443 // We need to clean up the resources after our test
1444 await pool.destroy()
1445 })
1446
1447 it('Verify INTERLEAVED_WEIGHTED_ROUND_ROBIN strategy can be run in a dynamic pool', async () => {
1448 const pool = new DynamicThreadPool(
1449 min,
1450 max,
1451 './tests/worker-files/thread/testWorker.js',
1452 {
1453 workerChoiceStrategy:
1454 WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
1455 }
1456 )
1457 // TODO: Create a better test to cover `InterleavedWeightedRoundRobinWorkerChoiceStrategy#choose`
1458 const promises = new Set()
1459 const maxMultiplier = 2
1460 for (let i = 0; i < max * maxMultiplier; i++) {
1461 promises.add(pool.execute())
1462 }
1463 await Promise.all(promises)
1464 for (const workerNode of pool.workerNodes) {
1465 expect(workerNode.workerUsage).toStrictEqual({
1466 tasks: {
1467 executed: maxMultiplier,
1468 executing: 0,
1469 queued: 0,
1470 failed: 0
1471 },
1472 runTime: {
1473 aggregate: 0,
1474 average: 0,
1475 median: 0,
1476 history: expect.any(CircularArray)
1477 },
1478 waitTime: {
1479 aggregate: 0,
1480 average: 0,
1481 median: 0,
1482 history: expect.any(CircularArray)
1483 },
1484 elu: undefined
1485 })
1486 }
1487 expect(
1488 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1489 pool.workerChoiceStrategyContext.workerChoiceStrategy
1490 ).defaultWorkerWeight
1491 ).toBeGreaterThan(0)
1492 expect(
1493 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1494 pool.workerChoiceStrategyContext.workerChoiceStrategy
1495 ).currentRoundId
1496 ).toBe(0)
1497 expect(
1498 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1499 pool.workerChoiceStrategyContext.workerChoiceStrategy
1500 ).currentWorkerNodeId
1501 ).toBe(0)
1502 expect(
1503 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1504 pool.workerChoiceStrategyContext.workerChoiceStrategy
1505 ).roundWeights
1506 ).toStrictEqual([
1507 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1508 pool.workerChoiceStrategyContext.workerChoiceStrategy
1509 ).defaultWorkerWeight
1510 ])
1511 // We need to clean up the resources after our test
1512 await pool.destroy()
1513 })
1514
1515 it('Verify INTERLEAVED_WEIGHTED_ROUND_ROBIN strategy internals are resets after setting it', async () => {
1516 const workerChoiceStrategy =
1517 WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
1518 let pool = new FixedThreadPool(
1519 max,
1520 './tests/worker-files/thread/testWorker.js'
1521 )
1522 expect(
1523 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1524 workerChoiceStrategy
1525 ).currentRoundId
1526 ).toBeDefined()
1527 expect(
1528 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1529 workerChoiceStrategy
1530 ).currentWorkerNodeId
1531 ).toBeDefined()
1532 expect(
1533 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1534 workerChoiceStrategy
1535 ).defaultWorkerWeight
1536 ).toBeDefined()
1537 expect(
1538 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1539 workerChoiceStrategy
1540 ).roundWeights
1541 ).toBeDefined()
1542 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
1543 expect(
1544 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1545 workerChoiceStrategy
1546 ).currentRoundId
1547 ).toBe(0)
1548 expect(
1549 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1550 pool.workerChoiceStrategyContext.workerChoiceStrategy
1551 ).currentWorkerNodeId
1552 ).toBe(0)
1553 expect(
1554 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1555 pool.workerChoiceStrategyContext.workerChoiceStrategy
1556 ).defaultWorkerWeight
1557 ).toBeGreaterThan(0)
1558 expect(
1559 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1560 workerChoiceStrategy
1561 ).roundWeights
1562 ).toStrictEqual([
1563 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1564 pool.workerChoiceStrategyContext.workerChoiceStrategy
1565 ).defaultWorkerWeight
1566 ])
1567 await pool.destroy()
1568 pool = new DynamicThreadPool(
1569 min,
1570 max,
1571 './tests/worker-files/thread/testWorker.js'
1572 )
1573 expect(
1574 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1575 workerChoiceStrategy
1576 ).currentRoundId
1577 ).toBeDefined()
1578 expect(
1579 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1580 workerChoiceStrategy
1581 ).currentWorkerNodeId
1582 ).toBeDefined()
1583 expect(
1584 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1585 workerChoiceStrategy
1586 ).defaultWorkerWeight
1587 ).toBeDefined()
1588 expect(
1589 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1590 workerChoiceStrategy
1591 ).roundWeights
1592 ).toBeDefined()
1593 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
1594 expect(
1595 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1596 pool.workerChoiceStrategyContext.workerChoiceStrategy
1597 ).currentWorkerNodeId
1598 ).toBe(0)
1599 expect(
1600 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1601 pool.workerChoiceStrategyContext.workerChoiceStrategy
1602 ).defaultWorkerWeight
1603 ).toBeGreaterThan(0)
1604 expect(
1605 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1606 workerChoiceStrategy
1607 ).roundWeights
1608 ).toStrictEqual([
1609 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1610 pool.workerChoiceStrategyContext.workerChoiceStrategy
1611 ).defaultWorkerWeight
1612 ])
1613 // We need to clean up the resources after our test
1614 await pool.destroy()
1615 })
1616
1617 it('Verify unknown strategy throw error', () => {
1618 expect(
1619 () =>
1620 new DynamicThreadPool(
1621 min,
1622 max,
1623 './tests/worker-files/thread/testWorker.js',
1624 { workerChoiceStrategy: 'UNKNOWN_STRATEGY' }
1625 )
1626 ).toThrowError("Invalid worker choice strategy 'UNKNOWN_STRATEGY'")
1627 })
1628 })