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'
58 pool
.setWorkerChoiceStrategy(workerChoiceStrategy
)
59 expect(pool
.opts
.workerChoiceStrategy
).toBe(workerChoiceStrategy
)
60 expect(pool
.workerChoiceStrategyContext
.workerChoiceStrategy
).toBe(
67 it('Verify available strategies default internals at pool creation', async () => {
68 const pool
= new FixedThreadPool(
70 './tests/worker-files/thread/testWorker.js'
72 for (const workerChoiceStrategy
of Object
.values(WorkerChoiceStrategies
)) {
73 if (workerChoiceStrategy
=== WorkerChoiceStrategies
.ROUND_ROBIN
) {
75 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
.get(
79 } else if (workerChoiceStrategy
=== WorkerChoiceStrategies
.FAIR_SHARE
) {
80 for (const workerNodeKey
of pool
.workerChoiceStrategyContext
.workerChoiceStrategies
81 .get(workerChoiceStrategy
)
82 .workerLastVirtualTaskTimestamp
.keys()) {
84 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
85 .get(workerChoiceStrategy
)
86 .workerLastVirtualTaskTimestamp
.get(workerNodeKey
).start
89 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
90 .get(workerChoiceStrategy
)
91 .workerLastVirtualTaskTimestamp
.get(workerNodeKey
).end
95 workerChoiceStrategy
=== WorkerChoiceStrategies
.WEIGHTED_ROUND_ROBIN
98 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
.get(
100 ).currentWorkerNodeId
103 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
.get(
105 ).defaultWorkerWeight
107 for (const workerNodeKey
of pool
.workerChoiceStrategyContext
.workerChoiceStrategies
108 .get(workerChoiceStrategy
)
109 .workersTaskRunTime
.keys()) {
111 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
112 .get(workerChoiceStrategy
)
113 .workersTaskRunTime
.get(workerNodeKey
).weight
116 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
117 .get(workerChoiceStrategy
)
118 .workersTaskRunTime
.get(workerNodeKey
).runTime
126 it('Verify ROUND_ROBIN strategy default tasks usage statistics requirements', async () => {
127 const workerChoiceStrategy
= WorkerChoiceStrategies
.ROUND_ROBIN
128 let pool
= new FixedThreadPool(
130 './tests/worker-files/thread/testWorker.js',
131 { workerChoiceStrategy
}
134 pool
.workerChoiceStrategyContext
.getRequiredStatistics().runTime
137 pool
.workerChoiceStrategyContext
.getRequiredStatistics().avgRunTime
140 pool
.workerChoiceStrategyContext
.getRequiredStatistics().medRunTime
143 pool
= new DynamicThreadPool(
146 './tests/worker-files/thread/testWorker.js',
147 { workerChoiceStrategy
}
150 pool
.workerChoiceStrategyContext
.getRequiredStatistics().runTime
153 pool
.workerChoiceStrategyContext
.getRequiredStatistics().avgRunTime
156 pool
.workerChoiceStrategyContext
.getRequiredStatistics().medRunTime
158 // We need to clean up the resources after our test
162 it('Verify ROUND_ROBIN strategy can be run in a fixed pool', async () => {
163 const pool
= new FixedThreadPool(
165 './tests/worker-files/thread/testWorker.js',
166 { workerChoiceStrategy
: WorkerChoiceStrategies
.ROUND_ROBIN
}
168 // TODO: Create a better test to cover `RoundRobinWorkerChoiceStrategy#choose`
170 for (let i
= 0; i
< max
* 2; i
++) {
171 promises
.push(pool
.execute())
173 await Promise
.all(promises
)
174 // We need to clean up the resources after our test
178 it('Verify ROUND_ROBIN strategy can be run in a dynamic pool', async () => {
179 const pool
= new DynamicThreadPool(
182 './tests/worker-files/thread/testWorker.js',
183 { workerChoiceStrategy
: WorkerChoiceStrategies
.ROUND_ROBIN
}
185 // TODO: Create a better test to cover `RoundRobinWorkerChoiceStrategy#choose`
187 for (let i
= 0; i
< max
* 2; i
++) {
188 promises
.push(pool
.execute())
190 await Promise
.all(promises
)
191 // We need to clean up the resources after our test
195 it('Verify ROUND_ROBIN strategy runtime behavior', async () => {
196 const workerChoiceStrategy
= WorkerChoiceStrategies
.ROUND_ROBIN
197 let pool
= new FixedClusterPool(
199 './tests/worker-files/cluster/testWorker.js',
200 { workerChoiceStrategy
}
202 let results
= new Set()
203 for (let i
= 0; i
< max
; i
++) {
204 results
.add(pool
.chooseWorkerNode()[1].worker
.id
)
206 expect(results
.size
).toBe(max
)
208 pool
= new FixedThreadPool(
210 './tests/worker-files/thread/testWorker.js',
211 { workerChoiceStrategy
}
214 for (let i
= 0; i
< max
; i
++) {
215 results
.add(pool
.chooseWorkerNode()[1].worker
.threadId
)
217 expect(results
.size
).toBe(max
)
221 it('Verify ROUND_ROBIN strategy internals are resets after setting it', async () => {
222 const workerChoiceStrategy
= WorkerChoiceStrategies
.ROUND_ROBIN
223 let pool
= new FixedThreadPool(
225 './tests/worker-files/thread/testWorker.js',
226 { workerChoiceStrategy
: WorkerChoiceStrategies
.WEIGHTED_ROUND_ROBIN
}
229 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
.get(
233 pool
.setWorkerChoiceStrategy(workerChoiceStrategy
)
235 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
.get(
236 pool
.workerChoiceStrategyContext
.workerChoiceStrategy
240 pool
= new DynamicThreadPool(
243 './tests/worker-files/thread/testWorker.js',
244 { workerChoiceStrategy
: WorkerChoiceStrategies
.WEIGHTED_ROUND_ROBIN
}
247 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
.get(
251 pool
.setWorkerChoiceStrategy(workerChoiceStrategy
)
253 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
.get(
254 pool
.workerChoiceStrategyContext
.workerChoiceStrategy
257 // We need to clean up the resources after our test
261 it('Verify LESS_USED strategy default tasks usage statistics requirements', async () => {
262 const workerChoiceStrategy
= WorkerChoiceStrategies
.LESS_USED
263 let pool
= new FixedThreadPool(
265 './tests/worker-files/thread/testWorker.js',
266 { workerChoiceStrategy
}
269 pool
.workerChoiceStrategyContext
.getRequiredStatistics().runTime
272 pool
.workerChoiceStrategyContext
.getRequiredStatistics().avgRunTime
275 pool
.workerChoiceStrategyContext
.getRequiredStatistics().medRunTime
278 pool
= new DynamicThreadPool(
281 './tests/worker-files/thread/testWorker.js',
282 { workerChoiceStrategy
}
285 pool
.workerChoiceStrategyContext
.getRequiredStatistics().runTime
288 pool
.workerChoiceStrategyContext
.getRequiredStatistics().avgRunTime
291 pool
.workerChoiceStrategyContext
.getRequiredStatistics().medRunTime
293 // We need to clean up the resources after our test
297 it('Verify LESS_USED strategy can be run in a fixed pool', async () => {
298 const pool
= new FixedThreadPool(
300 './tests/worker-files/thread/testWorker.js',
301 { workerChoiceStrategy
: WorkerChoiceStrategies
.LESS_USED
}
303 // TODO: Create a better test to cover `LessUsedWorkerChoiceStrategy#choose`
305 for (let i
= 0; i
< max
* 2; i
++) {
306 promises
.push(pool
.execute())
308 await Promise
.all(promises
)
309 // We need to clean up the resources after our test
313 it('Verify LESS_USED strategy can be run in a dynamic pool', async () => {
314 const pool
= new DynamicThreadPool(
317 './tests/worker-files/thread/testWorker.js',
318 { workerChoiceStrategy
: WorkerChoiceStrategies
.LESS_USED
}
320 // TODO: Create a better test to cover `LessUsedWorkerChoiceStrategy#choose`
322 for (let i
= 0; i
< max
* 2; i
++) {
323 promises
.push(pool
.execute())
325 await Promise
.all(promises
)
326 // We need to clean up the resources after our test
330 it('Verify LESS_BUSY strategy default tasks usage statistics requirements', async () => {
331 const workerChoiceStrategy
= WorkerChoiceStrategies
.LESS_BUSY
332 let pool
= new FixedThreadPool(
334 './tests/worker-files/thread/testWorker.js',
335 { workerChoiceStrategy
}
338 pool
.workerChoiceStrategyContext
.getRequiredStatistics().runTime
341 pool
.workerChoiceStrategyContext
.getRequiredStatistics().avgRunTime
344 pool
.workerChoiceStrategyContext
.getRequiredStatistics().medRunTime
347 pool
= new DynamicThreadPool(
350 './tests/worker-files/thread/testWorker.js',
351 { workerChoiceStrategy
}
354 pool
.workerChoiceStrategyContext
.getRequiredStatistics().runTime
357 pool
.workerChoiceStrategyContext
.getRequiredStatistics().avgRunTime
360 pool
.workerChoiceStrategyContext
.getRequiredStatistics().medRunTime
362 // We need to clean up the resources after our test
366 it('Verify LESS_BUSY strategy can be run in a fixed pool', async () => {
367 const pool
= new FixedThreadPool(
369 './tests/worker-files/thread/testWorker.js',
370 { workerChoiceStrategy
: WorkerChoiceStrategies
.LESS_BUSY
}
372 // TODO: Create a better test to cover `LessBusyWorkerChoiceStrategy#choose`
374 for (let i
= 0; i
< max
* 2; i
++) {
375 promises
.push(pool
.execute())
377 await Promise
.all(promises
)
378 // We need to clean up the resources after our test
382 it('Verify LESS_BUSY strategy can be run in a dynamic pool', async () => {
383 const pool
= new DynamicThreadPool(
386 './tests/worker-files/thread/testWorker.js',
387 { workerChoiceStrategy
: WorkerChoiceStrategies
.LESS_BUSY
}
389 // TODO: Create a better test to cover `LessBusyWorkerChoiceStrategy#choose`
391 for (let i
= 0; i
< max
* 2; i
++) {
392 promises
.push(pool
.execute())
394 await Promise
.all(promises
)
395 // We need to clean up the resources after our test
399 it('Verify FAIR_SHARE strategy default tasks usage statistics requirements', async () => {
400 const workerChoiceStrategy
= WorkerChoiceStrategies
.FAIR_SHARE
401 let pool
= new FixedThreadPool(
403 './tests/worker-files/thread/testWorker.js',
404 { workerChoiceStrategy
}
407 pool
.workerChoiceStrategyContext
.getRequiredStatistics().runTime
410 pool
.workerChoiceStrategyContext
.getRequiredStatistics().avgRunTime
413 pool
.workerChoiceStrategyContext
.getRequiredStatistics().medRunTime
416 pool
= new DynamicThreadPool(
419 './tests/worker-files/thread/testWorker.js',
420 { workerChoiceStrategy
}
423 pool
.workerChoiceStrategyContext
.getRequiredStatistics().runTime
426 pool
.workerChoiceStrategyContext
.getRequiredStatistics().avgRunTime
429 pool
.workerChoiceStrategyContext
.getRequiredStatistics().medRunTime
431 // We need to clean up the resources after our test
435 it('Verify FAIR_SHARE strategy can be run in a fixed pool', async () => {
436 const pool
= new FixedThreadPool(
438 './tests/worker-files/thread/testWorker.js',
439 { workerChoiceStrategy
: WorkerChoiceStrategies
.FAIR_SHARE
}
441 // TODO: Create a better test to cover `FairShareChoiceStrategy#choose`
443 for (let i
= 0; i
< max
* 2; i
++) {
444 promises
.push(pool
.execute())
446 await Promise
.all(promises
)
448 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
.get(
449 pool
.workerChoiceStrategyContext
.workerChoiceStrategy
450 ).workerLastVirtualTaskTimestamp
.size
451 ).toBe(pool
.workerNodes
.length
)
452 // We need to clean up the resources after our test
456 it('Verify FAIR_SHARE strategy can be run in a dynamic pool', async () => {
457 const pool
= new DynamicThreadPool(
460 './tests/worker-files/thread/testWorker.js',
461 { workerChoiceStrategy
: WorkerChoiceStrategies
.FAIR_SHARE
}
463 // TODO: Create a better test to cover `FairShareChoiceStrategy#choose`
465 const maxMultiplier
= 2
466 for (let i
= 0; i
< max
* maxMultiplier
; i
++) {
467 promises
.push(pool
.execute())
469 await Promise
.all(promises
)
470 // if (process.platform !== 'win32') {
472 // pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
473 // pool.workerChoiceStrategyContext.workerChoiceStrategy
474 // ).workerLastVirtualTaskTimestamp.size
475 // ).toBe(pool.workerNodes.length)
477 // We need to clean up the resources after our test
481 it('Verify FAIR_SHARE strategy internals are resets after setting it', async () => {
482 const workerChoiceStrategy
= WorkerChoiceStrategies
.FAIR_SHARE
483 let pool
= new FixedThreadPool(
485 './tests/worker-files/thread/testWorker.js'
488 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
.get(
490 ).workerLastVirtualTaskTimestamp
492 pool
.setWorkerChoiceStrategy(workerChoiceStrategy
)
493 for (const workerNodeKey
of pool
.workerChoiceStrategyContext
.workerChoiceStrategies
494 .get(pool
.workerChoiceStrategyContext
.workerChoiceStrategy
)
495 .workerLastVirtualTaskTimestamp
.keys()) {
497 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
498 .get(pool
.workerChoiceStrategyContext
.workerChoiceStrategy
)
499 .workerLastVirtualTaskTimestamp
.get(workerNodeKey
).start
502 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
503 .get(pool
.workerChoiceStrategyContext
.workerChoiceStrategy
)
504 .workerLastVirtualTaskTimestamp
.get(workerNodeKey
).end
508 pool
= new DynamicThreadPool(
511 './tests/worker-files/thread/testWorker.js'
514 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
.get(
516 ).workerLastVirtualTaskTimestamp
518 pool
.setWorkerChoiceStrategy(workerChoiceStrategy
)
519 for (const workerNodeKey
of pool
.workerChoiceStrategyContext
.workerChoiceStrategies
520 .get(pool
.workerChoiceStrategyContext
.workerChoiceStrategy
)
521 .workerLastVirtualTaskTimestamp
.keys()) {
523 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
524 .get(pool
.workerChoiceStrategyContext
.workerChoiceStrategy
)
525 .workerLastVirtualTaskTimestamp
.get(workerNodeKey
).start
528 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
529 .get(pool
.workerChoiceStrategyContext
.workerChoiceStrategy
)
530 .workerLastVirtualTaskTimestamp
.get(workerNodeKey
).end
533 // We need to clean up the resources after our test
537 it('Verify WEIGHTED_ROUND_ROBIN strategy default tasks usage statistics requirements', async () => {
538 const workerChoiceStrategy
= WorkerChoiceStrategies
.WEIGHTED_ROUND_ROBIN
539 let pool
= new FixedThreadPool(
541 './tests/worker-files/thread/testWorker.js',
542 { workerChoiceStrategy
}
545 pool
.workerChoiceStrategyContext
.getRequiredStatistics().runTime
548 pool
.workerChoiceStrategyContext
.getRequiredStatistics().avgRunTime
551 pool
.workerChoiceStrategyContext
.getRequiredStatistics().medRunTime
554 pool
= new DynamicThreadPool(
557 './tests/worker-files/thread/testWorker.js',
558 { workerChoiceStrategy
}
561 pool
.workerChoiceStrategyContext
.getRequiredStatistics().runTime
564 pool
.workerChoiceStrategyContext
.getRequiredStatistics().avgRunTime
567 pool
.workerChoiceStrategyContext
.getRequiredStatistics().medRunTime
569 // We need to clean up the resources after our test
573 it('Verify WEIGHTED_ROUND_ROBIN strategy can be run in a fixed pool', async () => {
574 const pool
= new FixedThreadPool(
576 './tests/worker-files/thread/testWorker.js',
577 { workerChoiceStrategy
: WorkerChoiceStrategies
.WEIGHTED_ROUND_ROBIN
}
579 // TODO: Create a better test to cover `WeightedRoundRobinWorkerChoiceStrategy#choose`
581 for (let i
= 0; i
< max
* 2; i
++) {
582 promises
.push(pool
.execute())
584 await Promise
.all(promises
)
586 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
.get(
587 pool
.workerChoiceStrategyContext
.workerChoiceStrategy
588 ).workersTaskRunTime
.size
589 ).toBe(pool
.workerNodes
.length
)
590 // We need to clean up the resources after our test
594 it('Verify WEIGHTED_ROUND_ROBIN strategy can be run in a dynamic pool', async () => {
595 const pool
= new DynamicThreadPool(
598 './tests/worker-files/thread/testWorker.js',
599 { workerChoiceStrategy
: WorkerChoiceStrategies
.WEIGHTED_ROUND_ROBIN
}
601 // TODO: Create a better test to cover `WeightedRoundRobinWorkerChoiceStrategy#choose`
603 const maxMultiplier
=
604 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
.get(
605 pool
.workerChoiceStrategyContext
.workerChoiceStrategy
606 ).defaultWorkerWeight
* 50
607 for (let i
= 0; i
< max
* maxMultiplier
; i
++) {
608 promises
.push(pool
.execute())
610 await Promise
.all(promises
)
611 if (process
.platform
!== 'win32') {
613 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
.get(
614 pool
.workerChoiceStrategyContext
.workerChoiceStrategy
615 ).workersTaskRunTime
.size
616 ).toBe(pool
.workerNodes
.length
)
618 // We need to clean up the resources after our test
622 it('Verify WEIGHTED_ROUND_ROBIN strategy internals are resets after setting it', async () => {
623 const workerChoiceStrategy
= WorkerChoiceStrategies
.WEIGHTED_ROUND_ROBIN
624 let pool
= new FixedThreadPool(
626 './tests/worker-files/thread/testWorker.js'
629 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
.get(
631 ).currentWorkerNodeId
634 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
.get(
636 ).defaultWorkerWeight
639 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
.get(
643 pool
.setWorkerChoiceStrategy(workerChoiceStrategy
)
645 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
.get(
646 pool
.workerChoiceStrategyContext
.workerChoiceStrategy
647 ).currentWorkerNodeId
650 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
.get(
651 pool
.workerChoiceStrategyContext
.workerChoiceStrategy
652 ).defaultWorkerWeight
654 for (const workerNodeKey
of pool
.workerChoiceStrategyContext
.workerChoiceStrategies
655 .get(pool
.workerChoiceStrategyContext
.workerChoiceStrategy
)
656 .workersTaskRunTime
.keys()) {
658 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
659 .get(pool
.workerChoiceStrategyContext
.workerChoiceStrategy
)
660 .workersTaskRunTime
.get(workerNodeKey
).runTime
664 pool
= new DynamicThreadPool(
667 './tests/worker-files/thread/testWorker.js'
670 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
.get(
672 ).currentWorkerNodeId
675 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
.get(
677 ).defaultWorkerWeight
680 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
.get(
684 pool
.setWorkerChoiceStrategy(workerChoiceStrategy
)
686 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
.get(
687 pool
.workerChoiceStrategyContext
.workerChoiceStrategy
688 ).currentWorkerNodeId
691 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
.get(
692 pool
.workerChoiceStrategyContext
.workerChoiceStrategy
693 ).defaultWorkerWeight
695 for (const workerNodeKey
of pool
.workerChoiceStrategyContext
.workerChoiceStrategies
696 .get(pool
.workerChoiceStrategyContext
.workerChoiceStrategy
)
697 .workersTaskRunTime
.keys()) {
699 pool
.workerChoiceStrategyContext
.workerChoiceStrategies
700 .get(pool
.workerChoiceStrategyContext
.workerChoiceStrategy
)
701 .workersTaskRunTime
.get(workerNodeKey
).runTime
704 // We need to clean up the resources after our test
708 it('Verify unknown strategies throw error', () => {
711 new DynamicThreadPool(
714 './tests/worker-files/thread/testWorker.js',
715 { workerChoiceStrategy
: 'UNKNOWN_STRATEGY' }
718 new Error("Invalid worker choice strategy 'UNKNOWN_STRATEGY'")