test: fix fair share strategy
[poolifier.git] / tests / pools / selection-strategies / selection-strategies.test.js
1 const { expect } = require('expect')
2 const {
3 WorkerChoiceStrategies,
4 DynamicThreadPool,
5 FixedThreadPool,
6 FixedClusterPool
7 } = require('../../../lib')
8
9 describe('Selection strategies test suite', () => {
10 const min = 0
11 const max = 3
12
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'
20 )
21 })
22
23 it('Verify ROUND_ROBIN strategy is the default at pool creation', async () => {
24 const pool = new DynamicThreadPool(
25 min,
26 max,
27 './tests/worker-files/thread/testWorker.js'
28 )
29 expect(pool.opts.workerChoiceStrategy).toBe(
30 WorkerChoiceStrategies.ROUND_ROBIN
31 )
32 // We need to clean up the resources after our test
33 await pool.destroy()
34 })
35
36 it('Verify available strategies are taken at pool creation', async () => {
37 for (const workerChoiceStrategy of Object.values(WorkerChoiceStrategies)) {
38 const pool = new FixedThreadPool(
39 max,
40 './tests/worker-files/thread/testWorker.js',
41 { workerChoiceStrategy }
42 )
43 expect(pool.opts.workerChoiceStrategy).toBe(workerChoiceStrategy)
44 expect(pool.workerChoiceStrategyContext.workerChoiceStrategy).toBe(
45 workerChoiceStrategy
46 )
47 await pool.destroy()
48 }
49 })
50
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(
54 min,
55 max,
56 './tests/worker-files/thread/testWorker.js'
57 )
58 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
59 expect(pool.opts.workerChoiceStrategy).toBe(workerChoiceStrategy)
60 expect(pool.workerChoiceStrategyContext.workerChoiceStrategy).toBe(
61 workerChoiceStrategy
62 )
63 await pool.destroy()
64 }
65 })
66
67 it('Verify available strategies default internals at pool creation', async () => {
68 const pool = new FixedThreadPool(
69 max,
70 './tests/worker-files/thread/testWorker.js'
71 )
72 for (const workerChoiceStrategy of Object.values(WorkerChoiceStrategies)) {
73 if (workerChoiceStrategy === WorkerChoiceStrategies.ROUND_ROBIN) {
74 expect(
75 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
76 workerChoiceStrategy
77 ).nextWorkerNodeId
78 ).toBe(0)
79 } else if (workerChoiceStrategy === WorkerChoiceStrategies.FAIR_SHARE) {
80 expect(
81 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
82 workerChoiceStrategy
83 ).workersVirtualTaskTimestamp
84 ).toBeInstanceOf(Array)
85 expect(
86 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
87 workerChoiceStrategy
88 ).workersVirtualTaskTimestamp.length
89 ).toBe(0)
90 } else if (
91 workerChoiceStrategy === WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
92 ) {
93 expect(
94 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
95 workerChoiceStrategy
96 ).currentWorkerNodeId
97 ).toBe(0)
98 expect(
99 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
100 workerChoiceStrategy
101 ).defaultWorkerWeight
102 ).toBeGreaterThan(0)
103 expect(
104 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
105 workerChoiceStrategy
106 ).workerVirtualTaskRunTime
107 ).toBe(0)
108 }
109 }
110 await pool.destroy()
111 })
112
113 it('Verify ROUND_ROBIN strategy default tasks usage statistics requirements', async () => {
114 const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN
115 let pool = new FixedThreadPool(
116 max,
117 './tests/worker-files/thread/testWorker.js',
118 { workerChoiceStrategy }
119 )
120 expect(
121 pool.workerChoiceStrategyContext.getRequiredStatistics().runTime
122 ).toBe(false)
123 expect(
124 pool.workerChoiceStrategyContext.getRequiredStatistics().avgRunTime
125 ).toBe(false)
126 expect(
127 pool.workerChoiceStrategyContext.getRequiredStatistics().medRunTime
128 ).toBe(false)
129 await pool.destroy()
130 pool = new DynamicThreadPool(
131 min,
132 max,
133 './tests/worker-files/thread/testWorker.js',
134 { workerChoiceStrategy }
135 )
136 expect(
137 pool.workerChoiceStrategyContext.getRequiredStatistics().runTime
138 ).toBe(false)
139 expect(
140 pool.workerChoiceStrategyContext.getRequiredStatistics().avgRunTime
141 ).toBe(false)
142 expect(
143 pool.workerChoiceStrategyContext.getRequiredStatistics().medRunTime
144 ).toBe(false)
145 // We need to clean up the resources after our test
146 await pool.destroy()
147 })
148
149 it('Verify ROUND_ROBIN strategy can be run in a fixed pool', async () => {
150 const pool = new FixedThreadPool(
151 max,
152 './tests/worker-files/thread/testWorker.js',
153 { workerChoiceStrategy: WorkerChoiceStrategies.ROUND_ROBIN }
154 )
155 // TODO: Create a better test to cover `RoundRobinWorkerChoiceStrategy#choose`
156 const promises = []
157 const maxMultiplier = 2
158 for (let i = 0; i < max * maxMultiplier; i++) {
159 promises.push(pool.execute())
160 }
161 await Promise.all(promises)
162 // We need to clean up the resources after our test
163 await pool.destroy()
164 })
165
166 it('Verify ROUND_ROBIN strategy can be run in a dynamic pool', async () => {
167 const pool = new DynamicThreadPool(
168 min,
169 max,
170 './tests/worker-files/thread/testWorker.js',
171 { workerChoiceStrategy: WorkerChoiceStrategies.ROUND_ROBIN }
172 )
173 // TODO: Create a better test to cover `RoundRobinWorkerChoiceStrategy#choose`
174 const promises = []
175 const maxMultiplier = 2
176 for (let i = 0; i < max * maxMultiplier; i++) {
177 promises.push(pool.execute())
178 }
179 await Promise.all(promises)
180 // We need to clean up the resources after our test
181 await pool.destroy()
182 })
183
184 it('Verify ROUND_ROBIN strategy runtime behavior', async () => {
185 const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN
186 let pool = new FixedClusterPool(
187 max,
188 './tests/worker-files/cluster/testWorker.js',
189 { workerChoiceStrategy }
190 )
191 let results = new Set()
192 for (let i = 0; i < max; i++) {
193 results.add(pool.chooseWorkerNode()[1].worker.id)
194 }
195 expect(results.size).toBe(max)
196 await pool.destroy()
197 pool = new FixedThreadPool(
198 max,
199 './tests/worker-files/thread/testWorker.js',
200 { workerChoiceStrategy }
201 )
202 results = new Set()
203 for (let i = 0; i < max; i++) {
204 results.add(pool.chooseWorkerNode()[1].worker.threadId)
205 }
206 expect(results.size).toBe(max)
207 await pool.destroy()
208 })
209
210 it('Verify ROUND_ROBIN strategy internals are resets after setting it', async () => {
211 const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN
212 let pool = new FixedThreadPool(
213 max,
214 './tests/worker-files/thread/testWorker.js',
215 { workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN }
216 )
217 expect(
218 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
219 workerChoiceStrategy
220 ).nextWorkerNodeId
221 ).toBeDefined()
222 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
223 expect(
224 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
225 pool.workerChoiceStrategyContext.workerChoiceStrategy
226 ).nextWorkerNodeId
227 ).toBe(0)
228 await pool.destroy()
229 pool = new DynamicThreadPool(
230 min,
231 max,
232 './tests/worker-files/thread/testWorker.js',
233 { workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN }
234 )
235 expect(
236 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
237 workerChoiceStrategy
238 ).nextWorkerNodeId
239 ).toBeDefined()
240 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
241 expect(
242 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
243 pool.workerChoiceStrategyContext.workerChoiceStrategy
244 ).nextWorkerNodeId
245 ).toBe(0)
246 // We need to clean up the resources after our test
247 await pool.destroy()
248 })
249
250 it('Verify LESS_USED strategy default tasks usage statistics requirements', async () => {
251 const workerChoiceStrategy = WorkerChoiceStrategies.LESS_USED
252 let pool = new FixedThreadPool(
253 max,
254 './tests/worker-files/thread/testWorker.js',
255 { workerChoiceStrategy }
256 )
257 expect(
258 pool.workerChoiceStrategyContext.getRequiredStatistics().runTime
259 ).toBe(false)
260 expect(
261 pool.workerChoiceStrategyContext.getRequiredStatistics().avgRunTime
262 ).toBe(false)
263 expect(
264 pool.workerChoiceStrategyContext.getRequiredStatistics().medRunTime
265 ).toBe(false)
266 await pool.destroy()
267 pool = new DynamicThreadPool(
268 min,
269 max,
270 './tests/worker-files/thread/testWorker.js',
271 { workerChoiceStrategy }
272 )
273 expect(
274 pool.workerChoiceStrategyContext.getRequiredStatistics().runTime
275 ).toBe(false)
276 expect(
277 pool.workerChoiceStrategyContext.getRequiredStatistics().avgRunTime
278 ).toBe(false)
279 expect(
280 pool.workerChoiceStrategyContext.getRequiredStatistics().medRunTime
281 ).toBe(false)
282 // We need to clean up the resources after our test
283 await pool.destroy()
284 })
285
286 it('Verify LESS_USED strategy can be run in a fixed pool', async () => {
287 const pool = new FixedThreadPool(
288 max,
289 './tests/worker-files/thread/testWorker.js',
290 { workerChoiceStrategy: WorkerChoiceStrategies.LESS_USED }
291 )
292 // TODO: Create a better test to cover `LessUsedWorkerChoiceStrategy#choose`
293 const promises = []
294 const maxMultiplier = 2
295 for (let i = 0; i < max * maxMultiplier; i++) {
296 promises.push(pool.execute())
297 }
298 await Promise.all(promises)
299 // We need to clean up the resources after our test
300 await pool.destroy()
301 })
302
303 it('Verify LESS_USED strategy can be run in a dynamic pool', async () => {
304 const pool = new DynamicThreadPool(
305 min,
306 max,
307 './tests/worker-files/thread/testWorker.js',
308 { workerChoiceStrategy: WorkerChoiceStrategies.LESS_USED }
309 )
310 // TODO: Create a better test to cover `LessUsedWorkerChoiceStrategy#choose`
311 const promises = []
312 const maxMultiplier = 2
313 for (let i = 0; i < max * maxMultiplier; i++) {
314 promises.push(pool.execute())
315 }
316 await Promise.all(promises)
317 // We need to clean up the resources after our test
318 await pool.destroy()
319 })
320
321 it('Verify LESS_BUSY strategy default tasks usage statistics requirements', async () => {
322 const workerChoiceStrategy = WorkerChoiceStrategies.LESS_BUSY
323 let pool = new FixedThreadPool(
324 max,
325 './tests/worker-files/thread/testWorker.js',
326 { workerChoiceStrategy }
327 )
328 expect(
329 pool.workerChoiceStrategyContext.getRequiredStatistics().runTime
330 ).toBe(true)
331 expect(
332 pool.workerChoiceStrategyContext.getRequiredStatistics().avgRunTime
333 ).toBe(false)
334 expect(
335 pool.workerChoiceStrategyContext.getRequiredStatistics().medRunTime
336 ).toBe(false)
337 await pool.destroy()
338 pool = new DynamicThreadPool(
339 min,
340 max,
341 './tests/worker-files/thread/testWorker.js',
342 { workerChoiceStrategy }
343 )
344 expect(
345 pool.workerChoiceStrategyContext.getRequiredStatistics().runTime
346 ).toBe(true)
347 expect(
348 pool.workerChoiceStrategyContext.getRequiredStatistics().avgRunTime
349 ).toBe(false)
350 expect(
351 pool.workerChoiceStrategyContext.getRequiredStatistics().medRunTime
352 ).toBe(false)
353 // We need to clean up the resources after our test
354 await pool.destroy()
355 })
356
357 it('Verify LESS_BUSY strategy can be run in a fixed pool', async () => {
358 const pool = new FixedThreadPool(
359 max,
360 './tests/worker-files/thread/testWorker.js',
361 { workerChoiceStrategy: WorkerChoiceStrategies.LESS_BUSY }
362 )
363 // TODO: Create a better test to cover `LessBusyWorkerChoiceStrategy#choose`
364 const promises = []
365 const maxMultiplier = 2
366 for (let i = 0; i < max * maxMultiplier; i++) {
367 promises.push(pool.execute())
368 }
369 await Promise.all(promises)
370 // We need to clean up the resources after our test
371 await pool.destroy()
372 })
373
374 it('Verify LESS_BUSY strategy can be run in a dynamic pool', async () => {
375 const pool = new DynamicThreadPool(
376 min,
377 max,
378 './tests/worker-files/thread/testWorker.js',
379 { workerChoiceStrategy: WorkerChoiceStrategies.LESS_BUSY }
380 )
381 // TODO: Create a better test to cover `LessBusyWorkerChoiceStrategy#choose`
382 const promises = []
383 const maxMultiplier = 2
384 for (let i = 0; i < max * maxMultiplier; i++) {
385 promises.push(pool.execute())
386 }
387 await Promise.all(promises)
388 // We need to clean up the resources after our test
389 await pool.destroy()
390 })
391
392 it('Verify FAIR_SHARE strategy default tasks usage statistics requirements', async () => {
393 const workerChoiceStrategy = WorkerChoiceStrategies.FAIR_SHARE
394 let pool = new FixedThreadPool(
395 max,
396 './tests/worker-files/thread/testWorker.js',
397 { workerChoiceStrategy }
398 )
399 expect(
400 pool.workerChoiceStrategyContext.getRequiredStatistics().runTime
401 ).toBe(true)
402 expect(
403 pool.workerChoiceStrategyContext.getRequiredStatistics().avgRunTime
404 ).toBe(true)
405 expect(
406 pool.workerChoiceStrategyContext.getRequiredStatistics().medRunTime
407 ).toBe(false)
408 await pool.destroy()
409 pool = new DynamicThreadPool(
410 min,
411 max,
412 './tests/worker-files/thread/testWorker.js',
413 { workerChoiceStrategy }
414 )
415 expect(
416 pool.workerChoiceStrategyContext.getRequiredStatistics().runTime
417 ).toBe(true)
418 expect(
419 pool.workerChoiceStrategyContext.getRequiredStatistics().avgRunTime
420 ).toBe(true)
421 expect(
422 pool.workerChoiceStrategyContext.getRequiredStatistics().medRunTime
423 ).toBe(false)
424 // We need to clean up the resources after our test
425 await pool.destroy()
426 })
427
428 it('Verify FAIR_SHARE strategy can be run in a fixed pool', async () => {
429 const pool = new FixedThreadPool(
430 max,
431 './tests/worker-files/thread/testWorker.js',
432 { workerChoiceStrategy: WorkerChoiceStrategies.FAIR_SHARE }
433 )
434 // TODO: Create a better test to cover `FairShareChoiceStrategy#choose`
435 const promises = []
436 const maxMultiplier = 2
437 for (let i = 0; i < max * maxMultiplier; i++) {
438 promises.push(pool.execute())
439 }
440 await Promise.all(promises)
441 expect(
442 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
443 pool.workerChoiceStrategyContext.workerChoiceStrategy
444 ).workersVirtualTaskTimestamp.length
445 ).toBe(pool.workerNodes.length)
446 // We need to clean up the resources after our test
447 await pool.destroy()
448 })
449
450 it('Verify FAIR_SHARE strategy can be run in a dynamic pool', async () => {
451 const pool = new DynamicThreadPool(
452 min,
453 max,
454 './tests/worker-files/thread/testWorker.js',
455 { workerChoiceStrategy: WorkerChoiceStrategies.FAIR_SHARE }
456 )
457 // TODO: Create a better test to cover `FairShareChoiceStrategy#choose`
458 const promises = []
459 const maxMultiplier = 2
460 for (let i = 0; i < max * maxMultiplier; i++) {
461 promises.push(pool.execute())
462 }
463 await Promise.all(promises)
464 expect(
465 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
466 pool.workerChoiceStrategyContext.workerChoiceStrategy
467 ).workersVirtualTaskTimestamp.length
468 ).toBe(pool.workerNodes.length)
469 // We need to clean up the resources after our test
470 await pool.destroy()
471 })
472
473 it('Verify FAIR_SHARE strategy can be run in a dynamic pool with median run time statistic', async () => {
474 const pool = new DynamicThreadPool(
475 min,
476 max,
477 './tests/worker-files/thread/testWorker.js',
478 {
479 workerChoiceStrategy: WorkerChoiceStrategies.FAIR_SHARE,
480 workerChoiceStrategyOptions: {
481 medRunTime: true
482 }
483 }
484 )
485 // TODO: Create a better test to cover `FairShareChoiceStrategy#choose`
486 const promises = []
487 const maxMultiplier = 2
488 for (let i = 0; i < max * maxMultiplier; i++) {
489 promises.push(pool.execute())
490 }
491 await Promise.all(promises)
492 for (const workerNode of pool.workerNodes) {
493 expect(workerNode.tasksUsage.avgRunTime).toBeDefined()
494 expect(workerNode.tasksUsage.avgRunTime).toBe(0)
495 expect(workerNode.tasksUsage.medRunTime).toBeDefined()
496 expect(workerNode.tasksUsage.medRunTime).toBeGreaterThan(0)
497 }
498 expect(
499 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
500 pool.workerChoiceStrategyContext.workerChoiceStrategy
501 ).workersVirtualTaskTimestamp.length
502 ).toBe(pool.workerNodes.length)
503 // We need to clean up the resources after our test
504 await pool.destroy()
505 })
506
507 it('Verify FAIR_SHARE strategy internals are resets after setting it', async () => {
508 const workerChoiceStrategy = WorkerChoiceStrategies.FAIR_SHARE
509 let pool = new FixedThreadPool(
510 max,
511 './tests/worker-files/thread/testWorker.js'
512 )
513 expect(
514 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
515 workerChoiceStrategy
516 ).workersVirtualTaskTimestamp
517 ).toBeInstanceOf(Array)
518 expect(
519 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
520 workerChoiceStrategy
521 ).workersVirtualTaskTimestamp.length
522 ).toBe(0)
523 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
524 workerChoiceStrategy
525 ).workersVirtualTaskTimestamp[0] = 0
526 expect(
527 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
528 workerChoiceStrategy
529 ).workersVirtualTaskTimestamp.length
530 ).toBe(1)
531 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
532 expect(
533 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
534 workerChoiceStrategy
535 ).workersVirtualTaskTimestamp
536 ).toBeInstanceOf(Array)
537 expect(
538 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
539 workerChoiceStrategy
540 ).workersVirtualTaskTimestamp.length
541 ).toBe(0)
542 await pool.destroy()
543 pool = new DynamicThreadPool(
544 min,
545 max,
546 './tests/worker-files/thread/testWorker.js'
547 )
548 expect(
549 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
550 workerChoiceStrategy
551 ).workersVirtualTaskTimestamp
552 ).toBeInstanceOf(Array)
553 expect(
554 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
555 workerChoiceStrategy
556 ).workersVirtualTaskTimestamp.length
557 ).toBe(0)
558 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
559 workerChoiceStrategy
560 ).workersVirtualTaskTimestamp[0] = 0
561 expect(
562 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
563 workerChoiceStrategy
564 ).workersVirtualTaskTimestamp.length
565 ).toBe(1)
566 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
567 expect(
568 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
569 workerChoiceStrategy
570 ).workersVirtualTaskTimestamp
571 ).toBeInstanceOf(Array)
572 expect(
573 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
574 workerChoiceStrategy
575 ).workersVirtualTaskTimestamp.length
576 ).toBe(0)
577 // We need to clean up the resources after our test
578 await pool.destroy()
579 })
580
581 it('Verify WEIGHTED_ROUND_ROBIN strategy default tasks usage statistics requirements', async () => {
582 const workerChoiceStrategy = WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
583 let pool = new FixedThreadPool(
584 max,
585 './tests/worker-files/thread/testWorker.js',
586 { workerChoiceStrategy }
587 )
588 expect(
589 pool.workerChoiceStrategyContext.getRequiredStatistics().runTime
590 ).toBe(true)
591 expect(
592 pool.workerChoiceStrategyContext.getRequiredStatistics().avgRunTime
593 ).toBe(true)
594 expect(
595 pool.workerChoiceStrategyContext.getRequiredStatistics().medRunTime
596 ).toBe(false)
597 await pool.destroy()
598 pool = new DynamicThreadPool(
599 min,
600 max,
601 './tests/worker-files/thread/testWorker.js',
602 { workerChoiceStrategy }
603 )
604 expect(
605 pool.workerChoiceStrategyContext.getRequiredStatistics().runTime
606 ).toBe(true)
607 expect(
608 pool.workerChoiceStrategyContext.getRequiredStatistics().avgRunTime
609 ).toBe(true)
610 expect(
611 pool.workerChoiceStrategyContext.getRequiredStatistics().medRunTime
612 ).toBe(false)
613 // We need to clean up the resources after our test
614 await pool.destroy()
615 })
616
617 it('Verify WEIGHTED_ROUND_ROBIN strategy can be run in a fixed pool', async () => {
618 const pool = new FixedThreadPool(
619 max,
620 './tests/worker-files/thread/testWorker.js',
621 { workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN }
622 )
623 // TODO: Create a better test to cover `WeightedRoundRobinWorkerChoiceStrategy#choose`
624 const promises = []
625 const maxMultiplier = 2
626 for (let i = 0; i < max * maxMultiplier; i++) {
627 promises.push(pool.execute())
628 }
629 await Promise.all(promises)
630 expect(
631 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
632 pool.workerChoiceStrategyContext.workerChoiceStrategy
633 ).defaultWorkerWeight
634 ).toBeGreaterThan(0)
635 expect(
636 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
637 pool.workerChoiceStrategyContext.workerChoiceStrategy
638 ).workerVirtualTaskRunTime
639 ).toBeGreaterThanOrEqual(0)
640 // We need to clean up the resources after our test
641 await pool.destroy()
642 })
643
644 it('Verify WEIGHTED_ROUND_ROBIN strategy can be run in a dynamic pool', async () => {
645 const pool = new DynamicThreadPool(
646 min,
647 max,
648 './tests/worker-files/thread/testWorker.js',
649 { workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN }
650 )
651 // TODO: Create a better test to cover `WeightedRoundRobinWorkerChoiceStrategy#choose`
652 const promises = []
653 const maxMultiplier =
654 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
655 pool.workerChoiceStrategyContext.workerChoiceStrategy
656 ).defaultWorkerWeight * 50
657 for (let i = 0; i < max * maxMultiplier; i++) {
658 promises.push(pool.execute())
659 }
660 await Promise.all(promises)
661 expect(
662 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
663 pool.workerChoiceStrategyContext.workerChoiceStrategy
664 ).defaultWorkerWeight
665 ).toBeGreaterThan(0)
666 expect(
667 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
668 pool.workerChoiceStrategyContext.workerChoiceStrategy
669 ).workerVirtualTaskRunTime
670 ).toBeGreaterThanOrEqual(0)
671 // We need to clean up the resources after our test
672 await pool.destroy()
673 })
674
675 it('Verify WEIGHTED_ROUND_ROBIN strategy can be run in a dynamic pool with median run time statistic', async () => {
676 const pool = new DynamicThreadPool(
677 min,
678 max,
679 './tests/worker-files/thread/testWorker.js',
680 {
681 workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN,
682 workerChoiceStrategyOptions: {
683 medRunTime: true
684 }
685 }
686 )
687 // TODO: Create a better test to cover `WeightedRoundRobinWorkerChoiceStrategy#choose`
688 const promises = []
689 const maxMultiplier = 2
690 for (let i = 0; i < max * maxMultiplier; i++) {
691 promises.push(pool.execute())
692 }
693 await Promise.all(promises)
694 for (const workerNode of pool.workerNodes) {
695 expect(workerNode.tasksUsage.avgRunTime).toBeDefined()
696 expect(workerNode.tasksUsage.avgRunTime).toBe(0)
697 expect(workerNode.tasksUsage.medRunTime).toBeDefined()
698 expect(workerNode.tasksUsage.medRunTime).toBeGreaterThan(0)
699 }
700 expect(
701 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
702 pool.workerChoiceStrategyContext.workerChoiceStrategy
703 ).defaultWorkerWeight
704 ).toBeGreaterThan(0)
705 expect(
706 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
707 pool.workerChoiceStrategyContext.workerChoiceStrategy
708 ).workerVirtualTaskRunTime
709 ).toBeGreaterThanOrEqual(0)
710 // We need to clean up the resources after our test
711 await pool.destroy()
712 })
713
714 it('Verify WEIGHTED_ROUND_ROBIN strategy internals are resets after setting it', async () => {
715 const workerChoiceStrategy = WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
716 let pool = new FixedThreadPool(
717 max,
718 './tests/worker-files/thread/testWorker.js'
719 )
720 expect(
721 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
722 workerChoiceStrategy
723 ).currentWorkerNodeId
724 ).toBeDefined()
725 expect(
726 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
727 workerChoiceStrategy
728 ).defaultWorkerWeight
729 ).toBeDefined()
730 expect(
731 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
732 workerChoiceStrategy
733 ).workerVirtualTaskRunTime
734 ).toBeDefined()
735 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
736 expect(
737 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
738 pool.workerChoiceStrategyContext.workerChoiceStrategy
739 ).currentWorkerNodeId
740 ).toBe(0)
741 expect(
742 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
743 pool.workerChoiceStrategyContext.workerChoiceStrategy
744 ).defaultWorkerWeight
745 ).toBeGreaterThan(0)
746 expect(
747 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
748 workerChoiceStrategy
749 ).workerVirtualTaskRunTime
750 ).toBe(0)
751 await pool.destroy()
752 pool = new DynamicThreadPool(
753 min,
754 max,
755 './tests/worker-files/thread/testWorker.js'
756 )
757 expect(
758 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
759 workerChoiceStrategy
760 ).currentWorkerNodeId
761 ).toBeDefined()
762 expect(
763 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
764 workerChoiceStrategy
765 ).defaultWorkerWeight
766 ).toBeDefined()
767 expect(
768 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
769 workerChoiceStrategy
770 ).workerVirtualTaskRunTime
771 ).toBeDefined()
772 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
773 expect(
774 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
775 pool.workerChoiceStrategyContext.workerChoiceStrategy
776 ).currentWorkerNodeId
777 ).toBe(0)
778 expect(
779 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
780 pool.workerChoiceStrategyContext.workerChoiceStrategy
781 ).defaultWorkerWeight
782 ).toBeGreaterThan(0)
783 expect(
784 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
785 workerChoiceStrategy
786 ).workerVirtualTaskRunTime
787 ).toBe(0)
788 // We need to clean up the resources after our test
789 await pool.destroy()
790 })
791
792 it('Verify unknown strategy throw error', () => {
793 expect(
794 () =>
795 new DynamicThreadPool(
796 min,
797 max,
798 './tests/worker-files/thread/testWorker.js',
799 { workerChoiceStrategy: 'UNKNOWN_STRATEGY' }
800 )
801 ).toThrowError("Invalid worker choice strategy 'UNKNOWN_STRATEGY'")
802 })
803 })