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