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