1 import { expect } from 'expect'
8 } from '../../../lib/index.cjs'
9 import { CircularArray } from '../../../lib/circular-array.cjs'
11 describe('Selection strategies test suite', () => {
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'
24 expect(WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN).toBe(
25 'INTERLEAVED_WEIGHTED_ROUND_ROBIN'
29 it('Verify ROUND_ROBIN strategy is the default at pool creation', async () => {
30 const pool = new DynamicThreadPool(
33 './tests/worker-files/thread/testWorker.mjs'
35 expect(pool.opts.workerChoiceStrategy).toBe(
36 WorkerChoiceStrategies.ROUND_ROBIN
38 // We need to clean up the resources after our test
42 it('Verify available strategies are taken at pool creation', async () => {
43 for (const workerChoiceStrategy of Object.values(WorkerChoiceStrategies)) {
44 const pool = new FixedThreadPool(
46 './tests/worker-files/thread/testWorker.mjs',
47 { workerChoiceStrategy }
49 expect(pool.opts.workerChoiceStrategy).toBe(workerChoiceStrategy)
50 expect(pool.workerChoiceStrategyContext.workerChoiceStrategy).toBe(
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(
62 './tests/worker-files/thread/testWorker.mjs'
64 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
65 expect(pool.opts.workerChoiceStrategy).toBe(workerChoiceStrategy)
66 expect(pool.workerChoiceStrategyContext.workerChoiceStrategy).toBe(
69 expect(pool.opts.workerChoiceStrategyOptions).toBeUndefined()
70 expect(pool.workerChoiceStrategyContext.opts).toStrictEqual({
73 Object.keys(pool.workerChoiceStrategyContext.opts.weights).length,
74 runTime: { median: false },
75 waitTime: { median: false },
76 elu: { median: false },
77 weights: expect.objectContaining({
78 0: expect.any(Number),
79 [pool.info.maxSize - 1]: expect.any(Number)
84 for (const workerChoiceStrategy of Object.values(WorkerChoiceStrategies)) {
85 const pool = new DynamicClusterPool(
88 './tests/worker-files/cluster/testWorker.cjs'
90 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
91 expect(pool.opts.workerChoiceStrategy).toBe(workerChoiceStrategy)
92 expect(pool.workerChoiceStrategyContext.workerChoiceStrategy).toBe(
95 expect(pool.opts.workerChoiceStrategyOptions).toBeUndefined()
96 expect(pool.workerChoiceStrategyContext.opts).toStrictEqual({
99 Object.keys(pool.workerChoiceStrategyContext.opts.weights).length,
100 runTime: { median: false },
101 waitTime: { median: false },
102 elu: { median: false },
103 weights: expect.objectContaining({
104 0: expect.any(Number),
105 [pool.info.maxSize - 1]: expect.any(Number)
112 it('Verify available strategies default internals at pool creation', async () => {
113 const pool = new FixedThreadPool(
115 './tests/worker-files/thread/testWorker.mjs'
117 for (const workerChoiceStrategy of Object.values(WorkerChoiceStrategies)) {
119 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
124 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
126 ).previousWorkerNodeKey
129 workerChoiceStrategy === WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
132 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
134 ).workerNodeVirtualTaskRunTime
137 workerChoiceStrategy ===
138 WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
141 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
143 ).workerNodeVirtualTaskRunTime
146 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
151 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
156 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
158 ).roundWeights.length
161 Number.isSafeInteger(
162 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
172 it('Verify strategies wait for worker node readiness in dynamic pool', async () => {
173 const pool = new DynamicThreadPool(
176 './tests/worker-files/thread/testWorker.mjs'
178 expect(pool.starting).toBe(false)
179 expect(pool.workerNodes.length).toBe(min)
180 const maxMultiplier = 10000
181 const promises = new Set()
182 for (let i = 0; i < max * maxMultiplier; i++) {
183 promises.add(pool.execute())
185 await Promise.all(promises)
186 expect(pool.workerNodes.length).toBe(max)
187 // We need to clean up the resources after our test
191 it('Verify ROUND_ROBIN strategy default policy', async () => {
192 const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN
193 let pool = new FixedThreadPool(
195 './tests/worker-files/thread/testWorker.mjs',
196 { workerChoiceStrategy }
198 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
199 dynamicWorkerUsage: false,
200 dynamicWorkerReady: true
203 pool = new DynamicThreadPool(
206 './tests/worker-files/thread/testWorker.mjs',
207 { workerChoiceStrategy }
209 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
210 dynamicWorkerUsage: false,
211 dynamicWorkerReady: true
213 // We need to clean up the resources after our test
217 it('Verify ROUND_ROBIN strategy default tasks statistics requirements', async () => {
218 const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN
219 let pool = new FixedThreadPool(
221 './tests/worker-files/thread/testWorker.mjs',
222 { workerChoiceStrategy }
225 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
244 pool = new DynamicThreadPool(
247 './tests/worker-files/thread/testWorker.mjs',
248 { workerChoiceStrategy }
251 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
269 // We need to clean up the resources after our test
273 it('Verify ROUND_ROBIN strategy can be run in a fixed pool', async () => {
274 const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN
275 const pool = new FixedThreadPool(
277 './tests/worker-files/thread/testWorker.mjs',
278 { workerChoiceStrategy }
280 // TODO: Create a better test to cover `RoundRobinWorkerChoiceStrategy#choose`
281 const promises = new Set()
282 const maxMultiplier = 2
283 for (let i = 0; i < max * maxMultiplier; i++) {
284 promises.add(pool.execute())
286 await Promise.all(promises)
287 for (const workerNode of pool.workerNodes) {
288 expect(workerNode.usage).toStrictEqual({
290 executed: maxMultiplier,
294 sequentiallyStolen: 0,
299 history: new CircularArray()
302 history: new CircularArray()
306 history: new CircularArray()
309 history: new CircularArray()
315 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
316 pool.workerChoiceStrategyContext.workerChoiceStrategy
320 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
321 pool.workerChoiceStrategyContext.workerChoiceStrategy
322 ).previousWorkerNodeKey
323 ).toBe(pool.workerNodes.length - 1)
324 // We need to clean up the resources after our test
328 it('Verify ROUND_ROBIN strategy can be run in a dynamic pool', async () => {
329 const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN
330 const pool = new DynamicThreadPool(
333 './tests/worker-files/thread/testWorker.mjs',
334 { workerChoiceStrategy }
336 // TODO: Create a better test to cover `RoundRobinWorkerChoiceStrategy#choose`
337 const promises = new Set()
338 const maxMultiplier = 2
339 for (let i = 0; i < max * maxMultiplier; i++) {
340 promises.add(pool.execute())
342 await Promise.all(promises)
343 for (const workerNode of pool.workerNodes) {
344 expect(workerNode.usage).toStrictEqual({
346 executed: expect.any(Number),
350 sequentiallyStolen: 0,
355 history: new CircularArray()
358 history: new CircularArray()
362 history: new CircularArray()
365 history: new CircularArray()
369 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
370 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
375 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
376 pool.workerChoiceStrategyContext.workerChoiceStrategy
380 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
381 pool.workerChoiceStrategyContext.workerChoiceStrategy
382 ).previousWorkerNodeKey
383 ).toBe(pool.workerNodes.length - 1)
384 // We need to clean up the resources after our test
388 it('Verify ROUND_ROBIN strategy runtime behavior', async () => {
389 const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN
390 let pool = new FixedClusterPool(
392 './tests/worker-files/cluster/testWorker.cjs',
393 { workerChoiceStrategy }
395 let results = new Set()
396 for (let i = 0; i < max; i++) {
397 results.add(pool.workerNodes[pool.chooseWorkerNode()].info.id)
399 expect(results.size).toBe(max)
401 pool = new FixedThreadPool(
403 './tests/worker-files/thread/testWorker.mjs',
404 { workerChoiceStrategy }
407 for (let i = 0; i < max; i++) {
408 results.add(pool.workerNodes[pool.chooseWorkerNode()].info.id)
410 expect(results.size).toBe(max)
414 it('Verify ROUND_ROBIN strategy internals are resets after setting it', async () => {
415 const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN
416 let pool = new FixedThreadPool(
418 './tests/worker-files/thread/testWorker.mjs',
419 { workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN }
422 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
423 pool.workerChoiceStrategyContext.workerChoiceStrategy
427 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
428 pool.workerChoiceStrategyContext.workerChoiceStrategy
429 ).previousWorkerNodeKey
431 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
433 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
434 pool.workerChoiceStrategyContext.workerChoiceStrategy
438 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
439 pool.workerChoiceStrategyContext.workerChoiceStrategy
440 ).previousWorkerNodeKey
443 pool = new DynamicThreadPool(
446 './tests/worker-files/thread/testWorker.mjs',
447 { workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN }
450 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
451 pool.workerChoiceStrategyContext.workerChoiceStrategy
455 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
456 pool.workerChoiceStrategyContext.workerChoiceStrategy
457 ).previousWorkerNodeKey
459 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
461 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
462 pool.workerChoiceStrategyContext.workerChoiceStrategy
466 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
467 pool.workerChoiceStrategyContext.workerChoiceStrategy
468 ).previousWorkerNodeKey
470 // We need to clean up the resources after our test
474 it('Verify LEAST_USED strategy default policy', async () => {
475 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_USED
476 let pool = new FixedThreadPool(
478 './tests/worker-files/thread/testWorker.mjs',
479 { workerChoiceStrategy }
481 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
482 dynamicWorkerUsage: false,
483 dynamicWorkerReady: true
486 pool = new DynamicThreadPool(
489 './tests/worker-files/thread/testWorker.mjs',
490 { workerChoiceStrategy }
492 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
493 dynamicWorkerUsage: false,
494 dynamicWorkerReady: true
496 // We need to clean up the resources after our test
500 it('Verify LEAST_USED strategy default tasks statistics requirements', async () => {
501 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_USED
502 let pool = new FixedThreadPool(
504 './tests/worker-files/thread/testWorker.mjs',
505 { workerChoiceStrategy }
508 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
527 pool = new DynamicThreadPool(
530 './tests/worker-files/thread/testWorker.mjs',
531 { workerChoiceStrategy }
534 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
552 // We need to clean up the resources after our test
556 it('Verify LEAST_USED strategy can be run in a fixed pool', async () => {
557 const pool = new FixedThreadPool(
559 './tests/worker-files/thread/testWorker.mjs',
560 { workerChoiceStrategy: WorkerChoiceStrategies.LEAST_USED }
562 // TODO: Create a better test to cover `LeastUsedWorkerChoiceStrategy#choose`
563 const promises = new Set()
564 const maxMultiplier = 2
565 for (let i = 0; i < max * maxMultiplier; i++) {
566 promises.add(pool.execute())
568 await Promise.all(promises)
569 for (const workerNode of pool.workerNodes) {
570 expect(workerNode.usage).toStrictEqual({
572 executed: expect.any(Number),
576 sequentiallyStolen: 0,
581 history: new CircularArray()
584 history: new CircularArray()
588 history: new CircularArray()
591 history: new CircularArray()
595 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
596 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
601 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
602 pool.workerChoiceStrategyContext.workerChoiceStrategy
604 ).toEqual(expect.any(Number))
606 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
607 pool.workerChoiceStrategyContext.workerChoiceStrategy
608 ).previousWorkerNodeKey
609 ).toEqual(expect.any(Number))
610 // We need to clean up the resources after our test
614 it('Verify LEAST_USED strategy can be run in a dynamic pool', async () => {
615 const pool = new DynamicThreadPool(
618 './tests/worker-files/thread/testWorker.mjs',
619 { workerChoiceStrategy: WorkerChoiceStrategies.LEAST_USED }
621 // TODO: Create a better test to cover `LeastUsedWorkerChoiceStrategy#choose`
622 const promises = new Set()
623 const maxMultiplier = 2
624 for (let i = 0; i < max * maxMultiplier; i++) {
625 promises.add(pool.execute())
627 await Promise.all(promises)
628 for (const workerNode of pool.workerNodes) {
629 expect(workerNode.usage).toStrictEqual({
631 executed: expect.any(Number),
635 sequentiallyStolen: 0,
640 history: new CircularArray()
643 history: new CircularArray()
647 history: new CircularArray()
650 history: new CircularArray()
654 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
655 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
660 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
661 pool.workerChoiceStrategyContext.workerChoiceStrategy
663 ).toEqual(expect.any(Number))
665 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
666 pool.workerChoiceStrategyContext.workerChoiceStrategy
667 ).previousWorkerNodeKey
668 ).toEqual(expect.any(Number))
669 // We need to clean up the resources after our test
673 it('Verify LEAST_BUSY strategy default policy', async () => {
674 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_BUSY
675 let pool = new FixedThreadPool(
677 './tests/worker-files/thread/testWorker.mjs',
678 { workerChoiceStrategy }
680 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
681 dynamicWorkerUsage: false,
682 dynamicWorkerReady: true
685 pool = new DynamicThreadPool(
688 './tests/worker-files/thread/testWorker.mjs',
689 { workerChoiceStrategy }
691 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
692 dynamicWorkerUsage: false,
693 dynamicWorkerReady: true
695 // We need to clean up the resources after our test
699 it('Verify LEAST_BUSY strategy default tasks statistics requirements', async () => {
700 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_BUSY
701 let pool = new FixedThreadPool(
703 './tests/worker-files/thread/testWorker.mjs',
704 { workerChoiceStrategy }
707 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
726 pool = new DynamicThreadPool(
729 './tests/worker-files/thread/testWorker.mjs',
730 { workerChoiceStrategy }
733 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
751 // We need to clean up the resources after our test
755 it('Verify LEAST_BUSY strategy can be run in a fixed pool', async () => {
756 const pool = new FixedThreadPool(
758 './tests/worker-files/thread/testWorker.mjs',
759 { workerChoiceStrategy: WorkerChoiceStrategies.LEAST_BUSY }
761 // TODO: Create a better test to cover `LeastBusyWorkerChoiceStrategy#choose`
762 const promises = new Set()
763 const maxMultiplier = 2
764 for (let i = 0; i < max * maxMultiplier; i++) {
765 promises.add(pool.execute())
767 await Promise.all(promises)
768 for (const workerNode of pool.workerNodes) {
769 expect(workerNode.usage).toStrictEqual({
771 executed: expect.any(Number),
775 sequentiallyStolen: 0,
779 runTime: expect.objectContaining({
780 history: expect.any(CircularArray)
782 waitTime: expect.objectContaining({
783 history: expect.any(CircularArray)
787 history: new CircularArray()
790 history: new CircularArray()
794 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
795 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
798 if (workerNode.usage.runTime.aggregate == null) {
799 expect(workerNode.usage.runTime.aggregate).toBeUndefined()
801 expect(workerNode.usage.runTime.aggregate).toBeGreaterThan(0)
803 if (workerNode.usage.waitTime.aggregate == null) {
804 expect(workerNode.usage.waitTime.aggregate).toBeUndefined()
806 expect(workerNode.usage.waitTime.aggregate).toBeGreaterThan(0)
810 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
811 pool.workerChoiceStrategyContext.workerChoiceStrategy
813 ).toEqual(expect.any(Number))
815 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
816 pool.workerChoiceStrategyContext.workerChoiceStrategy
817 ).previousWorkerNodeKey
818 ).toEqual(expect.any(Number))
819 // We need to clean up the resources after our test
823 it('Verify LEAST_BUSY strategy can be run in a dynamic pool', async () => {
824 const pool = new DynamicThreadPool(
827 './tests/worker-files/thread/testWorker.mjs',
828 { workerChoiceStrategy: WorkerChoiceStrategies.LEAST_BUSY }
830 // TODO: Create a better test to cover `LeastBusyWorkerChoiceStrategy#choose`
831 const promises = new Set()
832 const maxMultiplier = 2
833 for (let i = 0; i < max * maxMultiplier; i++) {
834 promises.add(pool.execute())
836 await Promise.all(promises)
837 for (const workerNode of pool.workerNodes) {
838 expect(workerNode.usage).toStrictEqual({
840 executed: expect.any(Number),
844 sequentiallyStolen: 0,
848 runTime: expect.objectContaining({
849 history: expect.any(CircularArray)
851 waitTime: expect.objectContaining({
852 history: expect.any(CircularArray)
856 history: new CircularArray()
859 history: new CircularArray()
863 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
864 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
867 if (workerNode.usage.runTime.aggregate == null) {
868 expect(workerNode.usage.runTime.aggregate).toBeUndefined()
870 expect(workerNode.usage.runTime.aggregate).toBeGreaterThan(0)
872 if (workerNode.usage.waitTime.aggregate == null) {
873 expect(workerNode.usage.waitTime.aggregate).toBeUndefined()
875 expect(workerNode.usage.waitTime.aggregate).toBeGreaterThan(0)
879 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
880 pool.workerChoiceStrategyContext.workerChoiceStrategy
882 ).toEqual(expect.any(Number))
884 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
885 pool.workerChoiceStrategyContext.workerChoiceStrategy
886 ).previousWorkerNodeKey
887 ).toEqual(expect.any(Number))
888 // We need to clean up the resources after our test
892 it('Verify LEAST_ELU strategy default policy', async () => {
893 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_ELU
894 let pool = new FixedThreadPool(
896 './tests/worker-files/thread/testWorker.mjs',
897 { workerChoiceStrategy }
899 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
900 dynamicWorkerUsage: false,
901 dynamicWorkerReady: true
904 pool = new DynamicThreadPool(
907 './tests/worker-files/thread/testWorker.mjs',
908 { workerChoiceStrategy }
910 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
911 dynamicWorkerUsage: false,
912 dynamicWorkerReady: true
914 // We need to clean up the resources after our test
918 it('Verify LEAST_ELU strategy default tasks statistics requirements', async () => {
919 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_ELU
920 let pool = new FixedThreadPool(
922 './tests/worker-files/thread/testWorker.mjs',
923 { workerChoiceStrategy }
926 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
945 pool = new DynamicThreadPool(
948 './tests/worker-files/thread/testWorker.mjs',
949 { workerChoiceStrategy }
952 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
970 // We need to clean up the resources after our test
974 it('Verify LEAST_ELU strategy can be run in a fixed pool', async () => {
975 const pool = new FixedThreadPool(
977 './tests/worker-files/thread/testWorker.mjs',
978 { workerChoiceStrategy: WorkerChoiceStrategies.LEAST_ELU }
980 // TODO: Create a better test to cover `LeastEluWorkerChoiceStrategy#choose`
981 const promises = new Set()
982 const maxMultiplier = 2
983 for (let i = 0; i < max * maxMultiplier; i++) {
984 promises.add(pool.execute())
986 await Promise.all(promises)
987 for (const workerNode of pool.workerNodes) {
988 expect(workerNode.usage).toStrictEqual({
990 executed: expect.any(Number),
994 sequentiallyStolen: 0,
999 history: new CircularArray()
1002 history: new CircularArray()
1004 elu: expect.objectContaining({
1005 idle: expect.objectContaining({
1006 history: expect.any(CircularArray)
1008 active: expect.objectContaining({
1009 history: expect.any(CircularArray)
1013 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
1014 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
1017 if (workerNode.usage.elu.active.aggregate == null) {
1018 expect(workerNode.usage.elu.active.aggregate).toBeUndefined()
1020 expect(workerNode.usage.elu.active.aggregate).toBeGreaterThan(0)
1022 if (workerNode.usage.elu.idle.aggregate == null) {
1023 expect(workerNode.usage.elu.idle.aggregate).toBeUndefined()
1025 expect(workerNode.usage.elu.idle.aggregate).toBeGreaterThanOrEqual(0)
1027 if (workerNode.usage.elu.utilization == null) {
1028 expect(workerNode.usage.elu.utilization).toBeUndefined()
1030 expect(workerNode.usage.elu.utilization).toBeGreaterThanOrEqual(0)
1031 expect(workerNode.usage.elu.utilization).toBeLessThanOrEqual(1)
1035 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1036 pool.workerChoiceStrategyContext.workerChoiceStrategy
1038 ).toEqual(expect.any(Number))
1040 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1041 pool.workerChoiceStrategyContext.workerChoiceStrategy
1042 ).previousWorkerNodeKey
1043 ).toEqual(expect.any(Number))
1044 // We need to clean up the resources after our test
1045 await pool.destroy()
1048 it('Verify LEAST_ELU strategy can be run in a dynamic pool', async () => {
1049 const pool = new DynamicThreadPool(
1052 './tests/worker-files/thread/testWorker.mjs',
1053 { workerChoiceStrategy: WorkerChoiceStrategies.LEAST_ELU }
1055 // TODO: Create a better test to cover `LeastEluWorkerChoiceStrategy#choose`
1056 const promises = new Set()
1057 const maxMultiplier = 2
1058 for (let i = 0; i < max * maxMultiplier; i++) {
1059 promises.add(pool.execute())
1061 await Promise.all(promises)
1062 for (const workerNode of pool.workerNodes) {
1063 expect(workerNode.usage).toStrictEqual({
1065 executed: expect.any(Number),
1069 sequentiallyStolen: 0,
1074 history: new CircularArray()
1077 history: new CircularArray()
1079 elu: expect.objectContaining({
1080 idle: expect.objectContaining({
1081 history: expect.any(CircularArray)
1083 active: expect.objectContaining({
1084 history: expect.any(CircularArray)
1088 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
1089 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
1092 if (workerNode.usage.elu.active.aggregate == null) {
1093 expect(workerNode.usage.elu.active.aggregate).toBeUndefined()
1095 expect(workerNode.usage.elu.active.aggregate).toBeGreaterThan(0)
1097 if (workerNode.usage.elu.idle.aggregate == null) {
1098 expect(workerNode.usage.elu.idle.aggregate).toBeUndefined()
1100 expect(workerNode.usage.elu.idle.aggregate).toBeGreaterThanOrEqual(0)
1102 if (workerNode.usage.elu.utilization == null) {
1103 expect(workerNode.usage.elu.utilization).toBeUndefined()
1105 expect(workerNode.usage.elu.utilization).toBeGreaterThanOrEqual(0)
1106 expect(workerNode.usage.elu.utilization).toBeLessThanOrEqual(1)
1110 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1111 pool.workerChoiceStrategyContext.workerChoiceStrategy
1113 ).toEqual(expect.any(Number))
1115 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1116 pool.workerChoiceStrategyContext.workerChoiceStrategy
1117 ).previousWorkerNodeKey
1118 ).toEqual(expect.any(Number))
1119 // We need to clean up the resources after our test
1120 await pool.destroy()
1123 it('Verify FAIR_SHARE strategy default policy', async () => {
1124 const workerChoiceStrategy = WorkerChoiceStrategies.FAIR_SHARE
1125 let pool = new FixedThreadPool(
1127 './tests/worker-files/thread/testWorker.mjs',
1128 { workerChoiceStrategy }
1130 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
1131 dynamicWorkerUsage: false,
1132 dynamicWorkerReady: true
1134 await pool.destroy()
1135 pool = new DynamicThreadPool(
1138 './tests/worker-files/thread/testWorker.mjs',
1139 { workerChoiceStrategy }
1141 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
1142 dynamicWorkerUsage: false,
1143 dynamicWorkerReady: true
1145 // We need to clean up the resources after our test
1146 await pool.destroy()
1149 it('Verify FAIR_SHARE strategy default tasks statistics requirements', async () => {
1150 const workerChoiceStrategy = WorkerChoiceStrategies.FAIR_SHARE
1151 let pool = new FixedThreadPool(
1153 './tests/worker-files/thread/testWorker.mjs',
1154 { workerChoiceStrategy }
1157 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
1175 await pool.destroy()
1176 pool = new DynamicThreadPool(
1179 './tests/worker-files/thread/testWorker.mjs',
1180 { workerChoiceStrategy }
1183 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
1201 // We need to clean up the resources after our test
1202 await pool.destroy()
1205 it('Verify FAIR_SHARE strategy can be run in a fixed pool', async () => {
1206 const pool = new FixedThreadPool(
1208 './tests/worker-files/thread/testWorker.mjs',
1209 { workerChoiceStrategy: WorkerChoiceStrategies.FAIR_SHARE }
1211 // TODO: Create a better test to cover `FairShareChoiceStrategy#choose`
1212 const promises = new Set()
1213 const maxMultiplier = 2
1214 for (let i = 0; i < max * maxMultiplier; i++) {
1215 promises.add(pool.execute())
1217 await Promise.all(promises)
1218 for (const workerNode of pool.workerNodes) {
1219 expect(workerNode.usage).toStrictEqual({
1221 executed: expect.any(Number),
1225 sequentiallyStolen: 0,
1229 runTime: expect.objectContaining({
1230 history: expect.any(CircularArray)
1233 history: new CircularArray()
1235 elu: expect.objectContaining({
1236 idle: expect.objectContaining({
1237 history: expect.any(CircularArray)
1239 active: expect.objectContaining({
1240 history: expect.any(CircularArray)
1244 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
1245 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
1248 if (workerNode.usage.runTime.aggregate == null) {
1249 expect(workerNode.usage.runTime.aggregate).toBeUndefined()
1251 expect(workerNode.usage.runTime.aggregate).toBeGreaterThan(0)
1253 if (workerNode.usage.runTime.average == null) {
1254 expect(workerNode.usage.runTime.average).toBeUndefined()
1256 expect(workerNode.usage.runTime.average).toBeGreaterThan(0)
1258 if (workerNode.usage.elu.active.aggregate == null) {
1259 expect(workerNode.usage.elu.active.aggregate).toBeUndefined()
1261 expect(workerNode.usage.elu.active.aggregate).toBeGreaterThan(0)
1263 if (workerNode.usage.elu.idle.aggregate == null) {
1264 expect(workerNode.usage.elu.idle.aggregate).toBeUndefined()
1266 expect(workerNode.usage.elu.idle.aggregate).toBeGreaterThanOrEqual(0)
1268 if (workerNode.usage.elu.utilization == null) {
1269 expect(workerNode.usage.elu.utilization).toBeUndefined()
1271 expect(workerNode.usage.elu.utilization).toBeGreaterThanOrEqual(0)
1272 expect(workerNode.usage.elu.utilization).toBeLessThanOrEqual(1)
1274 expect(workerNode.strategyData.virtualTaskEndTimestamp).toBeGreaterThan(0)
1277 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1278 pool.workerChoiceStrategyContext.workerChoiceStrategy
1280 ).toEqual(expect.any(Number))
1282 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1283 pool.workerChoiceStrategyContext.workerChoiceStrategy
1284 ).previousWorkerNodeKey
1285 ).toEqual(expect.any(Number))
1286 // We need to clean up the resources after our test
1287 await pool.destroy()
1290 it('Verify FAIR_SHARE strategy can be run in a dynamic pool', async () => {
1291 const pool = new DynamicThreadPool(
1294 './tests/worker-files/thread/testWorker.mjs',
1295 { workerChoiceStrategy: WorkerChoiceStrategies.FAIR_SHARE }
1297 // TODO: Create a better test to cover `FairShareChoiceStrategy#choose`
1298 const promises = new Set()
1299 const maxMultiplier = 2
1300 for (let i = 0; i < max * maxMultiplier; i++) {
1301 promises.add(pool.execute())
1303 await Promise.all(promises)
1304 for (const workerNode of pool.workerNodes) {
1305 expect(workerNode.usage).toStrictEqual({
1307 executed: expect.any(Number),
1311 sequentiallyStolen: 0,
1315 runTime: expect.objectContaining({
1316 history: expect.any(CircularArray)
1319 history: new CircularArray()
1321 elu: expect.objectContaining({
1322 idle: expect.objectContaining({
1323 history: expect.any(CircularArray)
1325 active: expect.objectContaining({
1326 history: expect.any(CircularArray)
1330 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
1331 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
1334 if (workerNode.usage.runTime.aggregate == null) {
1335 expect(workerNode.usage.runTime.aggregate).toBeUndefined()
1337 expect(workerNode.usage.runTime.aggregate).toBeGreaterThan(0)
1339 if (workerNode.usage.runTime.average == null) {
1340 expect(workerNode.usage.runTime.average).toBeUndefined()
1342 expect(workerNode.usage.runTime.average).toBeGreaterThan(0)
1344 if (workerNode.usage.elu.active.aggregate == null) {
1345 expect(workerNode.usage.elu.active.aggregate).toBeUndefined()
1347 expect(workerNode.usage.elu.active.aggregate).toBeGreaterThan(0)
1349 if (workerNode.usage.elu.idle.aggregate == null) {
1350 expect(workerNode.usage.elu.idle.aggregate).toBeUndefined()
1352 expect(workerNode.usage.elu.idle.aggregate).toBeGreaterThanOrEqual(0)
1354 if (workerNode.usage.elu.utilization == null) {
1355 expect(workerNode.usage.elu.utilization).toBeUndefined()
1357 expect(workerNode.usage.elu.utilization).toBeGreaterThanOrEqual(0)
1358 expect(workerNode.usage.elu.utilization).toBeLessThanOrEqual(1)
1360 expect(workerNode.strategyData.virtualTaskEndTimestamp).toBeGreaterThan(0)
1363 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1364 pool.workerChoiceStrategyContext.workerChoiceStrategy
1366 ).toEqual(expect.any(Number))
1368 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1369 pool.workerChoiceStrategyContext.workerChoiceStrategy
1370 ).previousWorkerNodeKey
1371 ).toEqual(expect.any(Number))
1372 // We need to clean up the resources after our test
1373 await pool.destroy()
1376 it('Verify FAIR_SHARE strategy can be run in a dynamic pool with median runtime statistic', async () => {
1377 const pool = new DynamicThreadPool(
1380 './tests/worker-files/thread/testWorker.mjs',
1382 workerChoiceStrategy: WorkerChoiceStrategies.FAIR_SHARE,
1383 workerChoiceStrategyOptions: {
1384 runTime: { median: true }
1388 // TODO: Create a better test to cover `FairShareChoiceStrategy#choose`
1389 const promises = new Set()
1390 const maxMultiplier = 2
1391 for (let i = 0; i < max * maxMultiplier; i++) {
1392 promises.add(pool.execute())
1394 await Promise.all(promises)
1395 for (const workerNode of pool.workerNodes) {
1396 expect(workerNode.usage).toStrictEqual({
1398 executed: expect.any(Number),
1402 sequentiallyStolen: 0,
1406 runTime: expect.objectContaining({
1407 history: expect.any(CircularArray)
1410 history: new CircularArray()
1412 elu: expect.objectContaining({
1413 idle: expect.objectContaining({
1414 history: expect.any(CircularArray)
1416 active: expect.objectContaining({
1417 history: expect.any(CircularArray)
1421 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
1422 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
1425 if (workerNode.usage.runTime.aggregate == null) {
1426 expect(workerNode.usage.runTime.aggregate).toBeUndefined()
1428 expect(workerNode.usage.runTime.aggregate).toBeGreaterThan(0)
1430 if (workerNode.usage.runTime.median == null) {
1431 expect(workerNode.usage.runTime.median).toBeUndefined()
1433 expect(workerNode.usage.runTime.median).toBeGreaterThan(0)
1435 if (workerNode.usage.elu.active.aggregate == null) {
1436 expect(workerNode.usage.elu.active.aggregate).toBeUndefined()
1438 expect(workerNode.usage.elu.active.aggregate).toBeGreaterThan(0)
1440 if (workerNode.usage.elu.idle.aggregate == null) {
1441 expect(workerNode.usage.elu.idle.aggregate).toBeUndefined()
1443 expect(workerNode.usage.elu.idle.aggregate).toBeGreaterThanOrEqual(0)
1445 if (workerNode.usage.elu.utilization == null) {
1446 expect(workerNode.usage.elu.utilization).toBeUndefined()
1448 expect(workerNode.usage.elu.utilization).toBeGreaterThanOrEqual(0)
1449 expect(workerNode.usage.elu.utilization).toBeLessThanOrEqual(1)
1451 expect(workerNode.strategyData.virtualTaskEndTimestamp).toBeGreaterThan(0)
1454 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1455 pool.workerChoiceStrategyContext.workerChoiceStrategy
1457 ).toEqual(expect.any(Number))
1459 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1460 pool.workerChoiceStrategyContext.workerChoiceStrategy
1461 ).previousWorkerNodeKey
1462 ).toEqual(expect.any(Number))
1463 // We need to clean up the resources after our test
1464 await pool.destroy()
1467 it('Verify FAIR_SHARE strategy internals are resets after setting it', async () => {
1468 const workerChoiceStrategy = WorkerChoiceStrategies.FAIR_SHARE
1469 let pool = new FixedThreadPool(
1471 './tests/worker-files/thread/testWorker.mjs'
1473 for (const workerNode of pool.workerNodes) {
1474 workerNode.strategyData = {
1475 virtualTaskEndTimestamp: performance.now()
1478 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
1479 for (const workerNode of pool.workerNodes) {
1480 expect(workerNode.strategyData.virtualTaskEndTimestamp).toBeUndefined()
1482 await pool.destroy()
1483 pool = new DynamicThreadPool(
1486 './tests/worker-files/thread/testWorker.mjs'
1488 for (const workerNode of pool.workerNodes) {
1489 workerNode.strategyData = {
1490 virtualTaskEndTimestamp: performance.now()
1493 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
1494 for (const workerNode of pool.workerNodes) {
1495 expect(workerNode.strategyData.virtualTaskEndTimestamp).toBeUndefined()
1497 // We need to clean up the resources after our test
1498 await pool.destroy()
1501 it('Verify WEIGHTED_ROUND_ROBIN strategy default policy', async () => {
1502 const workerChoiceStrategy = WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
1503 let pool = new FixedThreadPool(
1505 './tests/worker-files/thread/testWorker.mjs',
1506 { workerChoiceStrategy }
1508 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
1509 dynamicWorkerUsage: false,
1510 dynamicWorkerReady: true
1512 await pool.destroy()
1513 pool = new DynamicThreadPool(
1516 './tests/worker-files/thread/testWorker.mjs',
1517 { workerChoiceStrategy }
1519 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
1520 dynamicWorkerUsage: false,
1521 dynamicWorkerReady: true
1523 // We need to clean up the resources after our test
1524 await pool.destroy()
1527 it('Verify WEIGHTED_ROUND_ROBIN strategy default tasks statistics requirements', async () => {
1528 const workerChoiceStrategy = WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
1529 let pool = new FixedThreadPool(
1531 './tests/worker-files/thread/testWorker.mjs',
1532 { workerChoiceStrategy }
1535 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
1553 await pool.destroy()
1554 pool = new DynamicThreadPool(
1557 './tests/worker-files/thread/testWorker.mjs',
1558 { workerChoiceStrategy }
1561 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
1579 // We need to clean up the resources after our test
1580 await pool.destroy()
1583 it('Verify WEIGHTED_ROUND_ROBIN strategy can be run in a fixed pool', async () => {
1584 const pool = new FixedThreadPool(
1586 './tests/worker-files/thread/testWorker.mjs',
1587 { workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN }
1589 // TODO: Create a better test to cover `WeightedRoundRobinWorkerChoiceStrategy#choose`
1590 const promises = new Set()
1591 const maxMultiplier = 2
1592 for (let i = 0; i < max * maxMultiplier; i++) {
1593 promises.add(pool.execute())
1595 await Promise.all(promises)
1596 for (const workerNode of pool.workerNodes) {
1597 expect(workerNode.usage).toStrictEqual({
1599 executed: expect.any(Number),
1603 sequentiallyStolen: 0,
1607 runTime: expect.objectContaining({
1608 history: expect.any(CircularArray)
1611 history: new CircularArray()
1615 history: new CircularArray()
1618 history: new CircularArray()
1622 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
1623 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
1626 if (workerNode.usage.runTime.aggregate == null) {
1627 expect(workerNode.usage.runTime.aggregate).toBeUndefined()
1629 expect(workerNode.usage.runTime.aggregate).toBeGreaterThan(0)
1631 if (workerNode.usage.runTime.average == null) {
1632 expect(workerNode.usage.runTime.average).toBeUndefined()
1634 expect(workerNode.usage.runTime.average).toBeGreaterThan(0)
1638 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1639 pool.workerChoiceStrategyContext.workerChoiceStrategy
1643 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1644 pool.workerChoiceStrategyContext.workerChoiceStrategy
1645 ).previousWorkerNodeKey
1648 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1649 pool.workerChoiceStrategyContext.workerChoiceStrategy
1650 ).workerNodeVirtualTaskRunTime
1651 ).toBeGreaterThanOrEqual(0)
1652 // We need to clean up the resources after our test
1653 await pool.destroy()
1656 it('Verify WEIGHTED_ROUND_ROBIN strategy can be run in a dynamic pool', async () => {
1657 const pool = new DynamicThreadPool(
1660 './tests/worker-files/thread/testWorker.mjs',
1661 { workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN }
1663 // TODO: Create a better test to cover `WeightedRoundRobinWorkerChoiceStrategy#choose`
1664 const promises = new Set()
1665 const maxMultiplier = 2
1666 for (let i = 0; i < max * maxMultiplier; i++) {
1667 promises.add(pool.execute())
1669 await Promise.all(promises)
1670 for (const workerNode of pool.workerNodes) {
1671 expect(workerNode.usage).toStrictEqual({
1673 executed: expect.any(Number),
1677 sequentiallyStolen: 0,
1681 runTime: expect.objectContaining({
1682 history: expect.any(CircularArray)
1685 history: new CircularArray()
1689 history: new CircularArray()
1692 history: new CircularArray()
1696 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
1697 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
1700 if (workerNode.usage.runTime.aggregate == null) {
1701 expect(workerNode.usage.runTime.aggregate).toBeUndefined()
1703 expect(workerNode.usage.runTime.aggregate).toBeGreaterThan(0)
1705 if (workerNode.usage.runTime.average == null) {
1706 expect(workerNode.usage.runTime.average).toBeUndefined()
1708 expect(workerNode.usage.runTime.average).toBeGreaterThan(0)
1712 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1713 pool.workerChoiceStrategyContext.workerChoiceStrategy
1717 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1718 pool.workerChoiceStrategyContext.workerChoiceStrategy
1719 ).previousWorkerNodeKey
1722 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1723 pool.workerChoiceStrategyContext.workerChoiceStrategy
1724 ).workerNodeVirtualTaskRunTime
1725 ).toBeGreaterThanOrEqual(0)
1726 // We need to clean up the resources after our test
1727 await pool.destroy()
1730 it('Verify WEIGHTED_ROUND_ROBIN strategy can be run in a dynamic pool with median runtime statistic', async () => {
1731 const pool = new DynamicThreadPool(
1734 './tests/worker-files/thread/testWorker.mjs',
1736 workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN,
1737 workerChoiceStrategyOptions: {
1738 runTime: { median: true }
1742 // TODO: Create a better test to cover `WeightedRoundRobinWorkerChoiceStrategy#choose`
1743 const promises = new Set()
1744 const maxMultiplier = 2
1745 for (let i = 0; i < max * maxMultiplier; i++) {
1746 promises.add(pool.execute())
1748 await Promise.all(promises)
1749 for (const workerNode of pool.workerNodes) {
1750 expect(workerNode.usage).toStrictEqual({
1752 executed: expect.any(Number),
1756 sequentiallyStolen: 0,
1760 runTime: expect.objectContaining({
1761 history: expect.any(CircularArray)
1764 history: new CircularArray()
1768 history: new CircularArray()
1771 history: new CircularArray()
1775 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
1776 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
1779 if (workerNode.usage.runTime.aggregate == null) {
1780 expect(workerNode.usage.runTime.aggregate).toBeUndefined()
1782 expect(workerNode.usage.runTime.aggregate).toBeGreaterThan(0)
1784 if (workerNode.usage.runTime.median == null) {
1785 expect(workerNode.usage.runTime.median).toBeUndefined()
1787 expect(workerNode.usage.runTime.median).toBeGreaterThan(0)
1791 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1792 pool.workerChoiceStrategyContext.workerChoiceStrategy
1796 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1797 pool.workerChoiceStrategyContext.workerChoiceStrategy
1798 ).previousWorkerNodeKey
1801 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1802 pool.workerChoiceStrategyContext.workerChoiceStrategy
1803 ).workerNodeVirtualTaskRunTime
1804 ).toBeGreaterThanOrEqual(0)
1805 // We need to clean up the resources after our test
1806 await pool.destroy()
1809 it('Verify WEIGHTED_ROUND_ROBIN strategy internals are resets after setting it', async () => {
1810 const workerChoiceStrategy = WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
1811 let pool = new FixedThreadPool(
1813 './tests/worker-files/thread/testWorker.mjs'
1816 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1817 workerChoiceStrategy
1821 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1822 workerChoiceStrategy
1823 ).previousWorkerNodeKey
1826 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1827 workerChoiceStrategy
1828 ).workerNodeVirtualTaskRunTime
1830 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
1832 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1833 pool.workerChoiceStrategyContext.workerChoiceStrategy
1837 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1838 pool.workerChoiceStrategyContext.workerChoiceStrategy
1839 ).previousWorkerNodeKey
1842 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1843 pool.workerChoiceStrategyContext.workerChoiceStrategy
1844 ).workerNodeVirtualTaskRunTime
1846 await pool.destroy()
1847 pool = new DynamicThreadPool(
1850 './tests/worker-files/thread/testWorker.mjs'
1853 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1854 workerChoiceStrategy
1858 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1859 workerChoiceStrategy
1860 ).previousWorkerNodeKey
1863 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1864 workerChoiceStrategy
1865 ).workerNodeVirtualTaskRunTime
1867 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
1869 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1870 pool.workerChoiceStrategyContext.workerChoiceStrategy
1874 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1875 pool.workerChoiceStrategyContext.workerChoiceStrategy
1876 ).previousWorkerNodeKey
1879 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1880 pool.workerChoiceStrategyContext.workerChoiceStrategy
1881 ).workerNodeVirtualTaskRunTime
1883 // We need to clean up the resources after our test
1884 await pool.destroy()
1887 it('Verify INTERLEAVED_WEIGHTED_ROUND_ROBIN strategy default policy', async () => {
1888 const workerChoiceStrategy =
1889 WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
1890 let pool = new FixedThreadPool(
1892 './tests/worker-files/thread/testWorker.mjs',
1893 { workerChoiceStrategy }
1895 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
1896 dynamicWorkerUsage: false,
1897 dynamicWorkerReady: true
1899 await pool.destroy()
1900 pool = new DynamicThreadPool(
1903 './tests/worker-files/thread/testWorker.mjs',
1904 { workerChoiceStrategy }
1906 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
1907 dynamicWorkerUsage: false,
1908 dynamicWorkerReady: true
1910 // We need to clean up the resources after our test
1911 await pool.destroy()
1914 it('Verify INTERLEAVED_WEIGHTED_ROUND_ROBIN strategy default tasks statistics requirements', async () => {
1915 const workerChoiceStrategy =
1916 WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
1917 let pool = new FixedThreadPool(
1919 './tests/worker-files/thread/testWorker.mjs',
1920 { workerChoiceStrategy }
1923 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
1941 await pool.destroy()
1942 pool = new DynamicThreadPool(
1945 './tests/worker-files/thread/testWorker.mjs',
1946 { workerChoiceStrategy }
1949 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
1967 // We need to clean up the resources after our test
1968 await pool.destroy()
1971 it('Verify INTERLEAVED_WEIGHTED_ROUND_ROBIN strategy can be run in a fixed pool', async () => {
1972 const pool = new FixedThreadPool(
1974 './tests/worker-files/thread/testWorker.mjs',
1976 workerChoiceStrategy:
1977 WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
1980 // TODO: Create a better test to cover `InterleavedWeightedRoundRobinWorkerChoiceStrategy#choose`
1981 const promises = new Set()
1982 const maxMultiplier = 2
1983 for (let i = 0; i < max * maxMultiplier; i++) {
1984 promises.add(pool.execute())
1986 await Promise.all(promises)
1987 for (const workerNode of pool.workerNodes) {
1988 expect(workerNode.usage).toStrictEqual({
1990 executed: expect.any(Number),
1994 sequentiallyStolen: 0,
1998 runTime: expect.objectContaining({
1999 history: expect.any(CircularArray)
2002 history: new CircularArray()
2006 history: new CircularArray()
2009 history: new CircularArray()
2013 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
2014 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
2019 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2020 pool.workerChoiceStrategyContext.workerChoiceStrategy
2024 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2025 pool.workerChoiceStrategyContext.workerChoiceStrategy
2029 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2030 pool.workerChoiceStrategyContext.workerChoiceStrategy
2034 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2035 pool.workerChoiceStrategyContext.workerChoiceStrategy
2036 ).previousWorkerNodeKey
2039 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2040 pool.workerChoiceStrategyContext.workerChoiceStrategy
2041 ).roundWeights.length
2044 Number.isSafeInteger(
2045 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2046 pool.workerChoiceStrategyContext.workerChoiceStrategy
2050 // We need to clean up the resources after our test
2051 await pool.destroy()
2054 it('Verify INTERLEAVED_WEIGHTED_ROUND_ROBIN strategy can be run in a dynamic pool', async () => {
2055 const pool = new DynamicThreadPool(
2058 './tests/worker-files/thread/testWorker.mjs',
2060 workerChoiceStrategy:
2061 WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
2064 // TODO: Create a better test to cover `InterleavedWeightedRoundRobinWorkerChoiceStrategy#choose`
2065 const promises = new Set()
2066 const maxMultiplier = 2
2067 for (let i = 0; i < max * maxMultiplier; i++) {
2068 promises.add(pool.execute())
2070 await Promise.all(promises)
2071 for (const workerNode of pool.workerNodes) {
2072 expect(workerNode.usage).toStrictEqual({
2074 executed: expect.any(Number),
2078 sequentiallyStolen: 0,
2082 runTime: expect.objectContaining({
2083 history: expect.any(CircularArray)
2086 history: new CircularArray()
2090 history: new CircularArray()
2093 history: new CircularArray()
2097 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
2098 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
2103 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2104 pool.workerChoiceStrategyContext.workerChoiceStrategy
2108 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2109 pool.workerChoiceStrategyContext.workerChoiceStrategy
2113 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2114 pool.workerChoiceStrategyContext.workerChoiceStrategy
2118 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2119 pool.workerChoiceStrategyContext.workerChoiceStrategy
2120 ).previousWorkerNodeKey
2123 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2124 pool.workerChoiceStrategyContext.workerChoiceStrategy
2125 ).roundWeights.length
2128 Number.isSafeInteger(
2129 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2130 pool.workerChoiceStrategyContext.workerChoiceStrategy
2134 // We need to clean up the resources after our test
2135 await pool.destroy()
2138 it('Verify INTERLEAVED_WEIGHTED_ROUND_ROBIN strategy internals are resets after setting it', async () => {
2139 const workerChoiceStrategy =
2140 WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
2141 let pool = new FixedThreadPool(
2143 './tests/worker-files/thread/testWorker.mjs'
2146 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2147 workerChoiceStrategy
2151 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2152 workerChoiceStrategy
2156 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2157 workerChoiceStrategy
2161 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2162 workerChoiceStrategy
2163 ).previousWorkerNodeKey
2166 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2167 workerChoiceStrategy
2170 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
2172 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2173 pool.workerChoiceStrategyContext.workerChoiceStrategy
2177 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2178 pool.workerChoiceStrategyContext.workerChoiceStrategy
2182 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2183 pool.workerChoiceStrategyContext.workerChoiceStrategy
2187 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2188 pool.workerChoiceStrategyContext.workerChoiceStrategy
2189 ).previousWorkerNodeKey
2192 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2193 pool.workerChoiceStrategyContext.workerChoiceStrategy
2194 ).roundWeights.length
2197 Number.isSafeInteger(
2198 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2199 pool.workerChoiceStrategyContext.workerChoiceStrategy
2203 await pool.destroy()
2204 pool = new DynamicThreadPool(
2207 './tests/worker-files/thread/testWorker.mjs'
2210 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2211 workerChoiceStrategy
2215 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2216 workerChoiceStrategy
2220 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2221 workerChoiceStrategy
2225 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2226 workerChoiceStrategy
2227 ).previousWorkerNodeKey
2230 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2231 workerChoiceStrategy
2234 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
2236 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2237 pool.workerChoiceStrategyContext.workerChoiceStrategy
2241 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2242 pool.workerChoiceStrategyContext.workerChoiceStrategy
2246 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2247 pool.workerChoiceStrategyContext.workerChoiceStrategy
2251 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2252 pool.workerChoiceStrategyContext.workerChoiceStrategy
2253 ).previousWorkerNodeKey
2256 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2257 pool.workerChoiceStrategyContext.workerChoiceStrategy
2258 ).roundWeights.length
2261 Number.isSafeInteger(
2262 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2263 pool.workerChoiceStrategyContext.workerChoiceStrategy
2267 // We need to clean up the resources after our test
2268 await pool.destroy()
2271 it('Verify unknown strategy throw error', () => {
2274 new DynamicThreadPool(
2277 './tests/worker-files/thread/testWorker.mjs',
2278 { workerChoiceStrategy: 'UNKNOWN_STRATEGY' }
2280 ).toThrow("Invalid worker choice strategy 'UNKNOWN_STRATEGY'")