1 import { expect } from 'expect'
8 } from '../../../lib/index.js'
9 import { CircularArray } from '../../../lib/circular-array.js'
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.js'
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
165 it('Verify strategies wait for worker node readiness in dynamic pool', async () => {
166 const pool = new DynamicThreadPool(
169 './tests/worker-files/thread/testWorker.mjs'
171 expect(pool.starting).toBe(false)
172 expect(pool.workerNodes.length).toBe(min)
173 const maxMultiplier = 10000
174 const promises = new Set()
175 for (let i = 0; i < max * maxMultiplier; i++) {
176 promises.add(pool.execute())
178 await Promise.all(promises)
179 expect(pool.workerNodes.length).toBe(max)
180 // We need to clean up the resources after our test
184 it('Verify ROUND_ROBIN strategy default policy', async () => {
185 const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN
186 let pool = new FixedThreadPool(
188 './tests/worker-files/thread/testWorker.mjs',
189 { workerChoiceStrategy }
191 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
192 dynamicWorkerUsage: false,
193 dynamicWorkerReady: true
196 pool = new DynamicThreadPool(
199 './tests/worker-files/thread/testWorker.mjs',
200 { workerChoiceStrategy }
202 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
203 dynamicWorkerUsage: false,
204 dynamicWorkerReady: true
206 // We need to clean up the resources after our test
210 it('Verify ROUND_ROBIN strategy default tasks statistics requirements', async () => {
211 const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN
212 let pool = new FixedThreadPool(
214 './tests/worker-files/thread/testWorker.mjs',
215 { workerChoiceStrategy }
218 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
237 pool = new DynamicThreadPool(
240 './tests/worker-files/thread/testWorker.mjs',
241 { workerChoiceStrategy }
244 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
262 // We need to clean up the resources after our test
266 it('Verify ROUND_ROBIN strategy can be run in a fixed pool', async () => {
267 const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN
268 const pool = new FixedThreadPool(
270 './tests/worker-files/thread/testWorker.mjs',
271 { workerChoiceStrategy }
273 // TODO: Create a better test to cover `RoundRobinWorkerChoiceStrategy#choose`
274 const promises = new Set()
275 const maxMultiplier = 2
276 for (let i = 0; i < max * maxMultiplier; i++) {
277 promises.add(pool.execute())
279 await Promise.all(promises)
280 for (const workerNode of pool.workerNodes) {
281 expect(workerNode.usage).toStrictEqual({
283 executed: maxMultiplier,
287 sequentiallyStolen: 0,
292 history: new CircularArray()
295 history: new CircularArray()
299 history: new CircularArray()
302 history: new CircularArray()
308 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
309 pool.workerChoiceStrategyContext.workerChoiceStrategy
313 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
314 pool.workerChoiceStrategyContext.workerChoiceStrategy
315 ).previousWorkerNodeKey
316 ).toBe(pool.workerNodes.length - 1)
317 // We need to clean up the resources after our test
321 it('Verify ROUND_ROBIN strategy can be run in a dynamic pool', async () => {
322 const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN
323 const pool = new DynamicThreadPool(
326 './tests/worker-files/thread/testWorker.mjs',
327 { workerChoiceStrategy }
329 // TODO: Create a better test to cover `RoundRobinWorkerChoiceStrategy#choose`
330 const promises = new Set()
331 const maxMultiplier = 2
332 for (let i = 0; i < max * maxMultiplier; i++) {
333 promises.add(pool.execute())
335 await Promise.all(promises)
336 for (const workerNode of pool.workerNodes) {
337 expect(workerNode.usage).toStrictEqual({
339 executed: expect.any(Number),
343 sequentiallyStolen: 0,
348 history: new CircularArray()
351 history: new CircularArray()
355 history: new CircularArray()
358 history: new CircularArray()
362 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
363 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
368 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
369 pool.workerChoiceStrategyContext.workerChoiceStrategy
373 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
374 pool.workerChoiceStrategyContext.workerChoiceStrategy
375 ).previousWorkerNodeKey
376 ).toBe(pool.workerNodes.length - 1)
377 // We need to clean up the resources after our test
381 it('Verify ROUND_ROBIN strategy runtime behavior', async () => {
382 const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN
383 let pool = new FixedClusterPool(
385 './tests/worker-files/cluster/testWorker.js',
386 { workerChoiceStrategy }
388 let results = new Set()
389 for (let i = 0; i < max; i++) {
390 results.add(pool.workerNodes[pool.chooseWorkerNode()].info.id)
392 expect(results.size).toBe(max)
394 pool = new FixedThreadPool(
396 './tests/worker-files/thread/testWorker.mjs',
397 { workerChoiceStrategy }
400 for (let i = 0; i < max; i++) {
401 results.add(pool.workerNodes[pool.chooseWorkerNode()].info.id)
403 expect(results.size).toBe(max)
407 it('Verify ROUND_ROBIN strategy internals are resets after setting it', async () => {
408 const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN
409 let pool = new FixedThreadPool(
411 './tests/worker-files/thread/testWorker.mjs',
412 { workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN }
415 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
416 pool.workerChoiceStrategyContext.workerChoiceStrategy
420 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
421 pool.workerChoiceStrategyContext.workerChoiceStrategy
422 ).previousWorkerNodeKey
424 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
426 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
427 pool.workerChoiceStrategyContext.workerChoiceStrategy
431 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
432 pool.workerChoiceStrategyContext.workerChoiceStrategy
433 ).previousWorkerNodeKey
436 pool = new DynamicThreadPool(
439 './tests/worker-files/thread/testWorker.mjs',
440 { workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN }
443 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
444 pool.workerChoiceStrategyContext.workerChoiceStrategy
448 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
449 pool.workerChoiceStrategyContext.workerChoiceStrategy
450 ).previousWorkerNodeKey
452 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
454 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
455 pool.workerChoiceStrategyContext.workerChoiceStrategy
459 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
460 pool.workerChoiceStrategyContext.workerChoiceStrategy
461 ).previousWorkerNodeKey
463 // We need to clean up the resources after our test
467 it('Verify LEAST_USED strategy default policy', async () => {
468 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_USED
469 let pool = new FixedThreadPool(
471 './tests/worker-files/thread/testWorker.mjs',
472 { workerChoiceStrategy }
474 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
475 dynamicWorkerUsage: false,
476 dynamicWorkerReady: true
479 pool = new DynamicThreadPool(
482 './tests/worker-files/thread/testWorker.mjs',
483 { workerChoiceStrategy }
485 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
486 dynamicWorkerUsage: false,
487 dynamicWorkerReady: true
489 // We need to clean up the resources after our test
493 it('Verify LEAST_USED strategy default tasks statistics requirements', async () => {
494 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_USED
495 let pool = new FixedThreadPool(
497 './tests/worker-files/thread/testWorker.mjs',
498 { workerChoiceStrategy }
501 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
520 pool = new DynamicThreadPool(
523 './tests/worker-files/thread/testWorker.mjs',
524 { workerChoiceStrategy }
527 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
545 // We need to clean up the resources after our test
549 it('Verify LEAST_USED strategy can be run in a fixed pool', async () => {
550 const pool = new FixedThreadPool(
552 './tests/worker-files/thread/testWorker.mjs',
553 { workerChoiceStrategy: WorkerChoiceStrategies.LEAST_USED }
555 // TODO: Create a better test to cover `LeastUsedWorkerChoiceStrategy#choose`
556 const promises = new Set()
557 const maxMultiplier = 2
558 for (let i = 0; i < max * maxMultiplier; i++) {
559 promises.add(pool.execute())
561 await Promise.all(promises)
562 for (const workerNode of pool.workerNodes) {
563 expect(workerNode.usage).toStrictEqual({
565 executed: expect.any(Number),
569 sequentiallyStolen: 0,
574 history: new CircularArray()
577 history: new CircularArray()
581 history: new CircularArray()
584 history: new CircularArray()
588 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
589 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
594 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
595 pool.workerChoiceStrategyContext.workerChoiceStrategy
597 ).toEqual(expect.any(Number))
599 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
600 pool.workerChoiceStrategyContext.workerChoiceStrategy
601 ).previousWorkerNodeKey
602 ).toEqual(expect.any(Number))
603 // We need to clean up the resources after our test
607 it('Verify LEAST_USED strategy can be run in a dynamic pool', async () => {
608 const pool = new DynamicThreadPool(
611 './tests/worker-files/thread/testWorker.mjs',
612 { workerChoiceStrategy: WorkerChoiceStrategies.LEAST_USED }
614 // TODO: Create a better test to cover `LeastUsedWorkerChoiceStrategy#choose`
615 const promises = new Set()
616 const maxMultiplier = 2
617 for (let i = 0; i < max * maxMultiplier; i++) {
618 promises.add(pool.execute())
620 await Promise.all(promises)
621 for (const workerNode of pool.workerNodes) {
622 expect(workerNode.usage).toStrictEqual({
624 executed: expect.any(Number),
628 sequentiallyStolen: 0,
633 history: new CircularArray()
636 history: new CircularArray()
640 history: new CircularArray()
643 history: new CircularArray()
647 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
648 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
653 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
654 pool.workerChoiceStrategyContext.workerChoiceStrategy
656 ).toEqual(expect.any(Number))
658 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
659 pool.workerChoiceStrategyContext.workerChoiceStrategy
660 ).previousWorkerNodeKey
661 ).toEqual(expect.any(Number))
662 // We need to clean up the resources after our test
666 it('Verify LEAST_BUSY strategy default policy', async () => {
667 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_BUSY
668 let pool = new FixedThreadPool(
670 './tests/worker-files/thread/testWorker.mjs',
671 { workerChoiceStrategy }
673 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
674 dynamicWorkerUsage: false,
675 dynamicWorkerReady: true
678 pool = new DynamicThreadPool(
681 './tests/worker-files/thread/testWorker.mjs',
682 { workerChoiceStrategy }
684 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
685 dynamicWorkerUsage: false,
686 dynamicWorkerReady: true
688 // We need to clean up the resources after our test
692 it('Verify LEAST_BUSY strategy default tasks statistics requirements', async () => {
693 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_BUSY
694 let pool = new FixedThreadPool(
696 './tests/worker-files/thread/testWorker.mjs',
697 { workerChoiceStrategy }
700 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
719 pool = new DynamicThreadPool(
722 './tests/worker-files/thread/testWorker.mjs',
723 { workerChoiceStrategy }
726 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
744 // We need to clean up the resources after our test
748 it('Verify LEAST_BUSY strategy can be run in a fixed pool', async () => {
749 const pool = new FixedThreadPool(
751 './tests/worker-files/thread/testWorker.mjs',
752 { workerChoiceStrategy: WorkerChoiceStrategies.LEAST_BUSY }
754 // TODO: Create a better test to cover `LeastBusyWorkerChoiceStrategy#choose`
755 const promises = new Set()
756 const maxMultiplier = 2
757 for (let i = 0; i < max * maxMultiplier; i++) {
758 promises.add(pool.execute())
760 await Promise.all(promises)
761 for (const workerNode of pool.workerNodes) {
762 expect(workerNode.usage).toStrictEqual({
764 executed: expect.any(Number),
768 sequentiallyStolen: 0,
772 runTime: expect.objectContaining({
773 history: expect.any(CircularArray)
775 waitTime: expect.objectContaining({
776 history: expect.any(CircularArray)
780 history: new CircularArray()
783 history: new CircularArray()
787 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
788 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
791 if (workerNode.usage.runTime.aggregate == null) {
792 expect(workerNode.usage.runTime.aggregate).toBeUndefined()
794 expect(workerNode.usage.runTime.aggregate).toBeGreaterThan(0)
796 if (workerNode.usage.waitTime.aggregate == null) {
797 expect(workerNode.usage.waitTime.aggregate).toBeUndefined()
799 expect(workerNode.usage.waitTime.aggregate).toBeGreaterThan(0)
803 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
804 pool.workerChoiceStrategyContext.workerChoiceStrategy
806 ).toEqual(expect.any(Number))
808 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
809 pool.workerChoiceStrategyContext.workerChoiceStrategy
810 ).previousWorkerNodeKey
811 ).toEqual(expect.any(Number))
812 // We need to clean up the resources after our test
816 it('Verify LEAST_BUSY strategy can be run in a dynamic pool', async () => {
817 const pool = new DynamicThreadPool(
820 './tests/worker-files/thread/testWorker.mjs',
821 { workerChoiceStrategy: WorkerChoiceStrategies.LEAST_BUSY }
823 // TODO: Create a better test to cover `LeastBusyWorkerChoiceStrategy#choose`
824 const promises = new Set()
825 const maxMultiplier = 2
826 for (let i = 0; i < max * maxMultiplier; i++) {
827 promises.add(pool.execute())
829 await Promise.all(promises)
830 for (const workerNode of pool.workerNodes) {
831 expect(workerNode.usage).toStrictEqual({
833 executed: expect.any(Number),
837 sequentiallyStolen: 0,
841 runTime: expect.objectContaining({
842 history: expect.any(CircularArray)
844 waitTime: expect.objectContaining({
845 history: expect.any(CircularArray)
849 history: new CircularArray()
852 history: new CircularArray()
856 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
857 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
860 if (workerNode.usage.runTime.aggregate == null) {
861 expect(workerNode.usage.runTime.aggregate).toBeUndefined()
863 expect(workerNode.usage.runTime.aggregate).toBeGreaterThan(0)
865 if (workerNode.usage.waitTime.aggregate == null) {
866 expect(workerNode.usage.waitTime.aggregate).toBeUndefined()
868 expect(workerNode.usage.waitTime.aggregate).toBeGreaterThan(0)
872 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
873 pool.workerChoiceStrategyContext.workerChoiceStrategy
875 ).toEqual(expect.any(Number))
877 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
878 pool.workerChoiceStrategyContext.workerChoiceStrategy
879 ).previousWorkerNodeKey
880 ).toEqual(expect.any(Number))
881 // We need to clean up the resources after our test
885 it('Verify LEAST_ELU strategy default policy', async () => {
886 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_ELU
887 let pool = new FixedThreadPool(
889 './tests/worker-files/thread/testWorker.mjs',
890 { workerChoiceStrategy }
892 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
893 dynamicWorkerUsage: false,
894 dynamicWorkerReady: true
897 pool = new DynamicThreadPool(
900 './tests/worker-files/thread/testWorker.mjs',
901 { workerChoiceStrategy }
903 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
904 dynamicWorkerUsage: false,
905 dynamicWorkerReady: true
907 // We need to clean up the resources after our test
911 it('Verify LEAST_ELU strategy default tasks statistics requirements', async () => {
912 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_ELU
913 let pool = new FixedThreadPool(
915 './tests/worker-files/thread/testWorker.mjs',
916 { workerChoiceStrategy }
919 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
938 pool = new DynamicThreadPool(
941 './tests/worker-files/thread/testWorker.mjs',
942 { workerChoiceStrategy }
945 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
963 // We need to clean up the resources after our test
967 it('Verify LEAST_ELU strategy can be run in a fixed pool', async () => {
968 const pool = new FixedThreadPool(
970 './tests/worker-files/thread/testWorker.mjs',
971 { workerChoiceStrategy: WorkerChoiceStrategies.LEAST_ELU }
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())
979 await Promise.all(promises)
980 for (const workerNode of pool.workerNodes) {
981 expect(workerNode.usage).toStrictEqual({
983 executed: expect.any(Number),
987 sequentiallyStolen: 0,
992 history: new CircularArray()
995 history: new CircularArray()
997 elu: expect.objectContaining({
998 idle: expect.objectContaining({
999 history: expect.any(CircularArray)
1001 active: expect.objectContaining({
1002 history: expect.any(CircularArray)
1006 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
1007 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
1010 if (workerNode.usage.elu.active.aggregate == null) {
1011 expect(workerNode.usage.elu.active.aggregate).toBeUndefined()
1013 expect(workerNode.usage.elu.active.aggregate).toBeGreaterThan(0)
1015 if (workerNode.usage.elu.idle.aggregate == null) {
1016 expect(workerNode.usage.elu.idle.aggregate).toBeUndefined()
1018 expect(workerNode.usage.elu.idle.aggregate).toBeGreaterThanOrEqual(0)
1020 if (workerNode.usage.elu.utilization == null) {
1021 expect(workerNode.usage.elu.utilization).toBeUndefined()
1023 expect(workerNode.usage.elu.utilization).toBeGreaterThanOrEqual(0)
1024 expect(workerNode.usage.elu.utilization).toBeLessThanOrEqual(1)
1028 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1029 pool.workerChoiceStrategyContext.workerChoiceStrategy
1031 ).toEqual(expect.any(Number))
1033 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1034 pool.workerChoiceStrategyContext.workerChoiceStrategy
1035 ).previousWorkerNodeKey
1036 ).toEqual(expect.any(Number))
1037 // We need to clean up the resources after our test
1038 await pool.destroy()
1041 it('Verify LEAST_ELU strategy can be run in a dynamic pool', async () => {
1042 const pool = new DynamicThreadPool(
1045 './tests/worker-files/thread/testWorker.mjs',
1046 { workerChoiceStrategy: WorkerChoiceStrategies.LEAST_ELU }
1048 // TODO: Create a better test to cover `LeastEluWorkerChoiceStrategy#choose`
1049 const promises = new Set()
1050 const maxMultiplier = 2
1051 for (let i = 0; i < max * maxMultiplier; i++) {
1052 promises.add(pool.execute())
1054 await Promise.all(promises)
1055 for (const workerNode of pool.workerNodes) {
1056 expect(workerNode.usage).toStrictEqual({
1058 executed: expect.any(Number),
1062 sequentiallyStolen: 0,
1067 history: new CircularArray()
1070 history: new CircularArray()
1072 elu: expect.objectContaining({
1073 idle: expect.objectContaining({
1074 history: expect.any(CircularArray)
1076 active: expect.objectContaining({
1077 history: expect.any(CircularArray)
1081 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
1082 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
1085 if (workerNode.usage.elu.active.aggregate == null) {
1086 expect(workerNode.usage.elu.active.aggregate).toBeUndefined()
1088 expect(workerNode.usage.elu.active.aggregate).toBeGreaterThan(0)
1090 if (workerNode.usage.elu.idle.aggregate == null) {
1091 expect(workerNode.usage.elu.idle.aggregate).toBeUndefined()
1093 expect(workerNode.usage.elu.idle.aggregate).toBeGreaterThanOrEqual(0)
1095 if (workerNode.usage.elu.utilization == null) {
1096 expect(workerNode.usage.elu.utilization).toBeUndefined()
1098 expect(workerNode.usage.elu.utilization).toBeGreaterThanOrEqual(0)
1099 expect(workerNode.usage.elu.utilization).toBeLessThanOrEqual(1)
1103 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1104 pool.workerChoiceStrategyContext.workerChoiceStrategy
1106 ).toEqual(expect.any(Number))
1108 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1109 pool.workerChoiceStrategyContext.workerChoiceStrategy
1110 ).previousWorkerNodeKey
1111 ).toEqual(expect.any(Number))
1112 // We need to clean up the resources after our test
1113 await pool.destroy()
1116 it('Verify FAIR_SHARE strategy default policy', async () => {
1117 const workerChoiceStrategy = WorkerChoiceStrategies.FAIR_SHARE
1118 let pool = new FixedThreadPool(
1120 './tests/worker-files/thread/testWorker.mjs',
1121 { workerChoiceStrategy }
1123 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
1124 dynamicWorkerUsage: false,
1125 dynamicWorkerReady: true
1127 await pool.destroy()
1128 pool = new DynamicThreadPool(
1131 './tests/worker-files/thread/testWorker.mjs',
1132 { workerChoiceStrategy }
1134 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
1135 dynamicWorkerUsage: false,
1136 dynamicWorkerReady: true
1138 // We need to clean up the resources after our test
1139 await pool.destroy()
1142 it('Verify FAIR_SHARE strategy default tasks statistics requirements', async () => {
1143 const workerChoiceStrategy = WorkerChoiceStrategies.FAIR_SHARE
1144 let pool = new FixedThreadPool(
1146 './tests/worker-files/thread/testWorker.mjs',
1147 { workerChoiceStrategy }
1150 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
1168 await pool.destroy()
1169 pool = new DynamicThreadPool(
1172 './tests/worker-files/thread/testWorker.mjs',
1173 { workerChoiceStrategy }
1176 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
1194 // We need to clean up the resources after our test
1195 await pool.destroy()
1198 it('Verify FAIR_SHARE strategy can be run in a fixed pool', async () => {
1199 const pool = new FixedThreadPool(
1201 './tests/worker-files/thread/testWorker.mjs',
1202 { workerChoiceStrategy: WorkerChoiceStrategies.FAIR_SHARE }
1204 // TODO: Create a better test to cover `FairShareChoiceStrategy#choose`
1205 const promises = new Set()
1206 const maxMultiplier = 2
1207 for (let i = 0; i < max * maxMultiplier; i++) {
1208 promises.add(pool.execute())
1210 await Promise.all(promises)
1211 for (const workerNode of pool.workerNodes) {
1212 expect(workerNode.usage).toStrictEqual({
1214 executed: expect.any(Number),
1218 sequentiallyStolen: 0,
1222 runTime: expect.objectContaining({
1223 history: expect.any(CircularArray)
1226 history: new CircularArray()
1228 elu: expect.objectContaining({
1229 idle: expect.objectContaining({
1230 history: expect.any(CircularArray)
1232 active: expect.objectContaining({
1233 history: expect.any(CircularArray)
1237 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
1238 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
1241 if (workerNode.usage.runTime.aggregate == null) {
1242 expect(workerNode.usage.runTime.aggregate).toBeUndefined()
1244 expect(workerNode.usage.runTime.aggregate).toBeGreaterThan(0)
1246 if (workerNode.usage.runTime.average == null) {
1247 expect(workerNode.usage.runTime.average).toBeUndefined()
1249 expect(workerNode.usage.runTime.average).toBeGreaterThan(0)
1251 if (workerNode.usage.elu.active.aggregate == null) {
1252 expect(workerNode.usage.elu.active.aggregate).toBeUndefined()
1254 expect(workerNode.usage.elu.active.aggregate).toBeGreaterThan(0)
1256 if (workerNode.usage.elu.idle.aggregate == null) {
1257 expect(workerNode.usage.elu.idle.aggregate).toBeUndefined()
1259 expect(workerNode.usage.elu.idle.aggregate).toBeGreaterThanOrEqual(0)
1261 if (workerNode.usage.elu.utilization == null) {
1262 expect(workerNode.usage.elu.utilization).toBeUndefined()
1264 expect(workerNode.usage.elu.utilization).toBeGreaterThanOrEqual(0)
1265 expect(workerNode.usage.elu.utilization).toBeLessThanOrEqual(1)
1267 expect(workerNode.strategyData.virtualTaskEndTimestamp).toBeGreaterThan(0)
1270 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1271 pool.workerChoiceStrategyContext.workerChoiceStrategy
1273 ).toEqual(expect.any(Number))
1275 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1276 pool.workerChoiceStrategyContext.workerChoiceStrategy
1277 ).previousWorkerNodeKey
1278 ).toEqual(expect.any(Number))
1279 // We need to clean up the resources after our test
1280 await pool.destroy()
1283 it('Verify FAIR_SHARE strategy can be run in a dynamic pool', async () => {
1284 const pool = new DynamicThreadPool(
1287 './tests/worker-files/thread/testWorker.mjs',
1288 { workerChoiceStrategy: WorkerChoiceStrategies.FAIR_SHARE }
1290 // TODO: Create a better test to cover `FairShareChoiceStrategy#choose`
1291 const promises = new Set()
1292 const maxMultiplier = 2
1293 for (let i = 0; i < max * maxMultiplier; i++) {
1294 promises.add(pool.execute())
1296 await Promise.all(promises)
1297 for (const workerNode of pool.workerNodes) {
1298 expect(workerNode.usage).toStrictEqual({
1300 executed: expect.any(Number),
1304 sequentiallyStolen: 0,
1308 runTime: expect.objectContaining({
1309 history: expect.any(CircularArray)
1312 history: new CircularArray()
1314 elu: expect.objectContaining({
1315 idle: expect.objectContaining({
1316 history: expect.any(CircularArray)
1318 active: expect.objectContaining({
1319 history: expect.any(CircularArray)
1323 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
1324 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
1327 if (workerNode.usage.runTime.aggregate == null) {
1328 expect(workerNode.usage.runTime.aggregate).toBeUndefined()
1330 expect(workerNode.usage.runTime.aggregate).toBeGreaterThan(0)
1332 if (workerNode.usage.runTime.average == null) {
1333 expect(workerNode.usage.runTime.average).toBeUndefined()
1335 expect(workerNode.usage.runTime.average).toBeGreaterThan(0)
1337 if (workerNode.usage.elu.active.aggregate == null) {
1338 expect(workerNode.usage.elu.active.aggregate).toBeUndefined()
1340 expect(workerNode.usage.elu.active.aggregate).toBeGreaterThan(0)
1342 if (workerNode.usage.elu.idle.aggregate == null) {
1343 expect(workerNode.usage.elu.idle.aggregate).toBeUndefined()
1345 expect(workerNode.usage.elu.idle.aggregate).toBeGreaterThanOrEqual(0)
1347 if (workerNode.usage.elu.utilization == null) {
1348 expect(workerNode.usage.elu.utilization).toBeUndefined()
1350 expect(workerNode.usage.elu.utilization).toBeGreaterThanOrEqual(0)
1351 expect(workerNode.usage.elu.utilization).toBeLessThanOrEqual(1)
1353 expect(workerNode.strategyData.virtualTaskEndTimestamp).toBeGreaterThan(0)
1356 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1357 pool.workerChoiceStrategyContext.workerChoiceStrategy
1359 ).toEqual(expect.any(Number))
1361 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1362 pool.workerChoiceStrategyContext.workerChoiceStrategy
1363 ).previousWorkerNodeKey
1364 ).toEqual(expect.any(Number))
1365 // We need to clean up the resources after our test
1366 await pool.destroy()
1369 it('Verify FAIR_SHARE strategy can be run in a dynamic pool with median runtime statistic', async () => {
1370 const pool = new DynamicThreadPool(
1373 './tests/worker-files/thread/testWorker.mjs',
1375 workerChoiceStrategy: WorkerChoiceStrategies.FAIR_SHARE,
1376 workerChoiceStrategyOptions: {
1377 runTime: { median: true }
1381 // TODO: Create a better test to cover `FairShareChoiceStrategy#choose`
1382 const promises = new Set()
1383 const maxMultiplier = 2
1384 for (let i = 0; i < max * maxMultiplier; i++) {
1385 promises.add(pool.execute())
1387 await Promise.all(promises)
1388 for (const workerNode of pool.workerNodes) {
1389 expect(workerNode.usage).toStrictEqual({
1391 executed: expect.any(Number),
1395 sequentiallyStolen: 0,
1399 runTime: expect.objectContaining({
1400 history: expect.any(CircularArray)
1403 history: new CircularArray()
1405 elu: expect.objectContaining({
1406 idle: expect.objectContaining({
1407 history: expect.any(CircularArray)
1409 active: expect.objectContaining({
1410 history: expect.any(CircularArray)
1414 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
1415 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
1418 if (workerNode.usage.runTime.aggregate == null) {
1419 expect(workerNode.usage.runTime.aggregate).toBeUndefined()
1421 expect(workerNode.usage.runTime.aggregate).toBeGreaterThan(0)
1423 if (workerNode.usage.runTime.median == null) {
1424 expect(workerNode.usage.runTime.median).toBeUndefined()
1426 expect(workerNode.usage.runTime.median).toBeGreaterThan(0)
1428 if (workerNode.usage.elu.active.aggregate == null) {
1429 expect(workerNode.usage.elu.active.aggregate).toBeUndefined()
1431 expect(workerNode.usage.elu.active.aggregate).toBeGreaterThan(0)
1433 if (workerNode.usage.elu.idle.aggregate == null) {
1434 expect(workerNode.usage.elu.idle.aggregate).toBeUndefined()
1436 expect(workerNode.usage.elu.idle.aggregate).toBeGreaterThanOrEqual(0)
1438 if (workerNode.usage.elu.utilization == null) {
1439 expect(workerNode.usage.elu.utilization).toBeUndefined()
1441 expect(workerNode.usage.elu.utilization).toBeGreaterThanOrEqual(0)
1442 expect(workerNode.usage.elu.utilization).toBeLessThanOrEqual(1)
1444 expect(workerNode.strategyData.virtualTaskEndTimestamp).toBeGreaterThan(0)
1447 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1448 pool.workerChoiceStrategyContext.workerChoiceStrategy
1450 ).toEqual(expect.any(Number))
1452 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1453 pool.workerChoiceStrategyContext.workerChoiceStrategy
1454 ).previousWorkerNodeKey
1455 ).toEqual(expect.any(Number))
1456 // We need to clean up the resources after our test
1457 await pool.destroy()
1460 it('Verify FAIR_SHARE strategy internals are resets after setting it', async () => {
1461 const workerChoiceStrategy = WorkerChoiceStrategies.FAIR_SHARE
1462 let pool = new FixedThreadPool(
1464 './tests/worker-files/thread/testWorker.mjs'
1466 for (const workerNode of pool.workerNodes) {
1467 workerNode.strategyData = {
1468 virtualTaskEndTimestamp: performance.now()
1471 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
1472 for (const workerNode of pool.workerNodes) {
1473 expect(workerNode.strategyData.virtualTaskEndTimestamp).toBeUndefined()
1475 await pool.destroy()
1476 pool = new DynamicThreadPool(
1479 './tests/worker-files/thread/testWorker.mjs'
1481 for (const workerNode of pool.workerNodes) {
1482 workerNode.strategyData = {
1483 virtualTaskEndTimestamp: performance.now()
1486 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
1487 for (const workerNode of pool.workerNodes) {
1488 expect(workerNode.strategyData.virtualTaskEndTimestamp).toBeUndefined()
1490 // We need to clean up the resources after our test
1491 await pool.destroy()
1494 it('Verify WEIGHTED_ROUND_ROBIN strategy default policy', async () => {
1495 const workerChoiceStrategy = WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
1496 let pool = new FixedThreadPool(
1498 './tests/worker-files/thread/testWorker.mjs',
1499 { workerChoiceStrategy }
1501 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
1502 dynamicWorkerUsage: false,
1503 dynamicWorkerReady: true
1505 await pool.destroy()
1506 pool = new DynamicThreadPool(
1509 './tests/worker-files/thread/testWorker.mjs',
1510 { workerChoiceStrategy }
1512 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
1513 dynamicWorkerUsage: false,
1514 dynamicWorkerReady: true
1516 // We need to clean up the resources after our test
1517 await pool.destroy()
1520 it('Verify WEIGHTED_ROUND_ROBIN strategy default tasks statistics requirements', async () => {
1521 const workerChoiceStrategy = WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
1522 let pool = new FixedThreadPool(
1524 './tests/worker-files/thread/testWorker.mjs',
1525 { workerChoiceStrategy }
1528 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
1546 await pool.destroy()
1547 pool = new DynamicThreadPool(
1550 './tests/worker-files/thread/testWorker.mjs',
1551 { workerChoiceStrategy }
1554 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
1572 // We need to clean up the resources after our test
1573 await pool.destroy()
1576 it('Verify WEIGHTED_ROUND_ROBIN strategy can be run in a fixed pool', async () => {
1577 const pool = new FixedThreadPool(
1579 './tests/worker-files/thread/testWorker.mjs',
1580 { workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN }
1582 // TODO: Create a better test to cover `WeightedRoundRobinWorkerChoiceStrategy#choose`
1583 const promises = new Set()
1584 const maxMultiplier = 2
1585 for (let i = 0; i < max * maxMultiplier; i++) {
1586 promises.add(pool.execute())
1588 await Promise.all(promises)
1589 for (const workerNode of pool.workerNodes) {
1590 expect(workerNode.usage).toStrictEqual({
1592 executed: expect.any(Number),
1596 sequentiallyStolen: 0,
1600 runTime: expect.objectContaining({
1601 history: expect.any(CircularArray)
1604 history: new CircularArray()
1608 history: new CircularArray()
1611 history: new CircularArray()
1615 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
1616 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
1619 if (workerNode.usage.runTime.aggregate == null) {
1620 expect(workerNode.usage.runTime.aggregate).toBeUndefined()
1622 expect(workerNode.usage.runTime.aggregate).toBeGreaterThan(0)
1624 if (workerNode.usage.runTime.average == null) {
1625 expect(workerNode.usage.runTime.average).toBeUndefined()
1627 expect(workerNode.usage.runTime.average).toBeGreaterThan(0)
1631 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1632 pool.workerChoiceStrategyContext.workerChoiceStrategy
1636 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1637 pool.workerChoiceStrategyContext.workerChoiceStrategy
1638 ).previousWorkerNodeKey
1639 ).toEqual(expect.any(Number))
1641 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1642 pool.workerChoiceStrategyContext.workerChoiceStrategy
1643 ).workerNodeVirtualTaskRunTime
1644 ).toBeGreaterThanOrEqual(0)
1645 // We need to clean up the resources after our test
1646 await pool.destroy()
1649 it('Verify WEIGHTED_ROUND_ROBIN strategy can be run in a dynamic pool', async () => {
1650 const pool = new DynamicThreadPool(
1653 './tests/worker-files/thread/testWorker.mjs',
1654 { workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN }
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())
1662 await Promise.all(promises)
1663 for (const workerNode of pool.workerNodes) {
1664 expect(workerNode.usage).toStrictEqual({
1666 executed: expect.any(Number),
1670 sequentiallyStolen: 0,
1674 runTime: expect.objectContaining({
1675 history: expect.any(CircularArray)
1678 history: new CircularArray()
1682 history: new CircularArray()
1685 history: new CircularArray()
1689 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
1690 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
1693 if (workerNode.usage.runTime.aggregate == null) {
1694 expect(workerNode.usage.runTime.aggregate).toBeUndefined()
1696 expect(workerNode.usage.runTime.aggregate).toBeGreaterThan(0)
1698 if (workerNode.usage.runTime.average == null) {
1699 expect(workerNode.usage.runTime.average).toBeUndefined()
1701 expect(workerNode.usage.runTime.average).toBeGreaterThan(0)
1705 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1706 pool.workerChoiceStrategyContext.workerChoiceStrategy
1708 ).toEqual(expect.any(Number))
1710 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1711 pool.workerChoiceStrategyContext.workerChoiceStrategy
1712 ).previousWorkerNodeKey
1713 ).toEqual(expect.any(Number))
1715 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1716 pool.workerChoiceStrategyContext.workerChoiceStrategy
1717 ).workerNodeVirtualTaskRunTime
1718 ).toBeGreaterThanOrEqual(0)
1719 // We need to clean up the resources after our test
1720 await pool.destroy()
1723 it('Verify WEIGHTED_ROUND_ROBIN strategy can be run in a dynamic pool with median runtime statistic', async () => {
1724 const pool = new DynamicThreadPool(
1727 './tests/worker-files/thread/testWorker.mjs',
1729 workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN,
1730 workerChoiceStrategyOptions: {
1731 runTime: { median: true }
1735 // TODO: Create a better test to cover `WeightedRoundRobinWorkerChoiceStrategy#choose`
1736 const promises = new Set()
1737 const maxMultiplier = 2
1738 for (let i = 0; i < max * maxMultiplier; i++) {
1739 promises.add(pool.execute())
1741 await Promise.all(promises)
1742 for (const workerNode of pool.workerNodes) {
1743 expect(workerNode.usage).toStrictEqual({
1745 executed: expect.any(Number),
1749 sequentiallyStolen: 0,
1753 runTime: expect.objectContaining({
1754 history: expect.any(CircularArray)
1757 history: new CircularArray()
1761 history: new CircularArray()
1764 history: new CircularArray()
1768 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
1769 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
1772 if (workerNode.usage.runTime.aggregate == null) {
1773 expect(workerNode.usage.runTime.aggregate).toBeUndefined()
1775 expect(workerNode.usage.runTime.aggregate).toBeGreaterThan(0)
1777 if (workerNode.usage.runTime.median == null) {
1778 expect(workerNode.usage.runTime.median).toBeUndefined()
1780 expect(workerNode.usage.runTime.median).toBeGreaterThan(0)
1784 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1785 pool.workerChoiceStrategyContext.workerChoiceStrategy
1787 ).toEqual(expect.any(Number))
1789 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1790 pool.workerChoiceStrategyContext.workerChoiceStrategy
1791 ).previousWorkerNodeKey
1792 ).toEqual(expect.any(Number))
1794 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1795 pool.workerChoiceStrategyContext.workerChoiceStrategy
1796 ).workerNodeVirtualTaskRunTime
1797 ).toBeGreaterThanOrEqual(0)
1798 // We need to clean up the resources after our test
1799 await pool.destroy()
1802 it('Verify WEIGHTED_ROUND_ROBIN strategy internals are resets after setting it', async () => {
1803 const workerChoiceStrategy = WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
1804 let pool = new FixedThreadPool(
1806 './tests/worker-files/thread/testWorker.mjs'
1809 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1810 workerChoiceStrategy
1814 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1815 workerChoiceStrategy
1816 ).previousWorkerNodeKey
1819 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1820 workerChoiceStrategy
1821 ).workerNodeVirtualTaskRunTime
1823 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
1825 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1826 pool.workerChoiceStrategyContext.workerChoiceStrategy
1830 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1831 pool.workerChoiceStrategyContext.workerChoiceStrategy
1832 ).previousWorkerNodeKey
1835 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1836 pool.workerChoiceStrategyContext.workerChoiceStrategy
1837 ).workerNodeVirtualTaskRunTime
1839 await pool.destroy()
1840 pool = new DynamicThreadPool(
1843 './tests/worker-files/thread/testWorker.mjs'
1846 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1847 workerChoiceStrategy
1851 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1852 workerChoiceStrategy
1853 ).previousWorkerNodeKey
1856 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1857 workerChoiceStrategy
1858 ).workerNodeVirtualTaskRunTime
1860 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
1862 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1863 pool.workerChoiceStrategyContext.workerChoiceStrategy
1867 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1868 pool.workerChoiceStrategyContext.workerChoiceStrategy
1869 ).previousWorkerNodeKey
1872 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1873 pool.workerChoiceStrategyContext.workerChoiceStrategy
1874 ).workerNodeVirtualTaskRunTime
1876 // We need to clean up the resources after our test
1877 await pool.destroy()
1880 it('Verify INTERLEAVED_WEIGHTED_ROUND_ROBIN strategy default policy', async () => {
1881 const workerChoiceStrategy =
1882 WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
1883 let pool = new FixedThreadPool(
1885 './tests/worker-files/thread/testWorker.mjs',
1886 { workerChoiceStrategy }
1888 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
1889 dynamicWorkerUsage: false,
1890 dynamicWorkerReady: true
1892 await pool.destroy()
1893 pool = new DynamicThreadPool(
1896 './tests/worker-files/thread/testWorker.mjs',
1897 { workerChoiceStrategy }
1899 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
1900 dynamicWorkerUsage: false,
1901 dynamicWorkerReady: true
1903 // We need to clean up the resources after our test
1904 await pool.destroy()
1907 it('Verify INTERLEAVED_WEIGHTED_ROUND_ROBIN strategy default tasks statistics requirements', async () => {
1908 const workerChoiceStrategy =
1909 WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
1910 let pool = new FixedThreadPool(
1912 './tests/worker-files/thread/testWorker.mjs',
1913 { workerChoiceStrategy }
1916 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
1934 await pool.destroy()
1935 pool = new DynamicThreadPool(
1938 './tests/worker-files/thread/testWorker.mjs',
1939 { workerChoiceStrategy }
1942 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
1960 // We need to clean up the resources after our test
1961 await pool.destroy()
1964 it('Verify INTERLEAVED_WEIGHTED_ROUND_ROBIN strategy can be run in a fixed pool', async () => {
1965 const pool = new FixedThreadPool(
1967 './tests/worker-files/thread/testWorker.mjs',
1969 workerChoiceStrategy:
1970 WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
1973 // TODO: Create a better test to cover `InterleavedWeightedRoundRobinWorkerChoiceStrategy#choose`
1974 const promises = new Set()
1975 const maxMultiplier = 2
1976 for (let i = 0; i < max * maxMultiplier; i++) {
1977 promises.add(pool.execute())
1979 await Promise.all(promises)
1980 for (const workerNode of pool.workerNodes) {
1981 expect(workerNode.usage).toStrictEqual({
1983 executed: expect.any(Number),
1987 sequentiallyStolen: 0,
1991 runTime: expect.objectContaining({
1992 history: expect.any(CircularArray)
1995 history: new CircularArray()
1999 history: new CircularArray()
2002 history: new CircularArray()
2006 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
2007 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
2012 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2013 pool.workerChoiceStrategyContext.workerChoiceStrategy
2017 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2018 pool.workerChoiceStrategyContext.workerChoiceStrategy
2022 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2023 pool.workerChoiceStrategyContext.workerChoiceStrategy
2027 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2028 pool.workerChoiceStrategyContext.workerChoiceStrategy
2029 ).previousWorkerNodeKey
2030 ).toEqual(expect.any(Number))
2032 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2033 pool.workerChoiceStrategyContext.workerChoiceStrategy
2034 ).roundWeights.length
2036 // We need to clean up the resources after our test
2037 await pool.destroy()
2040 it('Verify INTERLEAVED_WEIGHTED_ROUND_ROBIN strategy can be run in a dynamic pool', async () => {
2041 const pool = new DynamicThreadPool(
2044 './tests/worker-files/thread/testWorker.mjs',
2046 workerChoiceStrategy:
2047 WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
2050 // TODO: Create a better test to cover `InterleavedWeightedRoundRobinWorkerChoiceStrategy#choose`
2051 const promises = new Set()
2052 const maxMultiplier = 2
2053 for (let i = 0; i < max * maxMultiplier; i++) {
2054 promises.add(pool.execute())
2056 await Promise.all(promises)
2057 for (const workerNode of pool.workerNodes) {
2058 expect(workerNode.usage).toStrictEqual({
2060 executed: expect.any(Number),
2064 sequentiallyStolen: 0,
2068 runTime: expect.objectContaining({
2069 history: expect.any(CircularArray)
2072 history: new CircularArray()
2076 history: new CircularArray()
2079 history: new CircularArray()
2083 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
2084 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
2089 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2090 pool.workerChoiceStrategyContext.workerChoiceStrategy
2094 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2095 pool.workerChoiceStrategyContext.workerChoiceStrategy
2099 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2100 pool.workerChoiceStrategyContext.workerChoiceStrategy
2104 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2105 pool.workerChoiceStrategyContext.workerChoiceStrategy
2106 ).previousWorkerNodeKey
2107 ).toEqual(expect.any(Number))
2109 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2110 pool.workerChoiceStrategyContext.workerChoiceStrategy
2111 ).roundWeights.length
2113 // We need to clean up the resources after our test
2114 await pool.destroy()
2117 it('Verify INTERLEAVED_WEIGHTED_ROUND_ROBIN strategy internals are resets after setting it', async () => {
2118 const workerChoiceStrategy =
2119 WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
2120 let pool = new FixedThreadPool(
2122 './tests/worker-files/thread/testWorker.mjs'
2125 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2126 workerChoiceStrategy
2130 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2131 workerChoiceStrategy
2135 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2136 workerChoiceStrategy
2140 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2141 workerChoiceStrategy
2142 ).previousWorkerNodeKey
2145 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2146 workerChoiceStrategy
2149 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
2151 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2152 pool.workerChoiceStrategyContext.workerChoiceStrategy
2156 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2157 pool.workerChoiceStrategyContext.workerChoiceStrategy
2161 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2162 pool.workerChoiceStrategyContext.workerChoiceStrategy
2166 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2167 pool.workerChoiceStrategyContext.workerChoiceStrategy
2168 ).previousWorkerNodeKey
2171 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2172 pool.workerChoiceStrategyContext.workerChoiceStrategy
2173 ).roundWeights.length
2175 await pool.destroy()
2176 pool = new DynamicThreadPool(
2179 './tests/worker-files/thread/testWorker.mjs'
2182 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2183 workerChoiceStrategy
2187 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2188 workerChoiceStrategy
2192 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2193 workerChoiceStrategy
2197 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2198 workerChoiceStrategy
2199 ).previousWorkerNodeKey
2202 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2203 workerChoiceStrategy
2206 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
2208 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2209 pool.workerChoiceStrategyContext.workerChoiceStrategy
2213 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2214 pool.workerChoiceStrategyContext.workerChoiceStrategy
2218 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2219 pool.workerChoiceStrategyContext.workerChoiceStrategy
2223 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2224 pool.workerChoiceStrategyContext.workerChoiceStrategy
2225 ).previousWorkerNodeKey
2228 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2229 pool.workerChoiceStrategyContext.workerChoiceStrategy
2230 ).roundWeights.length
2232 // We need to clean up the resources after our test
2233 await pool.destroy()
2236 it('Verify unknown strategy throw error', () => {
2239 new DynamicThreadPool(
2242 './tests/worker-files/thread/testWorker.mjs',
2243 { workerChoiceStrategy: 'UNKNOWN_STRATEGY' }
2245 ).toThrow("Invalid worker choice strategy 'UNKNOWN_STRATEGY'")