af63b3e976113702b98ec5947c54fc4ba03e44fe
[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 if (process.platform !== 'win32') {
465 expect(
466 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
467 pool.workerChoiceStrategyContext.workerChoiceStrategy
468 ).workersVirtualTaskTimestamp.length
469 ).toBe(pool.workerNodes.length)
470 }
471 // We need to clean up the resources after our test
472 await pool.destroy()
473 })
474
475 it('Verify FAIR_SHARE strategy can be run in a dynamic pool with median run time statistic', async () => {
476 const pool = new DynamicThreadPool(
477 min,
478 max,
479 './tests/worker-files/thread/testWorker.js',
480 {
481 workerChoiceStrategy: WorkerChoiceStrategies.FAIR_SHARE,
482 workerChoiceStrategyOptions: {
483 medRunTime: true
484 }
485 }
486 )
487 // TODO: Create a better test to cover `FairShareChoiceStrategy#choose`
488 const promises = []
489 const maxMultiplier = 2
490 for (let i = 0; i < max * maxMultiplier; i++) {
491 promises.push(pool.execute())
492 }
493 await Promise.all(promises)
494 for (const workerNode of pool.workerNodes) {
495 expect(workerNode.tasksUsage.avgRunTime).toBeDefined()
496 expect(workerNode.tasksUsage.avgRunTime).toBe(0)
497 expect(workerNode.tasksUsage.medRunTime).toBeDefined()
498 expect(workerNode.tasksUsage.medRunTime).toBeGreaterThan(0)
499 }
500 if (process.platform !== 'win32') {
501 expect(
502 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
503 pool.workerChoiceStrategyContext.workerChoiceStrategy
504 ).workersVirtualTaskTimestamp.length
505 ).toBe(pool.workerNodes.length)
506 }
507 // We need to clean up the resources after our test
508 await pool.destroy()
509 })
510
511 it('Verify FAIR_SHARE strategy internals are resets after setting it', async () => {
512 const workerChoiceStrategy = WorkerChoiceStrategies.FAIR_SHARE
513 let pool = new FixedThreadPool(
514 max,
515 './tests/worker-files/thread/testWorker.js'
516 )
517 expect(
518 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
519 workerChoiceStrategy
520 ).workersVirtualTaskTimestamp
521 ).toBeInstanceOf(Array)
522 expect(
523 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
524 workerChoiceStrategy
525 ).workersVirtualTaskTimestamp.length
526 ).toBe(0)
527 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
528 expect(
529 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
530 workerChoiceStrategy
531 ).workersVirtualTaskTimestamp
532 ).toBeInstanceOf(Array)
533 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
534 workerChoiceStrategy
535 ).workersVirtualTaskTimestamp[0] = 0
536 expect(
537 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
538 workerChoiceStrategy
539 ).workersVirtualTaskTimestamp.length
540 ).toBe(1)
541 await pool.destroy()
542 pool = new DynamicThreadPool(
543 min,
544 max,
545 './tests/worker-files/thread/testWorker.js'
546 )
547 expect(
548 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
549 workerChoiceStrategy
550 ).workersVirtualTaskTimestamp
551 ).toBeInstanceOf(Array)
552 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
553 workerChoiceStrategy
554 ).workersVirtualTaskTimestamp[0] = 0
555 expect(
556 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
557 workerChoiceStrategy
558 ).workersVirtualTaskTimestamp.length
559 ).toBe(1)
560 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
561 expect(
562 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
563 workerChoiceStrategy
564 ).workersVirtualTaskTimestamp
565 ).toBeInstanceOf(Array)
566 expect(
567 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
568 workerChoiceStrategy
569 ).workersVirtualTaskTimestamp.length
570 ).toBe(0)
571 // We need to clean up the resources after our test
572 await pool.destroy()
573 })
574
575 it('Verify WEIGHTED_ROUND_ROBIN strategy default tasks usage statistics requirements', async () => {
576 const workerChoiceStrategy = WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
577 let pool = new FixedThreadPool(
578 max,
579 './tests/worker-files/thread/testWorker.js',
580 { workerChoiceStrategy }
581 )
582 expect(
583 pool.workerChoiceStrategyContext.getRequiredStatistics().runTime
584 ).toBe(true)
585 expect(
586 pool.workerChoiceStrategyContext.getRequiredStatistics().avgRunTime
587 ).toBe(true)
588 expect(
589 pool.workerChoiceStrategyContext.getRequiredStatistics().medRunTime
590 ).toBe(false)
591 await pool.destroy()
592 pool = new DynamicThreadPool(
593 min,
594 max,
595 './tests/worker-files/thread/testWorker.js',
596 { workerChoiceStrategy }
597 )
598 expect(
599 pool.workerChoiceStrategyContext.getRequiredStatistics().runTime
600 ).toBe(true)
601 expect(
602 pool.workerChoiceStrategyContext.getRequiredStatistics().avgRunTime
603 ).toBe(true)
604 expect(
605 pool.workerChoiceStrategyContext.getRequiredStatistics().medRunTime
606 ).toBe(false)
607 // We need to clean up the resources after our test
608 await pool.destroy()
609 })
610
611 it('Verify WEIGHTED_ROUND_ROBIN strategy can be run in a fixed pool', async () => {
612 const pool = new FixedThreadPool(
613 max,
614 './tests/worker-files/thread/testWorker.js',
615 { workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN }
616 )
617 // TODO: Create a better test to cover `WeightedRoundRobinWorkerChoiceStrategy#choose`
618 const promises = []
619 const maxMultiplier = 2
620 for (let i = 0; i < max * maxMultiplier; i++) {
621 promises.push(pool.execute())
622 }
623 await Promise.all(promises)
624 expect(
625 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
626 pool.workerChoiceStrategyContext.workerChoiceStrategy
627 ).defaultWorkerWeight
628 ).toBeGreaterThan(0)
629 expect(
630 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
631 pool.workerChoiceStrategyContext.workerChoiceStrategy
632 ).workerVirtualTaskRunTime
633 ).toBeGreaterThanOrEqual(0)
634 // We need to clean up the resources after our test
635 await pool.destroy()
636 })
637
638 it('Verify WEIGHTED_ROUND_ROBIN strategy can be run in a dynamic pool', async () => {
639 const pool = new DynamicThreadPool(
640 min,
641 max,
642 './tests/worker-files/thread/testWorker.js',
643 { workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN }
644 )
645 // TODO: Create a better test to cover `WeightedRoundRobinWorkerChoiceStrategy#choose`
646 const promises = []
647 const maxMultiplier =
648 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
649 pool.workerChoiceStrategyContext.workerChoiceStrategy
650 ).defaultWorkerWeight * 50
651 for (let i = 0; i < max * maxMultiplier; i++) {
652 promises.push(pool.execute())
653 }
654 await Promise.all(promises)
655 if (process.platform !== 'win32') {
656 expect(
657 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
658 pool.workerChoiceStrategyContext.workerChoiceStrategy
659 ).defaultWorkerWeight
660 ).toBeGreaterThan(0)
661 expect(
662 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
663 pool.workerChoiceStrategyContext.workerChoiceStrategy
664 ).workerVirtualTaskRunTime
665 ).toBeGreaterThanOrEqual(0)
666 }
667 // We need to clean up the resources after our test
668 await pool.destroy()
669 })
670
671 it('Verify WEIGHTED_ROUND_ROBIN strategy can be run in a dynamic pool with median run time statistic', async () => {
672 const pool = new DynamicThreadPool(
673 min,
674 max,
675 './tests/worker-files/thread/testWorker.js',
676 {
677 workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN,
678 workerChoiceStrategyOptions: {
679 medRunTime: true
680 }
681 }
682 )
683 // TODO: Create a better test to cover `WeightedRoundRobinWorkerChoiceStrategy#choose`
684 const promises = []
685 const maxMultiplier = 2
686 for (let i = 0; i < max * maxMultiplier; i++) {
687 promises.push(pool.execute())
688 }
689 await Promise.all(promises)
690 for (const workerNode of pool.workerNodes) {
691 expect(workerNode.tasksUsage.avgRunTime).toBeDefined()
692 expect(workerNode.tasksUsage.avgRunTime).toBe(0)
693 expect(workerNode.tasksUsage.medRunTime).toBeDefined()
694 expect(workerNode.tasksUsage.medRunTime).toBeGreaterThan(0)
695 }
696 expect(
697 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
698 pool.workerChoiceStrategyContext.workerChoiceStrategy
699 ).defaultWorkerWeight
700 ).toBeGreaterThan(0)
701 expect(
702 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
703 pool.workerChoiceStrategyContext.workerChoiceStrategy
704 ).workerVirtualTaskRunTime
705 ).toBeGreaterThanOrEqual(0)
706 // We need to clean up the resources after our test
707 await pool.destroy()
708 })
709
710 it('Verify WEIGHTED_ROUND_ROBIN strategy internals are resets after setting it', async () => {
711 const workerChoiceStrategy = WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
712 let pool = new FixedThreadPool(
713 max,
714 './tests/worker-files/thread/testWorker.js'
715 )
716 expect(
717 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
718 workerChoiceStrategy
719 ).currentWorkerNodeId
720 ).toBeDefined()
721 expect(
722 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
723 workerChoiceStrategy
724 ).defaultWorkerWeight
725 ).toBeDefined()
726 expect(
727 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
728 workerChoiceStrategy
729 ).workerVirtualTaskRunTime
730 ).toBeDefined()
731 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
732 expect(
733 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
734 pool.workerChoiceStrategyContext.workerChoiceStrategy
735 ).currentWorkerNodeId
736 ).toBe(0)
737 expect(
738 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
739 pool.workerChoiceStrategyContext.workerChoiceStrategy
740 ).defaultWorkerWeight
741 ).toBeGreaterThan(0)
742 expect(
743 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
744 workerChoiceStrategy
745 ).workerVirtualTaskRunTime
746 ).toBe(0)
747 await pool.destroy()
748 pool = new DynamicThreadPool(
749 min,
750 max,
751 './tests/worker-files/thread/testWorker.js'
752 )
753 expect(
754 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
755 workerChoiceStrategy
756 ).currentWorkerNodeId
757 ).toBeDefined()
758 expect(
759 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
760 workerChoiceStrategy
761 ).defaultWorkerWeight
762 ).toBeDefined()
763 expect(
764 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
765 workerChoiceStrategy
766 ).workerVirtualTaskRunTime
767 ).toBeDefined()
768 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
769 expect(
770 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
771 pool.workerChoiceStrategyContext.workerChoiceStrategy
772 ).currentWorkerNodeId
773 ).toBe(0)
774 expect(
775 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
776 pool.workerChoiceStrategyContext.workerChoiceStrategy
777 ).defaultWorkerWeight
778 ).toBeGreaterThan(0)
779 expect(
780 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
781 workerChoiceStrategy
782 ).workerVirtualTaskRunTime
783 ).toBe(0)
784 // We need to clean up the resources after our test
785 await pool.destroy()
786 })
787
788 it('Verify unknown strategy throw error', () => {
789 expect(
790 () =>
791 new DynamicThreadPool(
792 min,
793 max,
794 './tests/worker-files/thread/testWorker.js',
795 { workerChoiceStrategy: 'UNKNOWN_STRATEGY' }
796 )
797 ).toThrowError("Invalid worker choice strategy 'UNKNOWN_STRATEGY'")
798 })
799 })