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