test: improve worker choice strategies testing
[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
cdace0e5 7} = require('../../../lib')
86bf340d 8const { CircularArray } = require('../../../lib/circular-array')
a35560ba
S
9
10describe('Selection strategies test suite', () => {
e1ffb94f
JB
11 const min = 0
12 const max = 3
13
a35560ba
S
14 it('Verify that WorkerChoiceStrategies enumeration provides string values', () => {
15 expect(WorkerChoiceStrategies.ROUND_ROBIN).toBe('ROUND_ROBIN')
e4543b14
JB
16 expect(WorkerChoiceStrategies.LEAST_USED).toBe('LEAST_USED')
17 expect(WorkerChoiceStrategies.LEAST_BUSY).toBe('LEAST_BUSY')
23ff945a 18 expect(WorkerChoiceStrategies.FAIR_SHARE).toBe('FAIR_SHARE')
b3432a63
JB
19 expect(WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN).toBe(
20 'WEIGHTED_ROUND_ROBIN'
21 )
a35560ba
S
22 })
23
e843b904 24 it('Verify ROUND_ROBIN strategy is the default at pool creation', async () => {
e843b904
JB
25 const pool = new DynamicThreadPool(
26 min,
27 max,
28 './tests/worker-files/thread/testWorker.js'
29 )
30 expect(pool.opts.workerChoiceStrategy).toBe(
31 WorkerChoiceStrategies.ROUND_ROBIN
32 )
33 // We need to clean up the resources after our test
34 await pool.destroy()
35 })
36
594bfb84
JB
37 it('Verify available strategies are taken at pool creation', async () => {
38 for (const workerChoiceStrategy of Object.values(WorkerChoiceStrategies)) {
39 const pool = new FixedThreadPool(
40 max,
41 './tests/worker-files/thread/testWorker.js',
42 { workerChoiceStrategy }
43 )
44 expect(pool.opts.workerChoiceStrategy).toBe(workerChoiceStrategy)
45 expect(pool.workerChoiceStrategyContext.workerChoiceStrategy).toBe(
46 workerChoiceStrategy
47 )
48 await pool.destroy()
49 }
d2f7b7a2
JB
50 })
51
594bfb84
JB
52 it('Verify available strategies can be set after pool creation', async () => {
53 for (const workerChoiceStrategy of Object.values(WorkerChoiceStrategies)) {
54 const pool = new DynamicThreadPool(
55 min,
56 max,
ec82cfa1 57 './tests/worker-files/thread/testWorker.js'
594bfb84
JB
58 )
59 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
60 expect(pool.opts.workerChoiceStrategy).toBe(workerChoiceStrategy)
61 expect(pool.workerChoiceStrategyContext.workerChoiceStrategy).toBe(
62 workerChoiceStrategy
63 )
64 await pool.destroy()
65 }
66 })
67
68 it('Verify available strategies default internals at pool creation', async () => {
69 const pool = new FixedThreadPool(
e843b904
JB
70 max,
71 './tests/worker-files/thread/testWorker.js'
72 )
594bfb84
JB
73 for (const workerChoiceStrategy of Object.values(WorkerChoiceStrategies)) {
74 if (workerChoiceStrategy === WorkerChoiceStrategies.ROUND_ROBIN) {
75 expect(
76 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
77 workerChoiceStrategy
78 ).nextWorkerNodeId
79 ).toBe(0)
80 } else if (workerChoiceStrategy === WorkerChoiceStrategies.FAIR_SHARE) {
08f3f44c
JB
81 expect(
82 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
83 workerChoiceStrategy
b0d6ed8f 84 ).workersVirtualTaskEndTimestamp
08f3f44c
JB
85 ).toBeInstanceOf(Array)
86 expect(
87 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
88 workerChoiceStrategy
b0d6ed8f 89 ).workersVirtualTaskEndTimestamp.length
08f3f44c 90 ).toBe(0)
594bfb84
JB
91 } else if (
92 workerChoiceStrategy === WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
93 ) {
94 expect(
95 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
96 workerChoiceStrategy
97 ).currentWorkerNodeId
98 ).toBe(0)
99 expect(
100 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
101 workerChoiceStrategy
102 ).defaultWorkerWeight
103 ).toBeGreaterThan(0)
08f3f44c
JB
104 expect(
105 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
106 workerChoiceStrategy
107 ).workerVirtualTaskRunTime
108 ).toBe(0)
594bfb84
JB
109 }
110 }
e843b904
JB
111 await pool.destroy()
112 })
113
10fcfaf4 114 it('Verify ROUND_ROBIN strategy default tasks usage statistics requirements', async () => {
594bfb84 115 const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN
10fcfaf4
JB
116 let pool = new FixedThreadPool(
117 max,
d710242d 118 './tests/worker-files/thread/testWorker.js',
594bfb84 119 { workerChoiceStrategy }
10fcfaf4 120 )
10fcfaf4 121 expect(
86bf340d
JB
122 pool.workerChoiceStrategyContext.getRequiredStatistics()
123 ).toStrictEqual({
124 runTime: false,
125 avgRunTime: false,
126 medRunTime: false,
127 waitTime: false,
128 avgWaitTime: false,
129 medWaitTime: false
130 })
fd7ebd49 131 await pool.destroy()
10fcfaf4
JB
132 pool = new DynamicThreadPool(
133 min,
134 max,
d710242d 135 './tests/worker-files/thread/testWorker.js',
594bfb84 136 { workerChoiceStrategy }
10fcfaf4 137 )
10fcfaf4 138 expect(
86bf340d
JB
139 pool.workerChoiceStrategyContext.getRequiredStatistics()
140 ).toStrictEqual({
141 runTime: false,
142 avgRunTime: false,
143 medRunTime: false,
144 waitTime: false,
145 avgWaitTime: false,
146 medWaitTime: false
147 })
10fcfaf4
JB
148 // We need to clean up the resources after our test
149 await pool.destroy()
150 })
151
bdaf31cd 152 it('Verify ROUND_ROBIN strategy can be run in a fixed pool', async () => {
bdaf31cd
JB
153 const pool = new FixedThreadPool(
154 max,
155 './tests/worker-files/thread/testWorker.js',
156 { workerChoiceStrategy: WorkerChoiceStrategies.ROUND_ROBIN }
157 )
bdaf31cd 158 // TODO: Create a better test to cover `RoundRobinWorkerChoiceStrategy#choose`
e211bc18 159 const promises = []
a20f0ba5
JB
160 const maxMultiplier = 2
161 for (let i = 0; i < max * maxMultiplier; i++) {
e211bc18
JB
162 promises.push(pool.execute())
163 }
164 await Promise.all(promises)
165 for (const workerNode of pool.workerNodes) {
166 expect(workerNode.tasksUsage).toStrictEqual({
167 run: expect.any(Number),
168 running: 0,
169 runTime: 0,
170 runTimeHistory: expect.any(CircularArray),
171 avgRunTime: 0,
172 medRunTime: 0,
173 waitTime: 0,
174 waitTimeHistory: expect.any(CircularArray),
175 avgWaitTime: 0,
176 medWaitTime: 0,
177 error: 0
178 })
179 expect(workerNode.tasksUsage.run).toBeGreaterThan(0)
bdaf31cd 180 }
bdaf31cd
JB
181 // We need to clean up the resources after our test
182 await pool.destroy()
183 })
184
185 it('Verify ROUND_ROBIN strategy can be run in a dynamic pool', async () => {
bdaf31cd
JB
186 const pool = new DynamicThreadPool(
187 min,
188 max,
189 './tests/worker-files/thread/testWorker.js',
190 { workerChoiceStrategy: WorkerChoiceStrategies.ROUND_ROBIN }
191 )
bdaf31cd 192 // TODO: Create a better test to cover `RoundRobinWorkerChoiceStrategy#choose`
e211bc18 193 const promises = []
a20f0ba5
JB
194 const maxMultiplier = 2
195 for (let i = 0; i < max * maxMultiplier; i++) {
e211bc18
JB
196 promises.push(pool.execute())
197 }
198 await Promise.all(promises)
199 for (const workerNode of pool.workerNodes) {
200 expect(workerNode.tasksUsage).toStrictEqual({
201 run: expect.any(Number),
202 running: 0,
203 runTime: 0,
204 runTimeHistory: expect.any(CircularArray),
205 avgRunTime: 0,
206 medRunTime: 0,
207 waitTime: 0,
208 waitTimeHistory: expect.any(CircularArray),
209 avgWaitTime: 0,
210 medWaitTime: 0,
211 error: 0
212 })
213 expect(workerNode.tasksUsage.run).toBeGreaterThan(0)
bdaf31cd 214 }
bdaf31cd
JB
215 // We need to clean up the resources after our test
216 await pool.destroy()
217 })
218
2ced693a 219 it('Verify ROUND_ROBIN strategy runtime behavior', async () => {
594bfb84 220 const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN
2ced693a
JB
221 let pool = new FixedClusterPool(
222 max,
594bfb84
JB
223 './tests/worker-files/cluster/testWorker.js',
224 { workerChoiceStrategy }
2ced693a
JB
225 )
226 let results = new Set()
227 for (let i = 0; i < max; i++) {
20dcad1a 228 results.add(pool.workerNodes[pool.chooseWorkerNode()].worker.id)
2ced693a
JB
229 }
230 expect(results.size).toBe(max)
231 await pool.destroy()
594bfb84
JB
232 pool = new FixedThreadPool(
233 max,
234 './tests/worker-files/thread/testWorker.js',
235 { workerChoiceStrategy }
236 )
2ced693a
JB
237 results = new Set()
238 for (let i = 0; i < max; i++) {
20dcad1a 239 results.add(pool.workerNodes[pool.chooseWorkerNode()].worker.threadId)
2ced693a
JB
240 }
241 expect(results.size).toBe(max)
242 await pool.destroy()
243 })
244
a6f7f1b4 245 it('Verify ROUND_ROBIN strategy internals are resets after setting it', async () => {
594bfb84 246 const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN
a6f7f1b4
JB
247 let pool = new FixedThreadPool(
248 max,
249 './tests/worker-files/thread/testWorker.js',
250 { workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN }
251 )
38f6e859 252 expect(
95c83464 253 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 254 workerChoiceStrategy
f06e48d8 255 ).nextWorkerNodeId
b529c323 256 ).toBeDefined()
594bfb84 257 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
a6f7f1b4 258 expect(
95c83464 259 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
d710242d 260 pool.workerChoiceStrategyContext.workerChoiceStrategy
f06e48d8 261 ).nextWorkerNodeId
a6f7f1b4
JB
262 ).toBe(0)
263 await pool.destroy()
264 pool = new DynamicThreadPool(
265 min,
266 max,
267 './tests/worker-files/thread/testWorker.js',
268 { workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN }
269 )
38f6e859 270 expect(
95c83464 271 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 272 workerChoiceStrategy
f06e48d8 273 ).nextWorkerNodeId
b529c323 274 ).toBeDefined()
594bfb84 275 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
a6f7f1b4 276 expect(
95c83464 277 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
d710242d 278 pool.workerChoiceStrategyContext.workerChoiceStrategy
f06e48d8 279 ).nextWorkerNodeId
a6f7f1b4
JB
280 ).toBe(0)
281 // We need to clean up the resources after our test
282 await pool.destroy()
283 })
284
e4543b14
JB
285 it('Verify LEAST_USED strategy default tasks usage statistics requirements', async () => {
286 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_USED
10fcfaf4
JB
287 let pool = new FixedThreadPool(
288 max,
d710242d 289 './tests/worker-files/thread/testWorker.js',
594bfb84 290 { workerChoiceStrategy }
10fcfaf4 291 )
10fcfaf4 292 expect(
86bf340d
JB
293 pool.workerChoiceStrategyContext.getRequiredStatistics()
294 ).toStrictEqual({
295 runTime: false,
296 avgRunTime: false,
297 medRunTime: false,
298 waitTime: false,
299 avgWaitTime: false,
300 medWaitTime: false
301 })
fd7ebd49 302 await pool.destroy()
10fcfaf4
JB
303 pool = new DynamicThreadPool(
304 min,
305 max,
d710242d 306 './tests/worker-files/thread/testWorker.js',
594bfb84 307 { workerChoiceStrategy }
10fcfaf4 308 )
10fcfaf4 309 expect(
86bf340d
JB
310 pool.workerChoiceStrategyContext.getRequiredStatistics()
311 ).toStrictEqual({
312 runTime: false,
313 avgRunTime: false,
314 medRunTime: false,
315 waitTime: false,
316 avgWaitTime: false,
317 medWaitTime: false
318 })
10fcfaf4
JB
319 // We need to clean up the resources after our test
320 await pool.destroy()
321 })
322
e4543b14 323 it('Verify LEAST_USED strategy can be run in a fixed pool', async () => {
b98ec2e6
JB
324 const pool = new FixedThreadPool(
325 max,
326 './tests/worker-files/thread/testWorker.js',
e4543b14 327 { workerChoiceStrategy: WorkerChoiceStrategies.LEAST_USED }
b98ec2e6 328 )
e4543b14 329 // TODO: Create a better test to cover `LeastUsedWorkerChoiceStrategy#choose`
e211bc18 330 const promises = []
a20f0ba5
JB
331 const maxMultiplier = 2
332 for (let i = 0; i < max * maxMultiplier; i++) {
e211bc18
JB
333 promises.push(pool.execute())
334 }
335 await Promise.all(promises)
336 for (const workerNode of pool.workerNodes) {
337 expect(workerNode.tasksUsage).toStrictEqual({
338 run: expect.any(Number),
339 running: 0,
340 runTime: 0,
341 runTimeHistory: expect.any(CircularArray),
342 avgRunTime: 0,
343 medRunTime: 0,
344 waitTime: 0,
345 waitTimeHistory: expect.any(CircularArray),
346 avgWaitTime: 0,
347 medWaitTime: 0,
348 error: 0
349 })
350 expect(workerNode.tasksUsage.run).toBeGreaterThan(0)
a35560ba 351 }
a35560ba
S
352 // We need to clean up the resources after our test
353 await pool.destroy()
354 })
355
e4543b14 356 it('Verify LEAST_USED strategy can be run in a dynamic pool', async () => {
ff5e76e1
JB
357 const pool = new DynamicThreadPool(
358 min,
359 max,
360 './tests/worker-files/thread/testWorker.js',
e4543b14 361 { workerChoiceStrategy: WorkerChoiceStrategies.LEAST_USED }
ff5e76e1 362 )
e4543b14 363 // TODO: Create a better test to cover `LeastUsedWorkerChoiceStrategy#choose`
e211bc18 364 const promises = []
a20f0ba5
JB
365 const maxMultiplier = 2
366 for (let i = 0; i < max * maxMultiplier; i++) {
e211bc18
JB
367 promises.push(pool.execute())
368 }
369 await Promise.all(promises)
370 for (const workerNode of pool.workerNodes) {
371 expect(workerNode.tasksUsage).toStrictEqual({
372 run: expect.any(Number),
373 running: 0,
374 runTime: 0,
375 runTimeHistory: expect.any(CircularArray),
376 avgRunTime: 0,
377 medRunTime: 0,
378 waitTime: 0,
379 waitTimeHistory: expect.any(CircularArray),
380 avgWaitTime: 0,
381 medWaitTime: 0,
382 error: 0
383 })
384 expect(workerNode.tasksUsage.run).toBeGreaterThan(0)
168c526f 385 }
168c526f
JB
386 // We need to clean up the resources after our test
387 await pool.destroy()
388 })
389
e4543b14
JB
390 it('Verify LEAST_BUSY strategy default tasks usage statistics requirements', async () => {
391 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_BUSY
168c526f
JB
392 let pool = new FixedThreadPool(
393 max,
d710242d 394 './tests/worker-files/thread/testWorker.js',
594bfb84 395 { workerChoiceStrategy }
168c526f 396 )
168c526f 397 expect(
86bf340d
JB
398 pool.workerChoiceStrategyContext.getRequiredStatistics()
399 ).toStrictEqual({
400 runTime: true,
401 avgRunTime: false,
402 medRunTime: false,
403 waitTime: false,
404 avgWaitTime: false,
405 medWaitTime: false
406 })
168c526f
JB
407 await pool.destroy()
408 pool = new DynamicThreadPool(
409 min,
410 max,
d710242d 411 './tests/worker-files/thread/testWorker.js',
594bfb84 412 { workerChoiceStrategy }
168c526f 413 )
168c526f 414 expect(
86bf340d
JB
415 pool.workerChoiceStrategyContext.getRequiredStatistics()
416 ).toStrictEqual({
417 runTime: true,
418 avgRunTime: false,
419 medRunTime: false,
420 waitTime: false,
421 avgWaitTime: false,
422 medWaitTime: false
423 })
168c526f
JB
424 // We need to clean up the resources after our test
425 await pool.destroy()
426 })
427
e4543b14 428 it('Verify LEAST_BUSY strategy can be run in a fixed pool', async () => {
168c526f
JB
429 const pool = new FixedThreadPool(
430 max,
431 './tests/worker-files/thread/testWorker.js',
e4543b14 432 { workerChoiceStrategy: WorkerChoiceStrategies.LEAST_BUSY }
168c526f 433 )
e4543b14 434 // TODO: Create a better test to cover `LeastBusyWorkerChoiceStrategy#choose`
e211bc18 435 const promises = []
a20f0ba5
JB
436 const maxMultiplier = 2
437 for (let i = 0; i < max * maxMultiplier; i++) {
e211bc18
JB
438 promises.push(pool.execute())
439 }
440 await Promise.all(promises)
441 for (const workerNode of pool.workerNodes) {
442 expect(workerNode.tasksUsage).toStrictEqual({
443 run: expect.any(Number),
444 running: 0,
445 runTime: expect.any(Number),
446 runTimeHistory: expect.any(CircularArray),
447 avgRunTime: 0,
448 medRunTime: 0,
449 waitTime: 0,
450 waitTimeHistory: expect.any(CircularArray),
451 avgWaitTime: 0,
452 medWaitTime: 0,
453 error: 0
454 })
455 expect(workerNode.tasksUsage.run).toBeGreaterThan(0)
456 expect(workerNode.tasksUsage.runTime).toBeGreaterThan(0)
168c526f 457 }
168c526f
JB
458 // We need to clean up the resources after our test
459 await pool.destroy()
460 })
461
e4543b14 462 it('Verify LEAST_BUSY strategy can be run in a dynamic pool', async () => {
168c526f
JB
463 const pool = new DynamicThreadPool(
464 min,
465 max,
466 './tests/worker-files/thread/testWorker.js',
e4543b14 467 { workerChoiceStrategy: WorkerChoiceStrategies.LEAST_BUSY }
168c526f 468 )
e4543b14 469 // TODO: Create a better test to cover `LeastBusyWorkerChoiceStrategy#choose`
e211bc18 470 const promises = []
a20f0ba5
JB
471 const maxMultiplier = 2
472 for (let i = 0; i < max * maxMultiplier; i++) {
e211bc18
JB
473 promises.push(pool.execute())
474 }
475 await Promise.all(promises)
476 for (const workerNode of pool.workerNodes) {
477 expect(workerNode.tasksUsage).toStrictEqual({
478 run: expect.any(Number),
479 running: 0,
480 runTime: expect.any(Number),
481 runTimeHistory: expect.any(CircularArray),
482 avgRunTime: 0,
483 medRunTime: 0,
484 waitTime: 0,
485 waitTimeHistory: expect.any(CircularArray),
486 avgWaitTime: 0,
487 medWaitTime: 0,
488 error: 0
489 })
490 expect(workerNode.tasksUsage.run).toBeGreaterThan(0)
491 expect(workerNode.tasksUsage.runTime).toBeGreaterThan(0)
ff5e76e1 492 }
ff5e76e1
JB
493 // We need to clean up the resources after our test
494 await pool.destroy()
495 })
496
10fcfaf4 497 it('Verify FAIR_SHARE strategy default tasks usage statistics requirements', async () => {
594bfb84 498 const workerChoiceStrategy = WorkerChoiceStrategies.FAIR_SHARE
10fcfaf4
JB
499 let pool = new FixedThreadPool(
500 max,
d710242d 501 './tests/worker-files/thread/testWorker.js',
594bfb84 502 { workerChoiceStrategy }
10fcfaf4 503 )
10fcfaf4 504 expect(
86bf340d
JB
505 pool.workerChoiceStrategyContext.getRequiredStatistics()
506 ).toStrictEqual({
507 runTime: true,
508 avgRunTime: true,
509 medRunTime: false,
510 waitTime: false,
511 avgWaitTime: false,
512 medWaitTime: false
513 })
fd7ebd49 514 await pool.destroy()
10fcfaf4
JB
515 pool = new DynamicThreadPool(
516 min,
517 max,
d710242d 518 './tests/worker-files/thread/testWorker.js',
594bfb84 519 { workerChoiceStrategy }
10fcfaf4 520 )
10fcfaf4 521 expect(
86bf340d
JB
522 pool.workerChoiceStrategyContext.getRequiredStatistics()
523 ).toStrictEqual({
524 runTime: true,
525 avgRunTime: true,
526 medRunTime: false,
527 waitTime: false,
528 avgWaitTime: false,
529 medWaitTime: false
530 })
10fcfaf4
JB
531 // We need to clean up the resources after our test
532 await pool.destroy()
533 })
534
23ff945a 535 it('Verify FAIR_SHARE strategy can be run in a fixed pool', async () => {
23ff945a
JB
536 const pool = new FixedThreadPool(
537 max,
538 './tests/worker-files/thread/testWorker.js',
539 { workerChoiceStrategy: WorkerChoiceStrategies.FAIR_SHARE }
540 )
541 // TODO: Create a better test to cover `FairShareChoiceStrategy#choose`
e211bc18 542 const promises = []
a20f0ba5
JB
543 const maxMultiplier = 2
544 for (let i = 0; i < max * maxMultiplier; i++) {
e211bc18 545 promises.push(pool.execute())
23ff945a 546 }
e211bc18 547 await Promise.all(promises)
138d29a8 548 for (const workerNode of pool.workerNodes) {
86bf340d 549 expect(workerNode.tasksUsage).toStrictEqual({
e211bc18 550 run: expect.any(Number),
86bf340d
JB
551 running: 0,
552 runTime: expect.any(Number),
553 runTimeHistory: expect.any(CircularArray),
554 avgRunTime: expect.any(Number),
555 medRunTime: 0,
556 waitTime: 0,
557 waitTimeHistory: expect.any(CircularArray),
558 avgWaitTime: 0,
559 medWaitTime: 0,
560 error: 0
561 })
e211bc18
JB
562 expect(workerNode.tasksUsage.run).toBeGreaterThan(0)
563 expect(workerNode.tasksUsage.runTime).toBeGreaterThan(0)
564 expect(workerNode.tasksUsage.avgRunTime).toBeGreaterThan(0)
138d29a8 565 }
97a2abc3 566 expect(
95c83464 567 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
d710242d 568 pool.workerChoiceStrategyContext.workerChoiceStrategy
b0d6ed8f 569 ).workersVirtualTaskEndTimestamp.length
f06e48d8 570 ).toBe(pool.workerNodes.length)
23ff945a
JB
571 // We need to clean up the resources after our test
572 await pool.destroy()
573 })
574
575 it('Verify FAIR_SHARE strategy can be run in a dynamic pool', async () => {
23ff945a
JB
576 const pool = new DynamicThreadPool(
577 min,
578 max,
579 './tests/worker-files/thread/testWorker.js',
580 { workerChoiceStrategy: WorkerChoiceStrategies.FAIR_SHARE }
581 )
582 // TODO: Create a better test to cover `FairShareChoiceStrategy#choose`
e211bc18 583 const promises = []
f7070eee 584 const maxMultiplier = 2
804a889e 585 for (let i = 0; i < max * maxMultiplier; i++) {
e211bc18 586 promises.push(pool.execute())
23ff945a 587 }
e211bc18 588 await Promise.all(promises)
138d29a8 589 for (const workerNode of pool.workerNodes) {
86bf340d 590 expect(workerNode.tasksUsage).toStrictEqual({
e211bc18 591 run: expect.any(Number),
86bf340d
JB
592 running: 0,
593 runTime: expect.any(Number),
594 runTimeHistory: expect.any(CircularArray),
595 avgRunTime: expect.any(Number),
596 medRunTime: 0,
597 waitTime: 0,
598 waitTimeHistory: expect.any(CircularArray),
599 avgWaitTime: 0,
600 medWaitTime: 0,
601 error: 0
602 })
e211bc18
JB
603 expect(workerNode.tasksUsage.run).toBeGreaterThan(0)
604 expect(workerNode.tasksUsage.runTime).toBeGreaterThan(0)
605 expect(workerNode.tasksUsage.avgRunTime).toBeGreaterThan(0)
138d29a8 606 }
2b4fddb8
JB
607 expect(
608 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
609 pool.workerChoiceStrategyContext.workerChoiceStrategy
b0d6ed8f 610 ).workersVirtualTaskEndTimestamp.length
2b4fddb8 611 ).toBe(pool.workerNodes.length)
23ff945a
JB
612 // We need to clean up the resources after our test
613 await pool.destroy()
614 })
615
9e775f96 616 it('Verify FAIR_SHARE strategy can be run in a dynamic pool with median runtime statistic', async () => {
010d7020
JB
617 const pool = new DynamicThreadPool(
618 min,
619 max,
620 './tests/worker-files/thread/testWorker.js',
621 {
622 workerChoiceStrategy: WorkerChoiceStrategies.FAIR_SHARE,
623 workerChoiceStrategyOptions: {
624 medRunTime: true
625 }
626 }
627 )
628 // TODO: Create a better test to cover `FairShareChoiceStrategy#choose`
e211bc18 629 const promises = []
010d7020
JB
630 const maxMultiplier = 2
631 for (let i = 0; i < max * maxMultiplier; i++) {
e211bc18 632 promises.push(pool.execute())
010d7020 633 }
e211bc18 634 await Promise.all(promises)
010d7020 635 for (const workerNode of pool.workerNodes) {
86bf340d 636 expect(workerNode.tasksUsage).toStrictEqual({
e211bc18 637 run: expect.any(Number),
86bf340d
JB
638 running: 0,
639 runTime: expect.any(Number),
640 runTimeHistory: expect.any(CircularArray),
641 avgRunTime: 0,
642 medRunTime: expect.any(Number),
643 waitTime: 0,
644 waitTimeHistory: expect.any(CircularArray),
645 avgWaitTime: 0,
646 medWaitTime: 0,
647 error: 0
648 })
e211bc18
JB
649 expect(workerNode.tasksUsage.run).toBeGreaterThan(0)
650 expect(workerNode.tasksUsage.runTime).toBeGreaterThan(0)
651 expect(workerNode.tasksUsage.medRunTime).toBeGreaterThan(0)
010d7020 652 }
2b4fddb8
JB
653 expect(
654 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
655 pool.workerChoiceStrategyContext.workerChoiceStrategy
b0d6ed8f 656 ).workersVirtualTaskEndTimestamp.length
2b4fddb8 657 ).toBe(pool.workerNodes.length)
010d7020
JB
658 // We need to clean up the resources after our test
659 await pool.destroy()
660 })
661
a6f7f1b4 662 it('Verify FAIR_SHARE strategy internals are resets after setting it', async () => {
594bfb84 663 const workerChoiceStrategy = WorkerChoiceStrategies.FAIR_SHARE
f0829c53 664 let pool = new FixedThreadPool(
caeb9817
JB
665 max,
666 './tests/worker-files/thread/testWorker.js'
667 )
668 expect(
95c83464 669 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 670 workerChoiceStrategy
b0d6ed8f 671 ).workersVirtualTaskEndTimestamp
08f3f44c
JB
672 ).toBeInstanceOf(Array)
673 expect(
674 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
675 workerChoiceStrategy
b0d6ed8f 676 ).workersVirtualTaskEndTimestamp.length
08f3f44c 677 ).toBe(0)
2b4fddb8
JB
678 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
679 workerChoiceStrategy
b0d6ed8f 680 ).workersVirtualTaskEndTimestamp[0] = performance.now()
2b4fddb8
JB
681 expect(
682 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
683 workerChoiceStrategy
b0d6ed8f 684 ).workersVirtualTaskEndTimestamp.length
2b4fddb8 685 ).toBe(1)
594bfb84 686 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
08f3f44c
JB
687 expect(
688 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
689 workerChoiceStrategy
b0d6ed8f 690 ).workersVirtualTaskEndTimestamp
08f3f44c 691 ).toBeInstanceOf(Array)
08f3f44c
JB
692 expect(
693 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
694 workerChoiceStrategy
b0d6ed8f 695 ).workersVirtualTaskEndTimestamp.length
2b4fddb8 696 ).toBe(0)
f0829c53
JB
697 await pool.destroy()
698 pool = new DynamicThreadPool(
699 min,
700 max,
701 './tests/worker-files/thread/testWorker.js'
702 )
703 expect(
95c83464 704 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 705 workerChoiceStrategy
b0d6ed8f 706 ).workersVirtualTaskEndTimestamp
08f3f44c 707 ).toBeInstanceOf(Array)
2b4fddb8
JB
708 expect(
709 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
710 workerChoiceStrategy
b0d6ed8f 711 ).workersVirtualTaskEndTimestamp.length
2b4fddb8 712 ).toBe(0)
08f3f44c
JB
713 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
714 workerChoiceStrategy
b0d6ed8f 715 ).workersVirtualTaskEndTimestamp[0] = performance.now()
08f3f44c
JB
716 expect(
717 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
718 workerChoiceStrategy
b0d6ed8f 719 ).workersVirtualTaskEndTimestamp.length
08f3f44c 720 ).toBe(1)
594bfb84 721 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
08f3f44c
JB
722 expect(
723 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
724 workerChoiceStrategy
b0d6ed8f 725 ).workersVirtualTaskEndTimestamp
08f3f44c
JB
726 ).toBeInstanceOf(Array)
727 expect(
728 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
729 workerChoiceStrategy
b0d6ed8f 730 ).workersVirtualTaskEndTimestamp.length
08f3f44c 731 ).toBe(0)
caeb9817
JB
732 // We need to clean up the resources after our test
733 await pool.destroy()
734 })
735
10fcfaf4 736 it('Verify WEIGHTED_ROUND_ROBIN strategy default tasks usage statistics requirements', async () => {
594bfb84 737 const workerChoiceStrategy = WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
10fcfaf4
JB
738 let pool = new FixedThreadPool(
739 max,
d710242d 740 './tests/worker-files/thread/testWorker.js',
594bfb84 741 { workerChoiceStrategy }
10fcfaf4 742 )
10fcfaf4 743 expect(
86bf340d
JB
744 pool.workerChoiceStrategyContext.getRequiredStatistics()
745 ).toStrictEqual({
746 runTime: true,
747 avgRunTime: true,
748 medRunTime: false,
749 waitTime: false,
750 avgWaitTime: false,
751 medWaitTime: false
752 })
fd7ebd49 753 await pool.destroy()
10fcfaf4
JB
754 pool = new DynamicThreadPool(
755 min,
756 max,
d710242d 757 './tests/worker-files/thread/testWorker.js',
594bfb84 758 { workerChoiceStrategy }
10fcfaf4 759 )
10fcfaf4 760 expect(
86bf340d
JB
761 pool.workerChoiceStrategyContext.getRequiredStatistics()
762 ).toStrictEqual({
763 runTime: true,
764 avgRunTime: true,
765 medRunTime: false,
766 waitTime: false,
767 avgWaitTime: false,
768 medWaitTime: false
769 })
10fcfaf4
JB
770 // We need to clean up the resources after our test
771 await pool.destroy()
772 })
773
b3432a63 774 it('Verify WEIGHTED_ROUND_ROBIN strategy can be run in a fixed pool', async () => {
b3432a63
JB
775 const pool = new FixedThreadPool(
776 max,
777 './tests/worker-files/thread/testWorker.js',
778 { workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN }
779 )
780 // TODO: Create a better test to cover `WeightedRoundRobinWorkerChoiceStrategy#choose`
e211bc18 781 const promises = []
a20f0ba5
JB
782 const maxMultiplier = 2
783 for (let i = 0; i < max * maxMultiplier; i++) {
e211bc18 784 promises.push(pool.execute())
b3432a63 785 }
e211bc18 786 await Promise.all(promises)
138d29a8 787 for (const workerNode of pool.workerNodes) {
86bf340d 788 expect(workerNode.tasksUsage).toStrictEqual({
cb4a00ab 789 run: expect.any(Number),
86bf340d
JB
790 running: 0,
791 runTime: expect.any(Number),
792 runTimeHistory: expect.any(CircularArray),
793 avgRunTime: expect.any(Number),
794 medRunTime: 0,
795 waitTime: 0,
796 waitTimeHistory: expect.any(CircularArray),
797 avgWaitTime: 0,
798 medWaitTime: 0,
799 error: 0
800 })
e211bc18
JB
801 expect(workerNode.tasksUsage.run).toBeGreaterThan(0)
802 expect(workerNode.tasksUsage.runTime).toBeGreaterThan(0)
803 expect(workerNode.tasksUsage.avgRunTime).toBeGreaterThan(0)
138d29a8 804 }
97a2abc3 805 expect(
95c83464 806 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
d710242d 807 pool.workerChoiceStrategyContext.workerChoiceStrategy
08f3f44c
JB
808 ).defaultWorkerWeight
809 ).toBeGreaterThan(0)
810 expect(
811 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
812 pool.workerChoiceStrategyContext.workerChoiceStrategy
813 ).workerVirtualTaskRunTime
814 ).toBeGreaterThanOrEqual(0)
b3432a63
JB
815 // We need to clean up the resources after our test
816 await pool.destroy()
817 })
818
819 it('Verify WEIGHTED_ROUND_ROBIN strategy can be run in a dynamic pool', async () => {
b3432a63
JB
820 const pool = new DynamicThreadPool(
821 min,
822 max,
823 './tests/worker-files/thread/testWorker.js',
824 { workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN }
825 )
826 // TODO: Create a better test to cover `WeightedRoundRobinWorkerChoiceStrategy#choose`
e211bc18 827 const promises = []
138d29a8 828 const maxMultiplier = 2
5502c07c 829 for (let i = 0; i < max * maxMultiplier; i++) {
e211bc18 830 promises.push(pool.execute())
b3432a63 831 }
e211bc18 832 await Promise.all(promises)
138d29a8 833 for (const workerNode of pool.workerNodes) {
86bf340d 834 expect(workerNode.tasksUsage).toStrictEqual({
e211bc18 835 run: expect.any(Number),
86bf340d
JB
836 running: 0,
837 runTime: expect.any(Number),
838 runTimeHistory: expect.any(CircularArray),
839 avgRunTime: expect.any(Number),
840 medRunTime: 0,
841 waitTime: 0,
842 waitTimeHistory: expect.any(CircularArray),
843 avgWaitTime: 0,
844 medWaitTime: 0,
845 error: 0
846 })
e211bc18
JB
847 expect(workerNode.tasksUsage.run).toBeGreaterThan(0)
848 expect(workerNode.tasksUsage.runTime).toBeGreaterThan(0)
849 expect(workerNode.tasksUsage.avgRunTime).toBeGreaterThan(0)
138d29a8 850 }
2b4fddb8
JB
851 expect(
852 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
853 pool.workerChoiceStrategyContext.workerChoiceStrategy
854 ).defaultWorkerWeight
855 ).toBeGreaterThan(0)
856 expect(
857 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
858 pool.workerChoiceStrategyContext.workerChoiceStrategy
859 ).workerVirtualTaskRunTime
860 ).toBeGreaterThanOrEqual(0)
b3432a63
JB
861 // We need to clean up the resources after our test
862 await pool.destroy()
863 })
864
9e775f96 865 it('Verify WEIGHTED_ROUND_ROBIN strategy can be run in a dynamic pool with median runtime statistic', async () => {
010d7020
JB
866 const pool = new DynamicThreadPool(
867 min,
868 max,
869 './tests/worker-files/thread/testWorker.js',
870 {
871 workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN,
872 workerChoiceStrategyOptions: {
873 medRunTime: true
874 }
875 }
876 )
877 // TODO: Create a better test to cover `WeightedRoundRobinWorkerChoiceStrategy#choose`
e211bc18 878 const promises = []
010d7020
JB
879 const maxMultiplier = 2
880 for (let i = 0; i < max * maxMultiplier; i++) {
e211bc18 881 promises.push(pool.execute())
010d7020 882 }
e211bc18 883 await Promise.all(promises)
010d7020 884 for (const workerNode of pool.workerNodes) {
86bf340d 885 expect(workerNode.tasksUsage).toStrictEqual({
e211bc18 886 run: expect.any(Number),
86bf340d
JB
887 running: 0,
888 runTime: expect.any(Number),
889 runTimeHistory: expect.any(CircularArray),
890 avgRunTime: 0,
891 medRunTime: expect.any(Number),
892 waitTime: 0,
893 waitTimeHistory: expect.any(CircularArray),
894 avgWaitTime: 0,
895 medWaitTime: 0,
896 error: 0
897 })
e211bc18
JB
898 expect(workerNode.tasksUsage.run).toBeGreaterThan(0)
899 expect(workerNode.tasksUsage.runTime).toBeGreaterThan(0)
900 expect(workerNode.tasksUsage.medRunTime).toBeGreaterThan(0)
010d7020 901 }
08f3f44c
JB
902 expect(
903 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
904 pool.workerChoiceStrategyContext.workerChoiceStrategy
905 ).defaultWorkerWeight
906 ).toBeGreaterThan(0)
907 expect(
908 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
909 pool.workerChoiceStrategyContext.workerChoiceStrategy
910 ).workerVirtualTaskRunTime
911 ).toBeGreaterThanOrEqual(0)
010d7020
JB
912 // We need to clean up the resources after our test
913 await pool.destroy()
914 })
915
a6f7f1b4 916 it('Verify WEIGHTED_ROUND_ROBIN strategy internals are resets after setting it', async () => {
594bfb84 917 const workerChoiceStrategy = WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
f0829c53 918 let pool = new FixedThreadPool(
caeb9817
JB
919 max,
920 './tests/worker-files/thread/testWorker.js'
921 )
38f6e859 922 expect(
95c83464 923 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 924 workerChoiceStrategy
f06e48d8 925 ).currentWorkerNodeId
b529c323 926 ).toBeDefined()
38f6e859 927 expect(
95c83464 928 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 929 workerChoiceStrategy
b529c323
JB
930 ).defaultWorkerWeight
931 ).toBeDefined()
caeb9817 932 expect(
95c83464 933 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 934 workerChoiceStrategy
08f3f44c 935 ).workerVirtualTaskRunTime
b529c323 936 ).toBeDefined()
594bfb84 937 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
a6f7f1b4 938 expect(
95c83464 939 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
d710242d 940 pool.workerChoiceStrategyContext.workerChoiceStrategy
f06e48d8 941 ).currentWorkerNodeId
a6f7f1b4
JB
942 ).toBe(0)
943 expect(
95c83464 944 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
d710242d 945 pool.workerChoiceStrategyContext.workerChoiceStrategy
95c83464 946 ).defaultWorkerWeight
a6f7f1b4 947 ).toBeGreaterThan(0)
08f3f44c
JB
948 expect(
949 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
950 workerChoiceStrategy
951 ).workerVirtualTaskRunTime
952 ).toBe(0)
f0829c53
JB
953 await pool.destroy()
954 pool = new DynamicThreadPool(
955 min,
956 max,
957 './tests/worker-files/thread/testWorker.js'
958 )
38f6e859 959 expect(
95c83464 960 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 961 workerChoiceStrategy
f06e48d8 962 ).currentWorkerNodeId
b529c323 963 ).toBeDefined()
38f6e859 964 expect(
95c83464 965 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 966 workerChoiceStrategy
b529c323
JB
967 ).defaultWorkerWeight
968 ).toBeDefined()
f0829c53 969 expect(
95c83464 970 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 971 workerChoiceStrategy
08f3f44c 972 ).workerVirtualTaskRunTime
b529c323 973 ).toBeDefined()
594bfb84 974 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
a6f7f1b4 975 expect(
95c83464 976 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
d710242d 977 pool.workerChoiceStrategyContext.workerChoiceStrategy
f06e48d8 978 ).currentWorkerNodeId
a6f7f1b4
JB
979 ).toBe(0)
980 expect(
95c83464 981 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
d710242d 982 pool.workerChoiceStrategyContext.workerChoiceStrategy
95c83464 983 ).defaultWorkerWeight
a6f7f1b4 984 ).toBeGreaterThan(0)
08f3f44c
JB
985 expect(
986 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
987 workerChoiceStrategy
988 ).workerVirtualTaskRunTime
989 ).toBe(0)
caeb9817
JB
990 // We need to clean up the resources after our test
991 await pool.destroy()
992 })
993
89b09b26 994 it('Verify unknown strategy throw error', () => {
a35560ba
S
995 expect(
996 () =>
997 new DynamicThreadPool(
998 min,
999 max,
1000 './tests/worker-files/thread/testWorker.js',
1927ee67 1001 { workerChoiceStrategy: 'UNKNOWN_STRATEGY' }
a35560ba 1002 )
d4aeae5a 1003 ).toThrowError("Invalid worker choice strategy 'UNKNOWN_STRATEGY'")
a35560ba
S
1004 })
1005})