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