refactor: rename worker choice strategies to sensible names
[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.LEAST_USED).toBe('LEAST_USED')
16 expect(WorkerChoiceStrategies.LEAST_BUSY).toBe('LEAST_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 ).workersVirtualTaskEndTimestamp
84 ).toBeInstanceOf(Array)
85 expect(
86 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
87 workerChoiceStrategy
88 ).workersVirtualTaskEndTimestamp.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 maxMultiplier = 2
157 for (let i = 0; i < max * maxMultiplier; i++) {
158 await pool.execute()
159 }
160 // We need to clean up the resources after our test
161 await pool.destroy()
162 })
163
164 it('Verify ROUND_ROBIN strategy can be run in a dynamic pool', async () => {
165 const pool = new DynamicThreadPool(
166 min,
167 max,
168 './tests/worker-files/thread/testWorker.js',
169 { workerChoiceStrategy: WorkerChoiceStrategies.ROUND_ROBIN }
170 )
171 // TODO: Create a better test to cover `RoundRobinWorkerChoiceStrategy#choose`
172 const maxMultiplier = 2
173 for (let i = 0; i < max * maxMultiplier; i++) {
174 await pool.execute()
175 }
176 // We need to clean up the resources after our test
177 await pool.destroy()
178 })
179
180 it('Verify ROUND_ROBIN strategy runtime behavior', async () => {
181 const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN
182 let pool = new FixedClusterPool(
183 max,
184 './tests/worker-files/cluster/testWorker.js',
185 { workerChoiceStrategy }
186 )
187 let results = new Set()
188 for (let i = 0; i < max; i++) {
189 results.add(pool.workerNodes[pool.chooseWorkerNode()].worker.id)
190 }
191 expect(results.size).toBe(max)
192 await pool.destroy()
193 pool = new FixedThreadPool(
194 max,
195 './tests/worker-files/thread/testWorker.js',
196 { workerChoiceStrategy }
197 )
198 results = new Set()
199 for (let i = 0; i < max; i++) {
200 results.add(pool.workerNodes[pool.chooseWorkerNode()].worker.threadId)
201 }
202 expect(results.size).toBe(max)
203 await pool.destroy()
204 })
205
206 it('Verify ROUND_ROBIN strategy internals are resets after setting it', async () => {
207 const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN
208 let pool = new FixedThreadPool(
209 max,
210 './tests/worker-files/thread/testWorker.js',
211 { workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN }
212 )
213 expect(
214 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
215 workerChoiceStrategy
216 ).nextWorkerNodeId
217 ).toBeDefined()
218 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
219 expect(
220 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
221 pool.workerChoiceStrategyContext.workerChoiceStrategy
222 ).nextWorkerNodeId
223 ).toBe(0)
224 await pool.destroy()
225 pool = new DynamicThreadPool(
226 min,
227 max,
228 './tests/worker-files/thread/testWorker.js',
229 { workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN }
230 )
231 expect(
232 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
233 workerChoiceStrategy
234 ).nextWorkerNodeId
235 ).toBeDefined()
236 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
237 expect(
238 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
239 pool.workerChoiceStrategyContext.workerChoiceStrategy
240 ).nextWorkerNodeId
241 ).toBe(0)
242 // We need to clean up the resources after our test
243 await pool.destroy()
244 })
245
246 it('Verify LEAST_USED strategy default tasks usage statistics requirements', async () => {
247 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_USED
248 let pool = new FixedThreadPool(
249 max,
250 './tests/worker-files/thread/testWorker.js',
251 { workerChoiceStrategy }
252 )
253 expect(
254 pool.workerChoiceStrategyContext.getRequiredStatistics().runTime
255 ).toBe(false)
256 expect(
257 pool.workerChoiceStrategyContext.getRequiredStatistics().avgRunTime
258 ).toBe(false)
259 expect(
260 pool.workerChoiceStrategyContext.getRequiredStatistics().medRunTime
261 ).toBe(false)
262 await pool.destroy()
263 pool = new DynamicThreadPool(
264 min,
265 max,
266 './tests/worker-files/thread/testWorker.js',
267 { workerChoiceStrategy }
268 )
269 expect(
270 pool.workerChoiceStrategyContext.getRequiredStatistics().runTime
271 ).toBe(false)
272 expect(
273 pool.workerChoiceStrategyContext.getRequiredStatistics().avgRunTime
274 ).toBe(false)
275 expect(
276 pool.workerChoiceStrategyContext.getRequiredStatistics().medRunTime
277 ).toBe(false)
278 // We need to clean up the resources after our test
279 await pool.destroy()
280 })
281
282 it('Verify LEAST_USED strategy can be run in a fixed pool', async () => {
283 const pool = new FixedThreadPool(
284 max,
285 './tests/worker-files/thread/testWorker.js',
286 { workerChoiceStrategy: WorkerChoiceStrategies.LEAST_USED }
287 )
288 // TODO: Create a better test to cover `LeastUsedWorkerChoiceStrategy#choose`
289 const maxMultiplier = 2
290 for (let i = 0; i < max * maxMultiplier; i++) {
291 await pool.execute()
292 }
293 // We need to clean up the resources after our test
294 await pool.destroy()
295 })
296
297 it('Verify LEAST_USED strategy can be run in a dynamic pool', async () => {
298 const pool = new DynamicThreadPool(
299 min,
300 max,
301 './tests/worker-files/thread/testWorker.js',
302 { workerChoiceStrategy: WorkerChoiceStrategies.LEAST_USED }
303 )
304 // TODO: Create a better test to cover `LeastUsedWorkerChoiceStrategy#choose`
305 const maxMultiplier = 2
306 for (let i = 0; i < max * maxMultiplier; i++) {
307 await pool.execute()
308 }
309 // We need to clean up the resources after our test
310 await pool.destroy()
311 })
312
313 it('Verify LEAST_BUSY strategy default tasks usage statistics requirements', async () => {
314 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_BUSY
315 let pool = new FixedThreadPool(
316 max,
317 './tests/worker-files/thread/testWorker.js',
318 { workerChoiceStrategy }
319 )
320 expect(
321 pool.workerChoiceStrategyContext.getRequiredStatistics().runTime
322 ).toBe(true)
323 expect(
324 pool.workerChoiceStrategyContext.getRequiredStatistics().avgRunTime
325 ).toBe(false)
326 expect(
327 pool.workerChoiceStrategyContext.getRequiredStatistics().medRunTime
328 ).toBe(false)
329 await pool.destroy()
330 pool = new DynamicThreadPool(
331 min,
332 max,
333 './tests/worker-files/thread/testWorker.js',
334 { workerChoiceStrategy }
335 )
336 expect(
337 pool.workerChoiceStrategyContext.getRequiredStatistics().runTime
338 ).toBe(true)
339 expect(
340 pool.workerChoiceStrategyContext.getRequiredStatistics().avgRunTime
341 ).toBe(false)
342 expect(
343 pool.workerChoiceStrategyContext.getRequiredStatistics().medRunTime
344 ).toBe(false)
345 // We need to clean up the resources after our test
346 await pool.destroy()
347 })
348
349 it('Verify LEAST_BUSY strategy can be run in a fixed pool', async () => {
350 const pool = new FixedThreadPool(
351 max,
352 './tests/worker-files/thread/testWorker.js',
353 { workerChoiceStrategy: WorkerChoiceStrategies.LEAST_BUSY }
354 )
355 // TODO: Create a better test to cover `LeastBusyWorkerChoiceStrategy#choose`
356 const maxMultiplier = 2
357 for (let i = 0; i < max * maxMultiplier; i++) {
358 await pool.execute()
359 }
360 // We need to clean up the resources after our test
361 await pool.destroy()
362 })
363
364 it('Verify LEAST_BUSY strategy can be run in a dynamic pool', async () => {
365 const pool = new DynamicThreadPool(
366 min,
367 max,
368 './tests/worker-files/thread/testWorker.js',
369 { workerChoiceStrategy: WorkerChoiceStrategies.LEAST_BUSY }
370 )
371 // TODO: Create a better test to cover `LeastBusyWorkerChoiceStrategy#choose`
372 const maxMultiplier = 2
373 for (let i = 0; i < max * maxMultiplier; i++) {
374 await pool.execute()
375 }
376 // We need to clean up the resources after our test
377 await pool.destroy()
378 })
379
380 it('Verify FAIR_SHARE strategy default tasks usage statistics requirements', async () => {
381 const workerChoiceStrategy = WorkerChoiceStrategies.FAIR_SHARE
382 let pool = new FixedThreadPool(
383 max,
384 './tests/worker-files/thread/testWorker.js',
385 { workerChoiceStrategy }
386 )
387 expect(
388 pool.workerChoiceStrategyContext.getRequiredStatistics().runTime
389 ).toBe(true)
390 expect(
391 pool.workerChoiceStrategyContext.getRequiredStatistics().avgRunTime
392 ).toBe(true)
393 expect(
394 pool.workerChoiceStrategyContext.getRequiredStatistics().medRunTime
395 ).toBe(false)
396 await pool.destroy()
397 pool = new DynamicThreadPool(
398 min,
399 max,
400 './tests/worker-files/thread/testWorker.js',
401 { workerChoiceStrategy }
402 )
403 expect(
404 pool.workerChoiceStrategyContext.getRequiredStatistics().runTime
405 ).toBe(true)
406 expect(
407 pool.workerChoiceStrategyContext.getRequiredStatistics().avgRunTime
408 ).toBe(true)
409 expect(
410 pool.workerChoiceStrategyContext.getRequiredStatistics().medRunTime
411 ).toBe(false)
412 // We need to clean up the resources after our test
413 await pool.destroy()
414 })
415
416 it('Verify FAIR_SHARE strategy can be run in a fixed pool', async () => {
417 const pool = new FixedThreadPool(
418 max,
419 './tests/worker-files/thread/testWorker.js',
420 { workerChoiceStrategy: WorkerChoiceStrategies.FAIR_SHARE }
421 )
422 // TODO: Create a better test to cover `FairShareChoiceStrategy#choose`
423 const maxMultiplier = 2
424 for (let i = 0; i < max * maxMultiplier; i++) {
425 await pool.execute()
426 }
427 for (const workerNode of pool.workerNodes) {
428 expect(workerNode.tasksUsage.avgRunTime).toBeDefined()
429 expect(workerNode.tasksUsage.avgRunTime).toBeGreaterThanOrEqual(0)
430 expect(workerNode.tasksUsage.medRunTime).toBeDefined()
431 expect(workerNode.tasksUsage.medRunTime).toBe(0)
432 }
433 expect(
434 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
435 pool.workerChoiceStrategyContext.workerChoiceStrategy
436 ).workersVirtualTaskEndTimestamp.length
437 ).toBe(pool.workerNodes.length)
438 // We need to clean up the resources after our test
439 await pool.destroy()
440 })
441
442 it('Verify FAIR_SHARE strategy can be run in a dynamic pool', async () => {
443 const pool = new DynamicThreadPool(
444 min,
445 max,
446 './tests/worker-files/thread/testWorker.js',
447 { workerChoiceStrategy: WorkerChoiceStrategies.FAIR_SHARE }
448 )
449 // TODO: Create a better test to cover `FairShareChoiceStrategy#choose`
450 const maxMultiplier = 2
451 for (let i = 0; i < max * maxMultiplier; i++) {
452 await pool.execute()
453 }
454 for (const workerNode of pool.workerNodes) {
455 expect(workerNode.tasksUsage.avgRunTime).toBeDefined()
456 expect(workerNode.tasksUsage.avgRunTime).toBeGreaterThanOrEqual(0)
457 expect(workerNode.tasksUsage.medRunTime).toBeDefined()
458 expect(workerNode.tasksUsage.medRunTime).toBe(0)
459 }
460 expect(
461 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
462 pool.workerChoiceStrategyContext.workerChoiceStrategy
463 ).workersVirtualTaskEndTimestamp.length
464 ).toBe(pool.workerNodes.length)
465 // We need to clean up the resources after our test
466 await pool.destroy()
467 })
468
469 it('Verify FAIR_SHARE strategy can be run in a dynamic pool with median runtime statistic', async () => {
470 const pool = new DynamicThreadPool(
471 min,
472 max,
473 './tests/worker-files/thread/testWorker.js',
474 {
475 workerChoiceStrategy: WorkerChoiceStrategies.FAIR_SHARE,
476 workerChoiceStrategyOptions: {
477 medRunTime: true
478 }
479 }
480 )
481 // TODO: Create a better test to cover `FairShareChoiceStrategy#choose`
482 const maxMultiplier = 2
483 for (let i = 0; i < max * maxMultiplier; i++) {
484 await pool.execute()
485 }
486 for (const workerNode of pool.workerNodes) {
487 expect(workerNode.tasksUsage.avgRunTime).toBeDefined()
488 expect(workerNode.tasksUsage.avgRunTime).toBe(0)
489 expect(workerNode.tasksUsage.medRunTime).toBeDefined()
490 expect(workerNode.tasksUsage.medRunTime).toBeGreaterThanOrEqual(0)
491 }
492 expect(
493 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
494 pool.workerChoiceStrategyContext.workerChoiceStrategy
495 ).workersVirtualTaskEndTimestamp.length
496 ).toBe(pool.workerNodes.length)
497 // We need to clean up the resources after our test
498 await pool.destroy()
499 })
500
501 it('Verify FAIR_SHARE strategy internals are resets after setting it', async () => {
502 const workerChoiceStrategy = WorkerChoiceStrategies.FAIR_SHARE
503 let pool = new FixedThreadPool(
504 max,
505 './tests/worker-files/thread/testWorker.js'
506 )
507 expect(
508 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
509 workerChoiceStrategy
510 ).workersVirtualTaskEndTimestamp
511 ).toBeInstanceOf(Array)
512 expect(
513 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
514 workerChoiceStrategy
515 ).workersVirtualTaskEndTimestamp.length
516 ).toBe(0)
517 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
518 workerChoiceStrategy
519 ).workersVirtualTaskEndTimestamp[0] = performance.now()
520 expect(
521 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
522 workerChoiceStrategy
523 ).workersVirtualTaskEndTimestamp.length
524 ).toBe(1)
525 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
526 expect(
527 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
528 workerChoiceStrategy
529 ).workersVirtualTaskEndTimestamp
530 ).toBeInstanceOf(Array)
531 expect(
532 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
533 workerChoiceStrategy
534 ).workersVirtualTaskEndTimestamp.length
535 ).toBe(0)
536 await pool.destroy()
537 pool = new DynamicThreadPool(
538 min,
539 max,
540 './tests/worker-files/thread/testWorker.js'
541 )
542 expect(
543 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
544 workerChoiceStrategy
545 ).workersVirtualTaskEndTimestamp
546 ).toBeInstanceOf(Array)
547 expect(
548 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
549 workerChoiceStrategy
550 ).workersVirtualTaskEndTimestamp.length
551 ).toBe(0)
552 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
553 workerChoiceStrategy
554 ).workersVirtualTaskEndTimestamp[0] = performance.now()
555 expect(
556 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
557 workerChoiceStrategy
558 ).workersVirtualTaskEndTimestamp.length
559 ).toBe(1)
560 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
561 expect(
562 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
563 workerChoiceStrategy
564 ).workersVirtualTaskEndTimestamp
565 ).toBeInstanceOf(Array)
566 expect(
567 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
568 workerChoiceStrategy
569 ).workersVirtualTaskEndTimestamp.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 maxMultiplier = 2
619 for (let i = 0; i < max * maxMultiplier; i++) {
620 await pool.execute()
621 }
622 for (const workerNode of pool.workerNodes) {
623 expect(workerNode.tasksUsage.avgRunTime).toBeDefined()
624 expect(workerNode.tasksUsage.avgRunTime).toBeGreaterThanOrEqual(0)
625 expect(workerNode.tasksUsage.medRunTime).toBeDefined()
626 expect(workerNode.tasksUsage.medRunTime).toBe(0)
627 }
628 expect(
629 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
630 pool.workerChoiceStrategyContext.workerChoiceStrategy
631 ).defaultWorkerWeight
632 ).toBeGreaterThan(0)
633 expect(
634 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
635 pool.workerChoiceStrategyContext.workerChoiceStrategy
636 ).workerVirtualTaskRunTime
637 ).toBeGreaterThanOrEqual(0)
638 // We need to clean up the resources after our test
639 await pool.destroy()
640 })
641
642 it('Verify WEIGHTED_ROUND_ROBIN strategy can be run in a dynamic pool', async () => {
643 const pool = new DynamicThreadPool(
644 min,
645 max,
646 './tests/worker-files/thread/testWorker.js',
647 { workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN }
648 )
649 // TODO: Create a better test to cover `WeightedRoundRobinWorkerChoiceStrategy#choose`
650 const maxMultiplier = 2
651 for (let i = 0; i < max * maxMultiplier; i++) {
652 await pool.execute()
653 }
654 for (const workerNode of pool.workerNodes) {
655 expect(workerNode.tasksUsage.avgRunTime).toBeDefined()
656 expect(workerNode.tasksUsage.avgRunTime).toBeGreaterThanOrEqual(0)
657 expect(workerNode.tasksUsage.medRunTime).toBeDefined()
658 expect(workerNode.tasksUsage.medRunTime).toBe(0)
659 }
660 expect(
661 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
662 pool.workerChoiceStrategyContext.workerChoiceStrategy
663 ).defaultWorkerWeight
664 ).toBeGreaterThan(0)
665 expect(
666 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
667 pool.workerChoiceStrategyContext.workerChoiceStrategy
668 ).workerVirtualTaskRunTime
669 ).toBeGreaterThanOrEqual(0)
670 // We need to clean up the resources after our test
671 await pool.destroy()
672 })
673
674 it('Verify WEIGHTED_ROUND_ROBIN strategy can be run in a dynamic pool with median runtime statistic', async () => {
675 const pool = new DynamicThreadPool(
676 min,
677 max,
678 './tests/worker-files/thread/testWorker.js',
679 {
680 workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN,
681 workerChoiceStrategyOptions: {
682 medRunTime: true
683 }
684 }
685 )
686 // TODO: Create a better test to cover `WeightedRoundRobinWorkerChoiceStrategy#choose`
687 const maxMultiplier = 2
688 for (let i = 0; i < max * maxMultiplier; i++) {
689 await pool.execute()
690 }
691 for (const workerNode of pool.workerNodes) {
692 expect(workerNode.tasksUsage.avgRunTime).toBeDefined()
693 expect(workerNode.tasksUsage.avgRunTime).toBe(0)
694 expect(workerNode.tasksUsage.medRunTime).toBeDefined()
695 expect(workerNode.tasksUsage.medRunTime).toBeGreaterThanOrEqual(0)
696 }
697 expect(
698 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
699 pool.workerChoiceStrategyContext.workerChoiceStrategy
700 ).defaultWorkerWeight
701 ).toBeGreaterThan(0)
702 expect(
703 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
704 pool.workerChoiceStrategyContext.workerChoiceStrategy
705 ).workerVirtualTaskRunTime
706 ).toBeGreaterThanOrEqual(0)
707 // We need to clean up the resources after our test
708 await pool.destroy()
709 })
710
711 it('Verify WEIGHTED_ROUND_ROBIN strategy internals are resets after setting it', async () => {
712 const workerChoiceStrategy = WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
713 let pool = new FixedThreadPool(
714 max,
715 './tests/worker-files/thread/testWorker.js'
716 )
717 expect(
718 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
719 workerChoiceStrategy
720 ).currentWorkerNodeId
721 ).toBeDefined()
722 expect(
723 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
724 workerChoiceStrategy
725 ).defaultWorkerWeight
726 ).toBeDefined()
727 expect(
728 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
729 workerChoiceStrategy
730 ).workerVirtualTaskRunTime
731 ).toBeDefined()
732 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
733 expect(
734 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
735 pool.workerChoiceStrategyContext.workerChoiceStrategy
736 ).currentWorkerNodeId
737 ).toBe(0)
738 expect(
739 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
740 pool.workerChoiceStrategyContext.workerChoiceStrategy
741 ).defaultWorkerWeight
742 ).toBeGreaterThan(0)
743 expect(
744 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
745 workerChoiceStrategy
746 ).workerVirtualTaskRunTime
747 ).toBe(0)
748 await pool.destroy()
749 pool = new DynamicThreadPool(
750 min,
751 max,
752 './tests/worker-files/thread/testWorker.js'
753 )
754 expect(
755 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
756 workerChoiceStrategy
757 ).currentWorkerNodeId
758 ).toBeDefined()
759 expect(
760 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
761 workerChoiceStrategy
762 ).defaultWorkerWeight
763 ).toBeDefined()
764 expect(
765 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
766 workerChoiceStrategy
767 ).workerVirtualTaskRunTime
768 ).toBeDefined()
769 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
770 expect(
771 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
772 pool.workerChoiceStrategyContext.workerChoiceStrategy
773 ).currentWorkerNodeId
774 ).toBe(0)
775 expect(
776 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
777 pool.workerChoiceStrategyContext.workerChoiceStrategy
778 ).defaultWorkerWeight
779 ).toBeGreaterThan(0)
780 expect(
781 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
782 workerChoiceStrategy
783 ).workerVirtualTaskRunTime
784 ).toBe(0)
785 // We need to clean up the resources after our test
786 await pool.destroy()
787 })
788
789 it('Verify unknown strategy throw error', () => {
790 expect(
791 () =>
792 new DynamicThreadPool(
793 min,
794 max,
795 './tests/worker-files/thread/testWorker.js',
796 { workerChoiceStrategy: 'UNKNOWN_STRATEGY' }
797 )
798 ).toThrowError("Invalid worker choice strategy 'UNKNOWN_STRATEGY'")
799 })
800 })