test: add tests for worker choice strategies using median run time
[poolifier.git] / tests / pools / selection-strategies / selection-strategies.test.js
CommitLineData
a61a0724 1const { expect } = require('expect')
a35560ba
S
2const {
3 WorkerChoiceStrategies,
4 DynamicThreadPool,
2ced693a
JB
5 FixedThreadPool,
6 FixedClusterPool
15d56315 7} = require('../../../lib/index')
a35560ba
S
8
9describe('Selection strategies test suite', () => {
e1ffb94f
JB
10 const min = 0
11 const max = 3
12
a35560ba
S
13 it('Verify that WorkerChoiceStrategies enumeration provides string values', () => {
14 expect(WorkerChoiceStrategies.ROUND_ROBIN).toBe('ROUND_ROBIN')
737c6d97 15 expect(WorkerChoiceStrategies.LESS_USED).toBe('LESS_USED')
168c526f 16 expect(WorkerChoiceStrategies.LESS_BUSY).toBe('LESS_BUSY')
23ff945a 17 expect(WorkerChoiceStrategies.FAIR_SHARE).toBe('FAIR_SHARE')
b3432a63
JB
18 expect(WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN).toBe(
19 'WEIGHTED_ROUND_ROBIN'
20 )
a35560ba
S
21 })
22
e843b904 23 it('Verify ROUND_ROBIN strategy is the default at pool creation', async () => {
e843b904
JB
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
594bfb84
JB
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 }
d2f7b7a2
JB
49 })
50
594bfb84
JB
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,
ec82cfa1 56 './tests/worker-files/thread/testWorker.js'
594bfb84
JB
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(
e843b904
JB
69 max,
70 './tests/worker-files/thread/testWorker.js'
71 )
594bfb84
JB
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 }
e843b904
JB
123 await pool.destroy()
124 })
125
10fcfaf4 126 it('Verify ROUND_ROBIN strategy default tasks usage statistics requirements', async () => {
594bfb84 127 const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN
10fcfaf4
JB
128 let pool = new FixedThreadPool(
129 max,
d710242d 130 './tests/worker-files/thread/testWorker.js',
594bfb84 131 { workerChoiceStrategy }
10fcfaf4 132 )
10fcfaf4 133 expect(
97a2abc3 134 pool.workerChoiceStrategyContext.getRequiredStatistics().runTime
10fcfaf4 135 ).toBe(false)
c6bd2650
JB
136 expect(
137 pool.workerChoiceStrategyContext.getRequiredStatistics().avgRunTime
138 ).toBe(false)
78099a15
JB
139 expect(
140 pool.workerChoiceStrategyContext.getRequiredStatistics().medRunTime
141 ).toBe(false)
fd7ebd49 142 await pool.destroy()
10fcfaf4
JB
143 pool = new DynamicThreadPool(
144 min,
145 max,
d710242d 146 './tests/worker-files/thread/testWorker.js',
594bfb84 147 { workerChoiceStrategy }
10fcfaf4 148 )
10fcfaf4 149 expect(
97a2abc3 150 pool.workerChoiceStrategyContext.getRequiredStatistics().runTime
10fcfaf4 151 ).toBe(false)
c6bd2650
JB
152 expect(
153 pool.workerChoiceStrategyContext.getRequiredStatistics().avgRunTime
154 ).toBe(false)
78099a15
JB
155 expect(
156 pool.workerChoiceStrategyContext.getRequiredStatistics().medRunTime
157 ).toBe(false)
10fcfaf4
JB
158 // We need to clean up the resources after our test
159 await pool.destroy()
160 })
161
bdaf31cd 162 it('Verify ROUND_ROBIN strategy can be run in a fixed pool', async () => {
bdaf31cd
JB
163 const pool = new FixedThreadPool(
164 max,
165 './tests/worker-files/thread/testWorker.js',
166 { workerChoiceStrategy: WorkerChoiceStrategies.ROUND_ROBIN }
167 )
bdaf31cd
JB
168 // TODO: Create a better test to cover `RoundRobinWorkerChoiceStrategy#choose`
169 const promises = []
170 for (let i = 0; i < max * 2; i++) {
6db75ad9 171 promises.push(pool.execute())
bdaf31cd
JB
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 () => {
bdaf31cd
JB
179 const pool = new DynamicThreadPool(
180 min,
181 max,
182 './tests/worker-files/thread/testWorker.js',
183 { workerChoiceStrategy: WorkerChoiceStrategies.ROUND_ROBIN }
184 )
bdaf31cd
JB
185 // TODO: Create a better test to cover `RoundRobinWorkerChoiceStrategy#choose`
186 const promises = []
187 for (let i = 0; i < max * 2; i++) {
6db75ad9 188 promises.push(pool.execute())
bdaf31cd
JB
189 }
190 await Promise.all(promises)
191 // We need to clean up the resources after our test
192 await pool.destroy()
193 })
194
2ced693a 195 it('Verify ROUND_ROBIN strategy runtime behavior', async () => {
594bfb84 196 const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN
2ced693a
JB
197 let pool = new FixedClusterPool(
198 max,
594bfb84
JB
199 './tests/worker-files/cluster/testWorker.js',
200 { workerChoiceStrategy }
2ced693a
JB
201 )
202 let results = new Set()
203 for (let i = 0; i < max; i++) {
adc3c320 204 results.add(pool.chooseWorkerNode()[1].worker.id)
2ced693a
JB
205 }
206 expect(results.size).toBe(max)
207 await pool.destroy()
594bfb84
JB
208 pool = new FixedThreadPool(
209 max,
210 './tests/worker-files/thread/testWorker.js',
211 { workerChoiceStrategy }
212 )
2ced693a
JB
213 results = new Set()
214 for (let i = 0; i < max; i++) {
adc3c320 215 results.add(pool.chooseWorkerNode()[1].worker.threadId)
2ced693a
JB
216 }
217 expect(results.size).toBe(max)
218 await pool.destroy()
219 })
220
a6f7f1b4 221 it('Verify ROUND_ROBIN strategy internals are resets after setting it', async () => {
594bfb84 222 const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN
a6f7f1b4
JB
223 let pool = new FixedThreadPool(
224 max,
225 './tests/worker-files/thread/testWorker.js',
226 { workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN }
227 )
38f6e859 228 expect(
95c83464 229 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 230 workerChoiceStrategy
f06e48d8 231 ).nextWorkerNodeId
b529c323 232 ).toBeDefined()
594bfb84 233 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
a6f7f1b4 234 expect(
95c83464 235 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
d710242d 236 pool.workerChoiceStrategyContext.workerChoiceStrategy
f06e48d8 237 ).nextWorkerNodeId
a6f7f1b4
JB
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 )
38f6e859 246 expect(
95c83464 247 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 248 workerChoiceStrategy
f06e48d8 249 ).nextWorkerNodeId
b529c323 250 ).toBeDefined()
594bfb84 251 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
a6f7f1b4 252 expect(
95c83464 253 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
d710242d 254 pool.workerChoiceStrategyContext.workerChoiceStrategy
f06e48d8 255 ).nextWorkerNodeId
a6f7f1b4
JB
256 ).toBe(0)
257 // We need to clean up the resources after our test
258 await pool.destroy()
259 })
260
737c6d97 261 it('Verify LESS_USED strategy default tasks usage statistics requirements', async () => {
594bfb84 262 const workerChoiceStrategy = WorkerChoiceStrategies.LESS_USED
10fcfaf4
JB
263 let pool = new FixedThreadPool(
264 max,
d710242d 265 './tests/worker-files/thread/testWorker.js',
594bfb84 266 { workerChoiceStrategy }
10fcfaf4 267 )
10fcfaf4 268 expect(
97a2abc3 269 pool.workerChoiceStrategyContext.getRequiredStatistics().runTime
10fcfaf4 270 ).toBe(false)
c6bd2650
JB
271 expect(
272 pool.workerChoiceStrategyContext.getRequiredStatistics().avgRunTime
273 ).toBe(false)
78099a15
JB
274 expect(
275 pool.workerChoiceStrategyContext.getRequiredStatistics().medRunTime
276 ).toBe(false)
fd7ebd49 277 await pool.destroy()
10fcfaf4
JB
278 pool = new DynamicThreadPool(
279 min,
280 max,
d710242d 281 './tests/worker-files/thread/testWorker.js',
594bfb84 282 { workerChoiceStrategy }
10fcfaf4 283 )
10fcfaf4 284 expect(
97a2abc3 285 pool.workerChoiceStrategyContext.getRequiredStatistics().runTime
10fcfaf4 286 ).toBe(false)
c6bd2650
JB
287 expect(
288 pool.workerChoiceStrategyContext.getRequiredStatistics().avgRunTime
289 ).toBe(false)
78099a15
JB
290 expect(
291 pool.workerChoiceStrategyContext.getRequiredStatistics().medRunTime
292 ).toBe(false)
10fcfaf4
JB
293 // We need to clean up the resources after our test
294 await pool.destroy()
295 })
296
737c6d97 297 it('Verify LESS_USED strategy can be run in a fixed pool', async () => {
b98ec2e6
JB
298 const pool = new FixedThreadPool(
299 max,
300 './tests/worker-files/thread/testWorker.js',
737c6d97 301 { workerChoiceStrategy: WorkerChoiceStrategies.LESS_USED }
b98ec2e6 302 )
168c526f 303 // TODO: Create a better test to cover `LessUsedWorkerChoiceStrategy#choose`
a35560ba
S
304 const promises = []
305 for (let i = 0; i < max * 2; i++) {
6db75ad9 306 promises.push(pool.execute())
a35560ba
S
307 }
308 await Promise.all(promises)
a35560ba
S
309 // We need to clean up the resources after our test
310 await pool.destroy()
311 })
312
737c6d97 313 it('Verify LESS_USED strategy can be run in a dynamic pool', async () => {
ff5e76e1
JB
314 const pool = new DynamicThreadPool(
315 min,
316 max,
317 './tests/worker-files/thread/testWorker.js',
737c6d97 318 { workerChoiceStrategy: WorkerChoiceStrategies.LESS_USED }
ff5e76e1 319 )
168c526f
JB
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
168c526f 330 it('Verify LESS_BUSY strategy default tasks usage statistics requirements', async () => {
594bfb84 331 const workerChoiceStrategy = WorkerChoiceStrategies.LESS_BUSY
168c526f
JB
332 let pool = new FixedThreadPool(
333 max,
d710242d 334 './tests/worker-files/thread/testWorker.js',
594bfb84 335 { workerChoiceStrategy }
168c526f 336 )
168c526f 337 expect(
97a2abc3 338 pool.workerChoiceStrategyContext.getRequiredStatistics().runTime
168c526f 339 ).toBe(true)
c6bd2650
JB
340 expect(
341 pool.workerChoiceStrategyContext.getRequiredStatistics().avgRunTime
342 ).toBe(false)
78099a15
JB
343 expect(
344 pool.workerChoiceStrategyContext.getRequiredStatistics().medRunTime
345 ).toBe(false)
168c526f
JB
346 await pool.destroy()
347 pool = new DynamicThreadPool(
348 min,
349 max,
d710242d 350 './tests/worker-files/thread/testWorker.js',
594bfb84 351 { workerChoiceStrategy }
168c526f 352 )
168c526f 353 expect(
97a2abc3 354 pool.workerChoiceStrategyContext.getRequiredStatistics().runTime
168c526f 355 ).toBe(true)
c6bd2650
JB
356 expect(
357 pool.workerChoiceStrategyContext.getRequiredStatistics().avgRunTime
358 ).toBe(false)
78099a15
JB
359 expect(
360 pool.workerChoiceStrategyContext.getRequiredStatistics().medRunTime
361 ).toBe(false)
168c526f
JB
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`
ff5e76e1
JB
390 const promises = []
391 for (let i = 0; i < max * 2; i++) {
6db75ad9 392 promises.push(pool.execute())
ff5e76e1
JB
393 }
394 await Promise.all(promises)
ff5e76e1
JB
395 // We need to clean up the resources after our test
396 await pool.destroy()
397 })
398
10fcfaf4 399 it('Verify FAIR_SHARE strategy default tasks usage statistics requirements', async () => {
594bfb84 400 const workerChoiceStrategy = WorkerChoiceStrategies.FAIR_SHARE
10fcfaf4
JB
401 let pool = new FixedThreadPool(
402 max,
d710242d 403 './tests/worker-files/thread/testWorker.js',
594bfb84 404 { workerChoiceStrategy }
10fcfaf4 405 )
10fcfaf4 406 expect(
97a2abc3 407 pool.workerChoiceStrategyContext.getRequiredStatistics().runTime
10fcfaf4 408 ).toBe(true)
c6bd2650
JB
409 expect(
410 pool.workerChoiceStrategyContext.getRequiredStatistics().avgRunTime
411 ).toBe(true)
78099a15
JB
412 expect(
413 pool.workerChoiceStrategyContext.getRequiredStatistics().medRunTime
414 ).toBe(false)
fd7ebd49 415 await pool.destroy()
10fcfaf4
JB
416 pool = new DynamicThreadPool(
417 min,
418 max,
d710242d 419 './tests/worker-files/thread/testWorker.js',
594bfb84 420 { workerChoiceStrategy }
10fcfaf4 421 )
10fcfaf4 422 expect(
97a2abc3 423 pool.workerChoiceStrategyContext.getRequiredStatistics().runTime
10fcfaf4 424 ).toBe(true)
c6bd2650
JB
425 expect(
426 pool.workerChoiceStrategyContext.getRequiredStatistics().avgRunTime
427 ).toBe(true)
78099a15
JB
428 expect(
429 pool.workerChoiceStrategyContext.getRequiredStatistics().medRunTime
430 ).toBe(false)
10fcfaf4
JB
431 // We need to clean up the resources after our test
432 await pool.destroy()
433 })
434
23ff945a 435 it('Verify FAIR_SHARE strategy can be run in a fixed pool', async () => {
23ff945a
JB
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++) {
6db75ad9 444 promises.push(pool.execute())
23ff945a
JB
445 }
446 await Promise.all(promises)
97a2abc3 447 expect(
95c83464 448 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
d710242d 449 pool.workerChoiceStrategyContext.workerChoiceStrategy
95c83464 450 ).workerLastVirtualTaskTimestamp.size
f06e48d8 451 ).toBe(pool.workerNodes.length)
23ff945a
JB
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 () => {
23ff945a
JB
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 = []
f7070eee 465 const maxMultiplier = 2
804a889e 466 for (let i = 0; i < max * maxMultiplier; i++) {
6db75ad9 467 promises.push(pool.execute())
23ff945a
JB
468 }
469 await Promise.all(promises)
f7070eee
JB
470 // if (process.platform !== 'win32') {
471 // expect(
95c83464 472 // pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
d710242d 473 // pool.workerChoiceStrategyContext.workerChoiceStrategy
95c83464 474 // ).workerLastVirtualTaskTimestamp.size
f06e48d8 475 // ).toBe(pool.workerNodes.length)
f7070eee 476 // }
23ff945a
JB
477 // We need to clean up the resources after our test
478 await pool.destroy()
479 })
480
010d7020
JB
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
a6f7f1b4 517 it('Verify FAIR_SHARE strategy internals are resets after setting it', async () => {
594bfb84 518 const workerChoiceStrategy = WorkerChoiceStrategies.FAIR_SHARE
f0829c53 519 let pool = new FixedThreadPool(
caeb9817
JB
520 max,
521 './tests/worker-files/thread/testWorker.js'
522 )
523 expect(
95c83464 524 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 525 workerChoiceStrategy
b529c323
JB
526 ).workerLastVirtualTaskTimestamp
527 ).toBeDefined()
594bfb84 528 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
f06e48d8 529 for (const workerNodeKey of pool.workerChoiceStrategyContext.workerChoiceStrategies
d710242d 530 .get(pool.workerChoiceStrategyContext.workerChoiceStrategy)
95c83464 531 .workerLastVirtualTaskTimestamp.keys()) {
caeb9817 532 expect(
95c83464 533 pool.workerChoiceStrategyContext.workerChoiceStrategies
d710242d 534 .get(pool.workerChoiceStrategyContext.workerChoiceStrategy)
f06e48d8 535 .workerLastVirtualTaskTimestamp.get(workerNodeKey).start
caeb9817
JB
536 ).toBe(0)
537 expect(
95c83464 538 pool.workerChoiceStrategyContext.workerChoiceStrategies
d710242d 539 .get(pool.workerChoiceStrategyContext.workerChoiceStrategy)
f06e48d8 540 .workerLastVirtualTaskTimestamp.get(workerNodeKey).end
caeb9817
JB
541 ).toBe(0)
542 }
f0829c53
JB
543 await pool.destroy()
544 pool = new DynamicThreadPool(
545 min,
546 max,
547 './tests/worker-files/thread/testWorker.js'
548 )
549 expect(
95c83464 550 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 551 workerChoiceStrategy
b529c323
JB
552 ).workerLastVirtualTaskTimestamp
553 ).toBeDefined()
594bfb84 554 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
f06e48d8 555 for (const workerNodeKey of pool.workerChoiceStrategyContext.workerChoiceStrategies
d710242d 556 .get(pool.workerChoiceStrategyContext.workerChoiceStrategy)
95c83464 557 .workerLastVirtualTaskTimestamp.keys()) {
f0829c53 558 expect(
95c83464 559 pool.workerChoiceStrategyContext.workerChoiceStrategies
d710242d 560 .get(pool.workerChoiceStrategyContext.workerChoiceStrategy)
f06e48d8 561 .workerLastVirtualTaskTimestamp.get(workerNodeKey).start
f0829c53
JB
562 ).toBe(0)
563 expect(
95c83464 564 pool.workerChoiceStrategyContext.workerChoiceStrategies
d710242d 565 .get(pool.workerChoiceStrategyContext.workerChoiceStrategy)
f06e48d8 566 .workerLastVirtualTaskTimestamp.get(workerNodeKey).end
f0829c53
JB
567 ).toBe(0)
568 }
caeb9817
JB
569 // We need to clean up the resources after our test
570 await pool.destroy()
571 })
572
10fcfaf4 573 it('Verify WEIGHTED_ROUND_ROBIN strategy default tasks usage statistics requirements', async () => {
594bfb84 574 const workerChoiceStrategy = WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
10fcfaf4
JB
575 let pool = new FixedThreadPool(
576 max,
d710242d 577 './tests/worker-files/thread/testWorker.js',
594bfb84 578 { workerChoiceStrategy }
10fcfaf4 579 )
10fcfaf4 580 expect(
97a2abc3 581 pool.workerChoiceStrategyContext.getRequiredStatistics().runTime
10fcfaf4 582 ).toBe(true)
c6bd2650
JB
583 expect(
584 pool.workerChoiceStrategyContext.getRequiredStatistics().avgRunTime
585 ).toBe(true)
78099a15
JB
586 expect(
587 pool.workerChoiceStrategyContext.getRequiredStatistics().medRunTime
588 ).toBe(false)
fd7ebd49 589 await pool.destroy()
10fcfaf4
JB
590 pool = new DynamicThreadPool(
591 min,
592 max,
d710242d 593 './tests/worker-files/thread/testWorker.js',
594bfb84 594 { workerChoiceStrategy }
10fcfaf4 595 )
10fcfaf4 596 expect(
97a2abc3 597 pool.workerChoiceStrategyContext.getRequiredStatistics().runTime
10fcfaf4 598 ).toBe(true)
c6bd2650
JB
599 expect(
600 pool.workerChoiceStrategyContext.getRequiredStatistics().avgRunTime
601 ).toBe(true)
78099a15
JB
602 expect(
603 pool.workerChoiceStrategyContext.getRequiredStatistics().medRunTime
604 ).toBe(false)
10fcfaf4
JB
605 // We need to clean up the resources after our test
606 await pool.destroy()
607 })
608
b3432a63 609 it('Verify WEIGHTED_ROUND_ROBIN strategy can be run in a fixed pool', async () => {
b3432a63
JB
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++) {
6db75ad9 618 promises.push(pool.execute())
b3432a63
JB
619 }
620 await Promise.all(promises)
97a2abc3 621 expect(
95c83464 622 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
d710242d 623 pool.workerChoiceStrategyContext.workerChoiceStrategy
95c83464 624 ).workersTaskRunTime.size
f06e48d8 625 ).toBe(pool.workerNodes.length)
b3432a63
JB
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 () => {
b3432a63
JB
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 = []
5502c07c 639 const maxMultiplier =
95c83464 640 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
d710242d 641 pool.workerChoiceStrategyContext.workerChoiceStrategy
8da9e84d 642 ).defaultWorkerWeight * 50
5502c07c 643 for (let i = 0; i < max * maxMultiplier; i++) {
6db75ad9 644 promises.push(pool.execute())
b3432a63
JB
645 }
646 await Promise.all(promises)
9f34a585
JB
647 if (process.platform !== 'win32') {
648 expect(
95c83464 649 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
d710242d 650 pool.workerChoiceStrategyContext.workerChoiceStrategy
95c83464 651 ).workersTaskRunTime.size
f06e48d8 652 ).toBe(pool.workerNodes.length)
9f34a585 653 }
b3432a63
JB
654 // We need to clean up the resources after our test
655 await pool.destroy()
656 })
657
010d7020
JB
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
a6f7f1b4 694 it('Verify WEIGHTED_ROUND_ROBIN strategy internals are resets after setting it', async () => {
594bfb84 695 const workerChoiceStrategy = WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
f0829c53 696 let pool = new FixedThreadPool(
caeb9817
JB
697 max,
698 './tests/worker-files/thread/testWorker.js'
699 )
38f6e859 700 expect(
95c83464 701 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 702 workerChoiceStrategy
f06e48d8 703 ).currentWorkerNodeId
b529c323 704 ).toBeDefined()
38f6e859 705 expect(
95c83464 706 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 707 workerChoiceStrategy
b529c323
JB
708 ).defaultWorkerWeight
709 ).toBeDefined()
caeb9817 710 expect(
95c83464 711 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 712 workerChoiceStrategy
b529c323
JB
713 ).workersTaskRunTime
714 ).toBeDefined()
594bfb84 715 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
a6f7f1b4 716 expect(
95c83464 717 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
d710242d 718 pool.workerChoiceStrategyContext.workerChoiceStrategy
f06e48d8 719 ).currentWorkerNodeId
a6f7f1b4
JB
720 ).toBe(0)
721 expect(
95c83464 722 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
d710242d 723 pool.workerChoiceStrategyContext.workerChoiceStrategy
95c83464 724 ).defaultWorkerWeight
a6f7f1b4 725 ).toBeGreaterThan(0)
f06e48d8 726 for (const workerNodeKey of pool.workerChoiceStrategyContext.workerChoiceStrategies
d710242d 727 .get(pool.workerChoiceStrategyContext.workerChoiceStrategy)
95c83464 728 .workersTaskRunTime.keys()) {
caeb9817 729 expect(
95c83464 730 pool.workerChoiceStrategyContext.workerChoiceStrategies
d710242d 731 .get(pool.workerChoiceStrategyContext.workerChoiceStrategy)
f06e48d8 732 .workersTaskRunTime.get(workerNodeKey).runTime
caeb9817
JB
733 ).toBe(0)
734 }
f0829c53
JB
735 await pool.destroy()
736 pool = new DynamicThreadPool(
737 min,
738 max,
739 './tests/worker-files/thread/testWorker.js'
740 )
38f6e859 741 expect(
95c83464 742 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 743 workerChoiceStrategy
f06e48d8 744 ).currentWorkerNodeId
b529c323 745 ).toBeDefined()
38f6e859 746 expect(
95c83464 747 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 748 workerChoiceStrategy
b529c323
JB
749 ).defaultWorkerWeight
750 ).toBeDefined()
f0829c53 751 expect(
95c83464 752 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 753 workerChoiceStrategy
b529c323
JB
754 ).workersTaskRunTime
755 ).toBeDefined()
594bfb84 756 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
a6f7f1b4 757 expect(
95c83464 758 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
d710242d 759 pool.workerChoiceStrategyContext.workerChoiceStrategy
f06e48d8 760 ).currentWorkerNodeId
a6f7f1b4
JB
761 ).toBe(0)
762 expect(
95c83464 763 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
d710242d 764 pool.workerChoiceStrategyContext.workerChoiceStrategy
95c83464 765 ).defaultWorkerWeight
a6f7f1b4 766 ).toBeGreaterThan(0)
f06e48d8 767 for (const workerNodeKey of pool.workerChoiceStrategyContext.workerChoiceStrategies
d710242d 768 .get(pool.workerChoiceStrategyContext.workerChoiceStrategy)
95c83464 769 .workersTaskRunTime.keys()) {
f0829c53 770 expect(
95c83464 771 pool.workerChoiceStrategyContext.workerChoiceStrategies
d710242d 772 .get(pool.workerChoiceStrategyContext.workerChoiceStrategy)
f06e48d8 773 .workersTaskRunTime.get(workerNodeKey).runTime
f0829c53
JB
774 ).toBe(0)
775 }
caeb9817
JB
776 // We need to clean up the resources after our test
777 await pool.destroy()
778 })
779
89b09b26 780 it('Verify unknown strategy throw error', () => {
a35560ba
S
781 expect(
782 () =>
783 new DynamicThreadPool(
784 min,
785 max,
786 './tests/worker-files/thread/testWorker.js',
1927ee67 787 { workerChoiceStrategy: 'UNKNOWN_STRATEGY' }
a35560ba 788 )
d4aeae5a 789 ).toThrowError("Invalid worker choice strategy 'UNKNOWN_STRATEGY'")
a35560ba
S
790 })
791})