1 const { expect
} = require('expect')
3 WorkerChoiceStrategies
,
7 } = require('../../../lib/index')
9 describe('Selection strategies test suite', () => {
13 it('Verify that WorkerChoiceStrategies enumeration provides string values', () => {
14 expect(WorkerChoiceStrategies
.ROUND_ROBIN
).toBe('ROUND_ROBIN')
15 expect(WorkerChoiceStrategies
.LESS_USED
).toBe('LESS_USED')
16 expect(WorkerChoiceStrategies
.LESS_BUSY
).toBe('LESS_BUSY')
17 expect(WorkerChoiceStrategies
.FAIR_SHARE
).toBe('FAIR_SHARE')
18 expect(WorkerChoiceStrategies
.WEIGHTED_ROUND_ROBIN
).toBe(
19 'WEIGHTED_ROUND_ROBIN'
23 it('Verify ROUND_ROBIN strategy is the default at pool creation', async () => {
24 const pool
= new DynamicThreadPool(
27 './tests/worker-files/thread/testWorker.js'
29 expect(pool
.opts
.workerChoiceStrategy
).toBe(
30 WorkerChoiceStrategies
.ROUND_ROBIN
32 // We need to clean up the resources after our test
36 it('Verify available strategies are taken at pool creation', async () => {
37 for (const workerChoiceStrategy
of Object
.values(WorkerChoiceStrategies
)) {
38 const pool
= new FixedThreadPool(
40 './tests/worker-files/thread/testWorker.js',
41 { workerChoiceStrategy
}
43 expect(pool
.opts
.workerChoiceStrategy
).toBe(workerChoiceStrategy
)
44 expect(pool
.workerChoiceStrategyContext
.workerChoiceStrategy
).toBe(
51 it('Verify available strategies can be set after pool creation', async () => {
52 for (const workerChoiceStrategy
of Object
.values(WorkerChoiceStrategies
)) {
53 const pool
= new DynamicThreadPool(
56 './tests/worker-files/thread/testWorker.js',
57 { workerChoiceStrategy
}
59 pool
.setWorkerChoiceStrategy(workerChoiceStrategy
)
60 expect(pool
.opts
.workerChoiceStrategy
).toBe(workerChoiceStrategy
)
61 expect(pool
.workerChoiceStrategyContext
.workerChoiceStrategy
).toBe(
68 it('Verify available strategies default internals at pool creation', async () => {
69 const pool
= new FixedThreadPool(
71 './tests/worker-files/thread/testWorker.js'
73 for (const workerChoiceStrategy
of Object
.values(WorkerChoiceStrategies
)) {
74 if (workerChoiceStrategy
=== WorkerChoiceStrategies
.ROUND_ROBIN
) {
76 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
.get(
80 } else if (workerChoiceStrategy
=== WorkerChoiceStrategies
.FAIR_SHARE
) {
81 for (const workerNodeKey
of pool
.workerChoiceStrategyContext
.workerChoiceStrategies
82 .get(workerChoiceStrategy
)
83 .workerLastVirtualTaskTimestamp
.keys()) {
85 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
86 .get(workerChoiceStrategy
)
87 .workerLastVirtualTaskTimestamp
.get(workerNodeKey
).start
90 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
91 .get(workerChoiceStrategy
)
92 .workerLastVirtualTaskTimestamp
.get(workerNodeKey
).end
96 workerChoiceStrategy
=== WorkerChoiceStrategies
.WEIGHTED_ROUND_ROBIN
99 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
.get(
101 ).currentWorkerNodeId
104 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
.get(
106 ).defaultWorkerWeight
108 for (const workerNodeKey
of pool
.workerChoiceStrategyContext
.workerChoiceStrategies
109 .get(workerChoiceStrategy
)
110 .workersTaskRunTime
.keys()) {
112 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
113 .get(workerChoiceStrategy
)
114 .workersTaskRunTime
.get(workerNodeKey
).weight
117 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
118 .get(workerChoiceStrategy
)
119 .workersTaskRunTime
.get(workerNodeKey
).runTime
127 it('Verify ROUND_ROBIN strategy default tasks usage statistics requirements', async () => {
128 const workerChoiceStrategy
= WorkerChoiceStrategies
.ROUND_ROBIN
129 let pool
= new FixedThreadPool(
131 './tests/worker-files/thread/testWorker.js',
132 { workerChoiceStrategy
}
135 pool
.workerChoiceStrategyContext
.getRequiredStatistics().runTime
138 pool
.workerChoiceStrategyContext
.getRequiredStatistics().avgRunTime
141 pool
.workerChoiceStrategyContext
.getRequiredStatistics().medRunTime
144 pool
= new DynamicThreadPool(
147 './tests/worker-files/thread/testWorker.js',
148 { workerChoiceStrategy
}
151 pool
.workerChoiceStrategyContext
.getRequiredStatistics().runTime
154 pool
.workerChoiceStrategyContext
.getRequiredStatistics().avgRunTime
157 pool
.workerChoiceStrategyContext
.getRequiredStatistics().medRunTime
159 // We need to clean up the resources after our test
163 it('Verify ROUND_ROBIN strategy can be run in a fixed pool', async () => {
164 const pool
= new FixedThreadPool(
166 './tests/worker-files/thread/testWorker.js',
167 { workerChoiceStrategy
: WorkerChoiceStrategies
.ROUND_ROBIN
}
169 // TODO: Create a better test to cover `RoundRobinWorkerChoiceStrategy#choose`
171 for (let i
= 0; i
< max
* 2; i
++) {
172 promises
.push(pool
.execute())
174 await Promise
.all(promises
)
175 // We need to clean up the resources after our test
179 it('Verify ROUND_ROBIN strategy can be run in a dynamic pool', async () => {
180 const pool
= new DynamicThreadPool(
183 './tests/worker-files/thread/testWorker.js',
184 { workerChoiceStrategy
: WorkerChoiceStrategies
.ROUND_ROBIN
}
186 // TODO: Create a better test to cover `RoundRobinWorkerChoiceStrategy#choose`
188 for (let i
= 0; i
< max
* 2; i
++) {
189 promises
.push(pool
.execute())
191 await Promise
.all(promises
)
192 // We need to clean up the resources after our test
196 it('Verify ROUND_ROBIN strategy runtime behavior', async () => {
197 const workerChoiceStrategy
= WorkerChoiceStrategies
.ROUND_ROBIN
198 let pool
= new FixedClusterPool(
200 './tests/worker-files/cluster/testWorker.js',
201 { workerChoiceStrategy
}
203 let results
= new Set()
204 for (let i
= 0; i
< max
; i
++) {
205 results
.add(pool
.chooseWorkerNode()[1].worker
.id
)
207 expect(results
.size
).toBe(max
)
209 pool
= new FixedThreadPool(
211 './tests/worker-files/thread/testWorker.js',
212 { workerChoiceStrategy
}
215 for (let i
= 0; i
< max
; i
++) {
216 results
.add(pool
.chooseWorkerNode()[1].worker
.threadId
)
218 expect(results
.size
).toBe(max
)
222 it('Verify ROUND_ROBIN strategy internals are resets after setting it', async () => {
223 const workerChoiceStrategy
= WorkerChoiceStrategies
.ROUND_ROBIN
224 let pool
= new FixedThreadPool(
226 './tests/worker-files/thread/testWorker.js',
227 { workerChoiceStrategy
: WorkerChoiceStrategies
.WEIGHTED_ROUND_ROBIN
}
230 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
.get(
234 pool
.setWorkerChoiceStrategy(workerChoiceStrategy
)
236 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
.get(
237 pool
.workerChoiceStrategyContext
.workerChoiceStrategy
241 pool
= new DynamicThreadPool(
244 './tests/worker-files/thread/testWorker.js',
245 { workerChoiceStrategy
: WorkerChoiceStrategies
.WEIGHTED_ROUND_ROBIN
}
248 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
.get(
252 pool
.setWorkerChoiceStrategy(workerChoiceStrategy
)
254 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
.get(
255 pool
.workerChoiceStrategyContext
.workerChoiceStrategy
258 // We need to clean up the resources after our test
262 it('Verify LESS_USED strategy default tasks usage statistics requirements', async () => {
263 const workerChoiceStrategy
= WorkerChoiceStrategies
.LESS_USED
264 let pool
= new FixedThreadPool(
266 './tests/worker-files/thread/testWorker.js',
267 { workerChoiceStrategy
}
270 pool
.workerChoiceStrategyContext
.getRequiredStatistics().runTime
273 pool
.workerChoiceStrategyContext
.getRequiredStatistics().avgRunTime
276 pool
.workerChoiceStrategyContext
.getRequiredStatistics().medRunTime
279 pool
= new DynamicThreadPool(
282 './tests/worker-files/thread/testWorker.js',
283 { workerChoiceStrategy
}
286 pool
.workerChoiceStrategyContext
.getRequiredStatistics().runTime
289 pool
.workerChoiceStrategyContext
.getRequiredStatistics().avgRunTime
292 pool
.workerChoiceStrategyContext
.getRequiredStatistics().medRunTime
294 // We need to clean up the resources after our test
298 it('Verify LESS_USED strategy can be run in a fixed pool', async () => {
299 const pool
= new FixedThreadPool(
301 './tests/worker-files/thread/testWorker.js',
302 { workerChoiceStrategy
: WorkerChoiceStrategies
.LESS_USED
}
304 // TODO: Create a better test to cover `LessUsedWorkerChoiceStrategy#choose`
306 for (let i
= 0; i
< max
* 2; i
++) {
307 promises
.push(pool
.execute())
309 await Promise
.all(promises
)
310 // We need to clean up the resources after our test
314 it('Verify LESS_USED strategy can be run in a dynamic pool', async () => {
315 const pool
= new DynamicThreadPool(
318 './tests/worker-files/thread/testWorker.js',
319 { workerChoiceStrategy
: WorkerChoiceStrategies
.LESS_USED
}
321 // TODO: Create a better test to cover `LessUsedWorkerChoiceStrategy#choose`
323 for (let i
= 0; i
< max
* 2; i
++) {
324 promises
.push(pool
.execute())
326 await Promise
.all(promises
)
327 // We need to clean up the resources after our test
331 it('Verify LESS_BUSY strategy default tasks usage statistics requirements', async () => {
332 const workerChoiceStrategy
= WorkerChoiceStrategies
.LESS_BUSY
333 let pool
= new FixedThreadPool(
335 './tests/worker-files/thread/testWorker.js',
336 { workerChoiceStrategy
}
339 pool
.workerChoiceStrategyContext
.getRequiredStatistics().runTime
342 pool
.workerChoiceStrategyContext
.getRequiredStatistics().avgRunTime
345 pool
.workerChoiceStrategyContext
.getRequiredStatistics().medRunTime
348 pool
= new DynamicThreadPool(
351 './tests/worker-files/thread/testWorker.js',
352 { workerChoiceStrategy
}
355 pool
.workerChoiceStrategyContext
.getRequiredStatistics().runTime
358 pool
.workerChoiceStrategyContext
.getRequiredStatistics().avgRunTime
361 pool
.workerChoiceStrategyContext
.getRequiredStatistics().medRunTime
363 // We need to clean up the resources after our test
367 it('Verify LESS_BUSY strategy can be run in a fixed pool', async () => {
368 const pool
= new FixedThreadPool(
370 './tests/worker-files/thread/testWorker.js',
371 { workerChoiceStrategy
: WorkerChoiceStrategies
.LESS_BUSY
}
373 // TODO: Create a better test to cover `LessBusyWorkerChoiceStrategy#choose`
375 for (let i
= 0; i
< max
* 2; i
++) {
376 promises
.push(pool
.execute())
378 await Promise
.all(promises
)
379 // We need to clean up the resources after our test
383 it('Verify LESS_BUSY strategy can be run in a dynamic pool', async () => {
384 const pool
= new DynamicThreadPool(
387 './tests/worker-files/thread/testWorker.js',
388 { workerChoiceStrategy
: WorkerChoiceStrategies
.LESS_BUSY
}
390 // TODO: Create a better test to cover `LessBusyWorkerChoiceStrategy#choose`
392 for (let i
= 0; i
< max
* 2; i
++) {
393 promises
.push(pool
.execute())
395 await Promise
.all(promises
)
396 // We need to clean up the resources after our test
400 it('Verify FAIR_SHARE strategy default tasks usage statistics requirements', async () => {
401 const workerChoiceStrategy
= WorkerChoiceStrategies
.FAIR_SHARE
402 let pool
= new FixedThreadPool(
404 './tests/worker-files/thread/testWorker.js',
405 { workerChoiceStrategy
}
408 pool
.workerChoiceStrategyContext
.getRequiredStatistics().runTime
411 pool
.workerChoiceStrategyContext
.getRequiredStatistics().avgRunTime
414 pool
.workerChoiceStrategyContext
.getRequiredStatistics().medRunTime
417 pool
= new DynamicThreadPool(
420 './tests/worker-files/thread/testWorker.js',
421 { workerChoiceStrategy
}
424 pool
.workerChoiceStrategyContext
.getRequiredStatistics().runTime
427 pool
.workerChoiceStrategyContext
.getRequiredStatistics().avgRunTime
430 pool
.workerChoiceStrategyContext
.getRequiredStatistics().medRunTime
432 // We need to clean up the resources after our test
436 it('Verify FAIR_SHARE strategy can be run in a fixed pool', async () => {
437 const pool
= new FixedThreadPool(
439 './tests/worker-files/thread/testWorker.js',
440 { workerChoiceStrategy
: WorkerChoiceStrategies
.FAIR_SHARE
}
442 // TODO: Create a better test to cover `FairShareChoiceStrategy#choose`
444 for (let i
= 0; i
< max
* 2; i
++) {
445 promises
.push(pool
.execute())
447 await Promise
.all(promises
)
449 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
.get(
450 pool
.workerChoiceStrategyContext
.workerChoiceStrategy
451 ).workerLastVirtualTaskTimestamp
.size
452 ).toBe(pool
.workerNodes
.length
)
453 // We need to clean up the resources after our test
457 it('Verify FAIR_SHARE strategy can be run in a dynamic pool', async () => {
458 const pool
= new DynamicThreadPool(
461 './tests/worker-files/thread/testWorker.js',
462 { workerChoiceStrategy
: WorkerChoiceStrategies
.FAIR_SHARE
}
464 // TODO: Create a better test to cover `FairShareChoiceStrategy#choose`
466 const maxMultiplier
= 2
467 for (let i
= 0; i
< max
* maxMultiplier
; i
++) {
468 promises
.push(pool
.execute())
470 await Promise
.all(promises
)
471 // if (process.platform !== 'win32') {
473 // pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
474 // pool.workerChoiceStrategyContext.workerChoiceStrategy
475 // ).workerLastVirtualTaskTimestamp.size
476 // ).toBe(pool.workerNodes.length)
478 // We need to clean up the resources after our test
482 it('Verify FAIR_SHARE strategy internals are resets after setting it', async () => {
483 const workerChoiceStrategy
= WorkerChoiceStrategies
.FAIR_SHARE
484 let pool
= new FixedThreadPool(
486 './tests/worker-files/thread/testWorker.js'
489 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
.get(
491 ).workerLastVirtualTaskTimestamp
493 pool
.setWorkerChoiceStrategy(workerChoiceStrategy
)
494 for (const workerNodeKey
of pool
.workerChoiceStrategyContext
.workerChoiceStrategies
495 .get(pool
.workerChoiceStrategyContext
.workerChoiceStrategy
)
496 .workerLastVirtualTaskTimestamp
.keys()) {
498 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
499 .get(pool
.workerChoiceStrategyContext
.workerChoiceStrategy
)
500 .workerLastVirtualTaskTimestamp
.get(workerNodeKey
).start
503 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
504 .get(pool
.workerChoiceStrategyContext
.workerChoiceStrategy
)
505 .workerLastVirtualTaskTimestamp
.get(workerNodeKey
).end
509 pool
= new DynamicThreadPool(
512 './tests/worker-files/thread/testWorker.js'
515 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
.get(
517 ).workerLastVirtualTaskTimestamp
519 pool
.setWorkerChoiceStrategy(workerChoiceStrategy
)
520 for (const workerNodeKey
of pool
.workerChoiceStrategyContext
.workerChoiceStrategies
521 .get(pool
.workerChoiceStrategyContext
.workerChoiceStrategy
)
522 .workerLastVirtualTaskTimestamp
.keys()) {
524 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
525 .get(pool
.workerChoiceStrategyContext
.workerChoiceStrategy
)
526 .workerLastVirtualTaskTimestamp
.get(workerNodeKey
).start
529 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
530 .get(pool
.workerChoiceStrategyContext
.workerChoiceStrategy
)
531 .workerLastVirtualTaskTimestamp
.get(workerNodeKey
).end
534 // We need to clean up the resources after our test
538 it('Verify WEIGHTED_ROUND_ROBIN strategy default tasks usage statistics requirements', async () => {
539 const workerChoiceStrategy
= WorkerChoiceStrategies
.WEIGHTED_ROUND_ROBIN
540 let pool
= new FixedThreadPool(
542 './tests/worker-files/thread/testWorker.js',
543 { workerChoiceStrategy
}
546 pool
.workerChoiceStrategyContext
.getRequiredStatistics().runTime
549 pool
.workerChoiceStrategyContext
.getRequiredStatistics().avgRunTime
552 pool
.workerChoiceStrategyContext
.getRequiredStatistics().medRunTime
555 pool
= new DynamicThreadPool(
558 './tests/worker-files/thread/testWorker.js',
559 { workerChoiceStrategy
}
562 pool
.workerChoiceStrategyContext
.getRequiredStatistics().runTime
565 pool
.workerChoiceStrategyContext
.getRequiredStatistics().avgRunTime
568 pool
.workerChoiceStrategyContext
.getRequiredStatistics().medRunTime
570 // We need to clean up the resources after our test
574 it('Verify WEIGHTED_ROUND_ROBIN strategy can be run in a fixed pool', async () => {
575 const pool
= new FixedThreadPool(
577 './tests/worker-files/thread/testWorker.js',
578 { workerChoiceStrategy
: WorkerChoiceStrategies
.WEIGHTED_ROUND_ROBIN
}
580 // TODO: Create a better test to cover `WeightedRoundRobinWorkerChoiceStrategy#choose`
582 for (let i
= 0; i
< max
* 2; i
++) {
583 promises
.push(pool
.execute())
585 await Promise
.all(promises
)
587 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
.get(
588 pool
.workerChoiceStrategyContext
.workerChoiceStrategy
589 ).workersTaskRunTime
.size
590 ).toBe(pool
.workerNodes
.length
)
591 // We need to clean up the resources after our test
595 it('Verify WEIGHTED_ROUND_ROBIN strategy can be run in a dynamic pool', async () => {
596 const pool
= new DynamicThreadPool(
599 './tests/worker-files/thread/testWorker.js',
600 { workerChoiceStrategy
: WorkerChoiceStrategies
.WEIGHTED_ROUND_ROBIN
}
602 // TODO: Create a better test to cover `WeightedRoundRobinWorkerChoiceStrategy#choose`
604 const maxMultiplier
=
605 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
.get(
606 pool
.workerChoiceStrategyContext
.workerChoiceStrategy
607 ).defaultWorkerWeight
* 50
608 for (let i
= 0; i
< max
* maxMultiplier
; i
++) {
609 promises
.push(pool
.execute())
611 await Promise
.all(promises
)
612 if (process
.platform
!== 'win32') {
614 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
.get(
615 pool
.workerChoiceStrategyContext
.workerChoiceStrategy
616 ).workersTaskRunTime
.size
617 ).toBe(pool
.workerNodes
.length
)
619 // We need to clean up the resources after our test
623 it('Verify WEIGHTED_ROUND_ROBIN strategy internals are resets after setting it', async () => {
624 const workerChoiceStrategy
= WorkerChoiceStrategies
.WEIGHTED_ROUND_ROBIN
625 let pool
= new FixedThreadPool(
627 './tests/worker-files/thread/testWorker.js'
630 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
.get(
632 ).currentWorkerNodeId
635 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
.get(
637 ).defaultWorkerWeight
640 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
.get(
644 pool
.setWorkerChoiceStrategy(workerChoiceStrategy
)
646 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
.get(
647 pool
.workerChoiceStrategyContext
.workerChoiceStrategy
648 ).currentWorkerNodeId
651 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
.get(
652 pool
.workerChoiceStrategyContext
.workerChoiceStrategy
653 ).defaultWorkerWeight
655 for (const workerNodeKey
of pool
.workerChoiceStrategyContext
.workerChoiceStrategies
656 .get(pool
.workerChoiceStrategyContext
.workerChoiceStrategy
)
657 .workersTaskRunTime
.keys()) {
659 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
660 .get(pool
.workerChoiceStrategyContext
.workerChoiceStrategy
)
661 .workersTaskRunTime
.get(workerNodeKey
).runTime
665 pool
= new DynamicThreadPool(
668 './tests/worker-files/thread/testWorker.js'
671 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
.get(
673 ).currentWorkerNodeId
676 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
.get(
678 ).defaultWorkerWeight
681 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
.get(
685 pool
.setWorkerChoiceStrategy(workerChoiceStrategy
)
687 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
.get(
688 pool
.workerChoiceStrategyContext
.workerChoiceStrategy
689 ).currentWorkerNodeId
692 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
.get(
693 pool
.workerChoiceStrategyContext
.workerChoiceStrategy
694 ).defaultWorkerWeight
696 for (const workerNodeKey
of pool
.workerChoiceStrategyContext
.workerChoiceStrategies
697 .get(pool
.workerChoiceStrategyContext
.workerChoiceStrategy
)
698 .workersTaskRunTime
.keys()) {
700 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
701 .get(pool
.workerChoiceStrategyContext
.workerChoiceStrategy
)
702 .workersTaskRunTime
.get(workerNodeKey
).runTime
705 // We need to clean up the resources after our test
709 it('Verify unknown strategies throw error', () => {
712 new DynamicThreadPool(
715 './tests/worker-files/thread/testWorker.js',
716 { workerChoiceStrategy
: 'UNKNOWN_STRATEGY' }
719 new Error("Invalid worker choice strategy 'UNKNOWN_STRATEGY'")