fix: fix worker choice strategy retries mechanism on some edge cases
[poolifier.git] / tests / pools / selection-strategies / selection-strategies.test.js
CommitLineData
a61a0724 1const { expect } = require('expect')
a35560ba 2const {
a35560ba 3 DynamicThreadPool,
3d6dd312 4 FixedClusterPool,
2ced693a 5 FixedThreadPool,
3d6dd312 6 WorkerChoiceStrategies
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')
a7bbf44a 18 expect(WorkerChoiceStrategies.LEAST_ELU).toBe('LEAST_ELU')
23ff945a 19 expect(WorkerChoiceStrategies.FAIR_SHARE).toBe('FAIR_SHARE')
b3432a63
JB
20 expect(WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN).toBe(
21 'WEIGHTED_ROUND_ROBIN'
22 )
feec6e8c
JB
23 expect(WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN).toBe(
24 'INTERLEAVED_WEIGHTED_ROUND_ROBIN'
25 )
a35560ba
S
26 })
27
e843b904 28 it('Verify ROUND_ROBIN strategy is the default at pool creation', async () => {
e843b904
JB
29 const pool = new DynamicThreadPool(
30 min,
31 max,
32 './tests/worker-files/thread/testWorker.js'
33 )
34 expect(pool.opts.workerChoiceStrategy).toBe(
35 WorkerChoiceStrategies.ROUND_ROBIN
36 )
37 // We need to clean up the resources after our test
38 await pool.destroy()
39 })
40
594bfb84
JB
41 it('Verify available strategies are taken at pool creation', async () => {
42 for (const workerChoiceStrategy of Object.values(WorkerChoiceStrategies)) {
43 const pool = new FixedThreadPool(
44 max,
45 './tests/worker-files/thread/testWorker.js',
46 { workerChoiceStrategy }
47 )
48 expect(pool.opts.workerChoiceStrategy).toBe(workerChoiceStrategy)
49 expect(pool.workerChoiceStrategyContext.workerChoiceStrategy).toBe(
50 workerChoiceStrategy
51 )
52 await pool.destroy()
53 }
d2f7b7a2
JB
54 })
55
594bfb84
JB
56 it('Verify available strategies can be set after pool creation', async () => {
57 for (const workerChoiceStrategy of Object.values(WorkerChoiceStrategies)) {
58 const pool = new DynamicThreadPool(
59 min,
60 max,
ec82cfa1 61 './tests/worker-files/thread/testWorker.js'
594bfb84
JB
62 )
63 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
64 expect(pool.opts.workerChoiceStrategy).toBe(workerChoiceStrategy)
65 expect(pool.workerChoiceStrategyContext.workerChoiceStrategy).toBe(
66 workerChoiceStrategy
67 )
68 await pool.destroy()
69 }
70 })
71
72 it('Verify available strategies default internals at pool creation', async () => {
73 const pool = new FixedThreadPool(
e843b904
JB
74 max,
75 './tests/worker-files/thread/testWorker.js'
76 )
594bfb84
JB
77 for (const workerChoiceStrategy of Object.values(WorkerChoiceStrategies)) {
78 if (workerChoiceStrategy === WorkerChoiceStrategies.ROUND_ROBIN) {
79 expect(
80 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
81 workerChoiceStrategy
9b106837 82 ).nextWorkerNodeKey
594bfb84
JB
83 ).toBe(0)
84 } else if (workerChoiceStrategy === WorkerChoiceStrategies.FAIR_SHARE) {
08f3f44c
JB
85 expect(
86 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
87 workerChoiceStrategy
b0d6ed8f 88 ).workersVirtualTaskEndTimestamp
08f3f44c
JB
89 ).toBeInstanceOf(Array)
90 expect(
91 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
92 workerChoiceStrategy
b0d6ed8f 93 ).workersVirtualTaskEndTimestamp.length
08f3f44c 94 ).toBe(0)
594bfb84
JB
95 } else if (
96 workerChoiceStrategy === WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
97 ) {
98 expect(
99 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
100 workerChoiceStrategy
9b106837 101 ).nextWorkerNodeKey
594bfb84
JB
102 ).toBe(0)
103 expect(
104 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
105 workerChoiceStrategy
106 ).defaultWorkerWeight
107 ).toBeGreaterThan(0)
08f3f44c
JB
108 expect(
109 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
110 workerChoiceStrategy
111 ).workerVirtualTaskRunTime
112 ).toBe(0)
594bfb84
JB
113 }
114 }
e843b904
JB
115 await pool.destroy()
116 })
117
6c6afb84
JB
118 it('Verify ROUND_ROBIN strategy default policy', async () => {
119 const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN
120 let pool = new FixedThreadPool(
121 max,
122 './tests/worker-files/thread/testWorker.js',
123 { workerChoiceStrategy }
124 )
125 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
b1aae695
JB
126 dynamicWorkerUsage: true,
127 dynamicWorkerReady: true
6c6afb84
JB
128 })
129 await pool.destroy()
130 pool = new DynamicThreadPool(
131 min,
132 max,
133 './tests/worker-files/thread/testWorker.js',
134 { workerChoiceStrategy }
135 )
136 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
b1aae695
JB
137 dynamicWorkerUsage: true,
138 dynamicWorkerReady: true
6c6afb84
JB
139 })
140 // We need to clean up the resources after our test
141 await pool.destroy()
142 })
143
144 it('Verify ROUND_ROBIN strategy default tasks statistics requirements', async () => {
594bfb84 145 const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN
10fcfaf4
JB
146 let pool = new FixedThreadPool(
147 max,
d710242d 148 './tests/worker-files/thread/testWorker.js',
594bfb84 149 { workerChoiceStrategy }
10fcfaf4 150 )
87de9ff5
JB
151 expect(
152 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
153 ).toStrictEqual({
932fc8be
JB
154 runTime: {
155 aggregate: false,
156 average: false,
157 median: false
158 },
159 waitTime: {
160 aggregate: false,
161 average: false,
162 median: false
163 },
5df69fab
JB
164 elu: {
165 aggregate: false,
166 average: false,
167 median: false
168 }
86bf340d 169 })
fd7ebd49 170 await pool.destroy()
10fcfaf4
JB
171 pool = new DynamicThreadPool(
172 min,
173 max,
d710242d 174 './tests/worker-files/thread/testWorker.js',
594bfb84 175 { workerChoiceStrategy }
10fcfaf4 176 )
87de9ff5
JB
177 expect(
178 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
179 ).toStrictEqual({
932fc8be
JB
180 runTime: {
181 aggregate: false,
182 average: false,
183 median: false
184 },
185 waitTime: {
186 aggregate: false,
187 average: false,
188 median: false
189 },
5df69fab
JB
190 elu: {
191 aggregate: false,
192 average: false,
193 median: false
194 }
86bf340d 195 })
10fcfaf4
JB
196 // We need to clean up the resources after our test
197 await pool.destroy()
198 })
199
bdaf31cd 200 it('Verify ROUND_ROBIN strategy can be run in a fixed pool', async () => {
bdaf31cd
JB
201 const pool = new FixedThreadPool(
202 max,
203 './tests/worker-files/thread/testWorker.js',
204 { workerChoiceStrategy: WorkerChoiceStrategies.ROUND_ROBIN }
205 )
bdaf31cd 206 // TODO: Create a better test to cover `RoundRobinWorkerChoiceStrategy#choose`
ee9f5295 207 const promises = new Set()
a20f0ba5
JB
208 const maxMultiplier = 2
209 for (let i = 0; i < max * maxMultiplier; i++) {
ee9f5295 210 promises.add(pool.execute())
e211bc18
JB
211 }
212 await Promise.all(promises)
213 for (const workerNode of pool.workerNodes) {
465b2940 214 expect(workerNode.usage).toStrictEqual({
a4e07f72
JB
215 tasks: {
216 executed: maxMultiplier,
217 executing: 0,
218 queued: 0,
df593701 219 maxQueued: 0,
a4e07f72
JB
220 failed: 0
221 },
222 runTime: {
a4e07f72
JB
223 history: expect.any(CircularArray)
224 },
225 waitTime: {
a4e07f72
JB
226 history: expect.any(CircularArray)
227 },
5df69fab
JB
228 elu: {
229 idle: {
5df69fab
JB
230 history: expect.any(CircularArray)
231 },
232 active: {
5df69fab 233 history: expect.any(CircularArray)
71514351 234 }
5df69fab 235 }
e211bc18 236 })
bdaf31cd 237 }
9458090a
JB
238 expect(
239 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
240 WorkerChoiceStrategies.ROUND_ROBIN
9b106837 241 ).nextWorkerNodeKey
9458090a 242 ).toBe(0)
bdaf31cd
JB
243 // We need to clean up the resources after our test
244 await pool.destroy()
245 })
246
247 it('Verify ROUND_ROBIN strategy can be run in a dynamic pool', async () => {
bdaf31cd
JB
248 const pool = new DynamicThreadPool(
249 min,
250 max,
251 './tests/worker-files/thread/testWorker.js',
252 { workerChoiceStrategy: WorkerChoiceStrategies.ROUND_ROBIN }
253 )
bdaf31cd 254 // TODO: Create a better test to cover `RoundRobinWorkerChoiceStrategy#choose`
ee9f5295 255 const promises = new Set()
a20f0ba5
JB
256 const maxMultiplier = 2
257 for (let i = 0; i < max * maxMultiplier; i++) {
ee9f5295 258 promises.add(pool.execute())
e211bc18
JB
259 }
260 await Promise.all(promises)
261 for (const workerNode of pool.workerNodes) {
465b2940 262 expect(workerNode.usage).toStrictEqual({
a4e07f72
JB
263 tasks: {
264 executed: maxMultiplier,
265 executing: 0,
266 queued: 0,
df593701 267 maxQueued: 0,
a4e07f72
JB
268 failed: 0
269 },
270 runTime: {
a4e07f72
JB
271 history: expect.any(CircularArray)
272 },
273 waitTime: {
a4e07f72
JB
274 history: expect.any(CircularArray)
275 },
5df69fab
JB
276 elu: {
277 idle: {
5df69fab
JB
278 history: expect.any(CircularArray)
279 },
280 active: {
5df69fab 281 history: expect.any(CircularArray)
71514351 282 }
5df69fab 283 }
e211bc18 284 })
bdaf31cd 285 }
9458090a
JB
286 expect(
287 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
288 WorkerChoiceStrategies.ROUND_ROBIN
9b106837 289 ).nextWorkerNodeKey
9458090a 290 ).toBe(0)
bdaf31cd
JB
291 // We need to clean up the resources after our test
292 await pool.destroy()
293 })
294
2ced693a 295 it('Verify ROUND_ROBIN strategy runtime behavior', async () => {
594bfb84 296 const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN
2ced693a
JB
297 let pool = new FixedClusterPool(
298 max,
594bfb84
JB
299 './tests/worker-files/cluster/testWorker.js',
300 { workerChoiceStrategy }
2ced693a
JB
301 )
302 let results = new Set()
303 for (let i = 0; i < max; i++) {
20dcad1a 304 results.add(pool.workerNodes[pool.chooseWorkerNode()].worker.id)
2ced693a
JB
305 }
306 expect(results.size).toBe(max)
307 await pool.destroy()
594bfb84
JB
308 pool = new FixedThreadPool(
309 max,
310 './tests/worker-files/thread/testWorker.js',
311 { workerChoiceStrategy }
312 )
2ced693a
JB
313 results = new Set()
314 for (let i = 0; i < max; i++) {
20dcad1a 315 results.add(pool.workerNodes[pool.chooseWorkerNode()].worker.threadId)
2ced693a
JB
316 }
317 expect(results.size).toBe(max)
318 await pool.destroy()
319 })
320
a6f7f1b4 321 it('Verify ROUND_ROBIN strategy internals are resets after setting it', async () => {
594bfb84 322 const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN
a6f7f1b4
JB
323 let pool = new FixedThreadPool(
324 max,
325 './tests/worker-files/thread/testWorker.js',
326 { workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN }
327 )
38f6e859 328 expect(
95c83464 329 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 330 workerChoiceStrategy
9b106837 331 ).nextWorkerNodeKey
b529c323 332 ).toBeDefined()
594bfb84 333 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
a6f7f1b4 334 expect(
95c83464 335 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
d710242d 336 pool.workerChoiceStrategyContext.workerChoiceStrategy
9b106837 337 ).nextWorkerNodeKey
a6f7f1b4
JB
338 ).toBe(0)
339 await pool.destroy()
340 pool = new DynamicThreadPool(
341 min,
342 max,
343 './tests/worker-files/thread/testWorker.js',
344 { workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN }
345 )
38f6e859 346 expect(
95c83464 347 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 348 workerChoiceStrategy
9b106837 349 ).nextWorkerNodeKey
b529c323 350 ).toBeDefined()
594bfb84 351 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
a6f7f1b4 352 expect(
95c83464 353 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
d710242d 354 pool.workerChoiceStrategyContext.workerChoiceStrategy
9b106837 355 ).nextWorkerNodeKey
a6f7f1b4
JB
356 ).toBe(0)
357 // We need to clean up the resources after our test
358 await pool.destroy()
359 })
360
6c6afb84
JB
361 it('Verify LEAST_USED strategy default policy', async () => {
362 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_USED
363 let pool = new FixedThreadPool(
364 max,
365 './tests/worker-files/thread/testWorker.js',
366 { workerChoiceStrategy }
367 )
368 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
b1aae695
JB
369 dynamicWorkerUsage: false,
370 dynamicWorkerReady: true
6c6afb84
JB
371 })
372 await pool.destroy()
373 pool = new DynamicThreadPool(
374 min,
375 max,
376 './tests/worker-files/thread/testWorker.js',
377 { workerChoiceStrategy }
378 )
379 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
b1aae695
JB
380 dynamicWorkerUsage: false,
381 dynamicWorkerReady: true
6c6afb84
JB
382 })
383 // We need to clean up the resources after our test
384 await pool.destroy()
385 })
386
387 it('Verify LEAST_USED strategy default tasks statistics requirements', async () => {
e4543b14 388 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_USED
10fcfaf4
JB
389 let pool = new FixedThreadPool(
390 max,
d710242d 391 './tests/worker-files/thread/testWorker.js',
594bfb84 392 { workerChoiceStrategy }
10fcfaf4 393 )
87de9ff5
JB
394 expect(
395 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
396 ).toStrictEqual({
932fc8be
JB
397 runTime: {
398 aggregate: false,
399 average: false,
400 median: false
401 },
402 waitTime: {
403 aggregate: false,
404 average: false,
405 median: false
406 },
5df69fab
JB
407 elu: {
408 aggregate: false,
409 average: false,
410 median: false
411 }
86bf340d 412 })
fd7ebd49 413 await pool.destroy()
10fcfaf4
JB
414 pool = new DynamicThreadPool(
415 min,
416 max,
d710242d 417 './tests/worker-files/thread/testWorker.js',
594bfb84 418 { workerChoiceStrategy }
10fcfaf4 419 )
87de9ff5
JB
420 expect(
421 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
422 ).toStrictEqual({
932fc8be
JB
423 runTime: {
424 aggregate: false,
425 average: false,
426 median: false
427 },
428 waitTime: {
429 aggregate: false,
430 average: false,
431 median: false
432 },
5df69fab
JB
433 elu: {
434 aggregate: false,
435 average: false,
436 median: false
437 }
86bf340d 438 })
10fcfaf4
JB
439 // We need to clean up the resources after our test
440 await pool.destroy()
441 })
442
e4543b14 443 it('Verify LEAST_USED strategy can be run in a fixed pool', async () => {
b98ec2e6
JB
444 const pool = new FixedThreadPool(
445 max,
446 './tests/worker-files/thread/testWorker.js',
e4543b14 447 { workerChoiceStrategy: WorkerChoiceStrategies.LEAST_USED }
b98ec2e6 448 )
e4543b14 449 // TODO: Create a better test to cover `LeastUsedWorkerChoiceStrategy#choose`
ee9f5295 450 const promises = new Set()
a20f0ba5
JB
451 const maxMultiplier = 2
452 for (let i = 0; i < max * maxMultiplier; i++) {
ee9f5295 453 promises.add(pool.execute())
e211bc18
JB
454 }
455 await Promise.all(promises)
456 for (const workerNode of pool.workerNodes) {
465b2940 457 expect(workerNode.usage).toStrictEqual({
a4e07f72 458 tasks: {
76407b8e 459 executed: expect.any(Number),
a4e07f72
JB
460 executing: 0,
461 queued: 0,
df593701 462 maxQueued: 0,
a4e07f72
JB
463 failed: 0
464 },
465 runTime: {
a4e07f72
JB
466 history: expect.any(CircularArray)
467 },
468 waitTime: {
a4e07f72
JB
469 history: expect.any(CircularArray)
470 },
5df69fab
JB
471 elu: {
472 idle: {
5df69fab
JB
473 history: expect.any(CircularArray)
474 },
475 active: {
5df69fab 476 history: expect.any(CircularArray)
71514351 477 }
5df69fab 478 }
e211bc18 479 })
465b2940
JB
480 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
481 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
76407b8e
JB
482 max * maxMultiplier
483 )
a35560ba 484 }
a35560ba
S
485 // We need to clean up the resources after our test
486 await pool.destroy()
487 })
488
e4543b14 489 it('Verify LEAST_USED strategy can be run in a dynamic pool', async () => {
ff5e76e1
JB
490 const pool = new DynamicThreadPool(
491 min,
492 max,
493 './tests/worker-files/thread/testWorker.js',
e4543b14 494 { workerChoiceStrategy: WorkerChoiceStrategies.LEAST_USED }
ff5e76e1 495 )
e4543b14 496 // TODO: Create a better test to cover `LeastUsedWorkerChoiceStrategy#choose`
ee9f5295 497 const promises = new Set()
a20f0ba5
JB
498 const maxMultiplier = 2
499 for (let i = 0; i < max * maxMultiplier; i++) {
ee9f5295 500 promises.add(pool.execute())
e211bc18
JB
501 }
502 await Promise.all(promises)
503 for (const workerNode of pool.workerNodes) {
465b2940 504 expect(workerNode.usage).toStrictEqual({
a4e07f72 505 tasks: {
76407b8e 506 executed: expect.any(Number),
a4e07f72
JB
507 executing: 0,
508 queued: 0,
df593701 509 maxQueued: 0,
a4e07f72
JB
510 failed: 0
511 },
512 runTime: {
a4e07f72
JB
513 history: expect.any(CircularArray)
514 },
515 waitTime: {
a4e07f72
JB
516 history: expect.any(CircularArray)
517 },
5df69fab
JB
518 elu: {
519 idle: {
5df69fab
JB
520 history: expect.any(CircularArray)
521 },
522 active: {
5df69fab 523 history: expect.any(CircularArray)
71514351 524 }
5df69fab 525 }
e211bc18 526 })
465b2940
JB
527 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
528 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
76407b8e
JB
529 max * maxMultiplier
530 )
168c526f 531 }
168c526f
JB
532 // We need to clean up the resources after our test
533 await pool.destroy()
534 })
535
6c6afb84
JB
536 it('Verify LEAST_BUSY strategy default policy', async () => {
537 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_BUSY
538 let pool = new FixedThreadPool(
539 max,
540 './tests/worker-files/thread/testWorker.js',
541 { workerChoiceStrategy }
542 )
543 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
b1aae695
JB
544 dynamicWorkerUsage: false,
545 dynamicWorkerReady: true
6c6afb84
JB
546 })
547 await pool.destroy()
548 pool = new DynamicThreadPool(
549 min,
550 max,
551 './tests/worker-files/thread/testWorker.js',
552 { workerChoiceStrategy }
553 )
554 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
b1aae695
JB
555 dynamicWorkerUsage: false,
556 dynamicWorkerReady: true
6c6afb84
JB
557 })
558 // We need to clean up the resources after our test
559 await pool.destroy()
560 })
561
562 it('Verify LEAST_BUSY strategy default tasks statistics requirements', async () => {
e4543b14 563 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_BUSY
168c526f
JB
564 let pool = new FixedThreadPool(
565 max,
d710242d 566 './tests/worker-files/thread/testWorker.js',
594bfb84 567 { workerChoiceStrategy }
168c526f 568 )
87de9ff5
JB
569 expect(
570 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
571 ).toStrictEqual({
932fc8be
JB
572 runTime: {
573 aggregate: true,
574 average: false,
575 median: false
576 },
577 waitTime: {
578 aggregate: true,
579 average: false,
580 median: false
581 },
5df69fab
JB
582 elu: {
583 aggregate: false,
584 average: false,
585 median: false
586 }
86bf340d 587 })
168c526f
JB
588 await pool.destroy()
589 pool = new DynamicThreadPool(
590 min,
591 max,
d710242d 592 './tests/worker-files/thread/testWorker.js',
594bfb84 593 { workerChoiceStrategy }
168c526f 594 )
87de9ff5
JB
595 expect(
596 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
597 ).toStrictEqual({
932fc8be
JB
598 runTime: {
599 aggregate: true,
600 average: false,
601 median: false
602 },
603 waitTime: {
604 aggregate: true,
605 average: false,
606 median: false
607 },
5df69fab
JB
608 elu: {
609 aggregate: false,
610 average: false,
611 median: false
612 }
86bf340d 613 })
168c526f
JB
614 // We need to clean up the resources after our test
615 await pool.destroy()
616 })
617
e4543b14 618 it('Verify LEAST_BUSY strategy can be run in a fixed pool', async () => {
168c526f
JB
619 const pool = new FixedThreadPool(
620 max,
621 './tests/worker-files/thread/testWorker.js',
e4543b14 622 { workerChoiceStrategy: WorkerChoiceStrategies.LEAST_BUSY }
168c526f 623 )
e4543b14 624 // TODO: Create a better test to cover `LeastBusyWorkerChoiceStrategy#choose`
ee9f5295 625 const promises = new Set()
a20f0ba5
JB
626 const maxMultiplier = 2
627 for (let i = 0; i < max * maxMultiplier; i++) {
ee9f5295 628 promises.add(pool.execute())
e211bc18
JB
629 }
630 await Promise.all(promises)
631 for (const workerNode of pool.workerNodes) {
19dbc45b 632 expect(workerNode.usage).toMatchObject({
a4e07f72
JB
633 tasks: {
634 executed: expect.any(Number),
635 executing: 0,
636 queued: 0,
df593701 637 maxQueued: 0,
a4e07f72
JB
638 failed: 0
639 },
640 runTime: {
a4e07f72
JB
641 history: expect.any(CircularArray)
642 },
643 waitTime: {
a4e07f72
JB
644 history: expect.any(CircularArray)
645 },
5df69fab
JB
646 elu: {
647 idle: {
5df69fab
JB
648 history: expect.any(CircularArray)
649 },
650 active: {
5df69fab 651 history: expect.any(CircularArray)
71514351 652 }
5df69fab 653 }
e211bc18 654 })
465b2940
JB
655 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
656 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
a4e07f72
JB
657 max * maxMultiplier
658 )
19dbc45b
JB
659 if (workerNode.usage.runTime.aggregate == null) {
660 expect(workerNode.usage.runTime.aggregate).toBeUndefined()
661 } else {
662 expect(workerNode.usage.runTime.aggregate).toBeGreaterThan(0)
663 }
664 if (workerNode.usage.waitTime.aggregate == null) {
665 expect(workerNode.usage.waitTime.aggregate).toBeUndefined()
666 } else {
667 expect(workerNode.usage.waitTime.aggregate).toBeGreaterThan(0)
668 }
168c526f 669 }
168c526f
JB
670 // We need to clean up the resources after our test
671 await pool.destroy()
672 })
673
e4543b14 674 it('Verify LEAST_BUSY strategy can be run in a dynamic pool', async () => {
168c526f
JB
675 const pool = new DynamicThreadPool(
676 min,
677 max,
678 './tests/worker-files/thread/testWorker.js',
e4543b14 679 { workerChoiceStrategy: WorkerChoiceStrategies.LEAST_BUSY }
168c526f 680 )
e4543b14 681 // TODO: Create a better test to cover `LeastBusyWorkerChoiceStrategy#choose`
ee9f5295 682 const promises = new Set()
a20f0ba5
JB
683 const maxMultiplier = 2
684 for (let i = 0; i < max * maxMultiplier; i++) {
ee9f5295 685 promises.add(pool.execute())
e211bc18
JB
686 }
687 await Promise.all(promises)
688 for (const workerNode of pool.workerNodes) {
19dbc45b 689 expect(workerNode.usage).toMatchObject({
a4e07f72
JB
690 tasks: {
691 executed: expect.any(Number),
692 executing: 0,
693 queued: 0,
df593701 694 maxQueued: 0,
a4e07f72
JB
695 failed: 0
696 },
697 runTime: {
a4e07f72
JB
698 history: expect.any(CircularArray)
699 },
700 waitTime: {
a4e07f72
JB
701 history: expect.any(CircularArray)
702 },
5df69fab
JB
703 elu: {
704 idle: {
5df69fab
JB
705 history: expect.any(CircularArray)
706 },
707 active: {
5df69fab 708 history: expect.any(CircularArray)
71514351 709 }
5df69fab 710 }
e211bc18 711 })
465b2940
JB
712 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
713 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
a4e07f72
JB
714 max * maxMultiplier
715 )
19dbc45b
JB
716 if (workerNode.usage.runTime.aggregate == null) {
717 expect(workerNode.usage.runTime.aggregate).toBeUndefined()
718 } else {
719 expect(workerNode.usage.runTime.aggregate).toBeGreaterThan(0)
720 }
721 if (workerNode.usage.waitTime.aggregate == null) {
722 expect(workerNode.usage.waitTime.aggregate).toBeUndefined()
723 } else {
724 expect(workerNode.usage.waitTime.aggregate).toBeGreaterThan(0)
725 }
ff5e76e1 726 }
ff5e76e1
JB
727 // We need to clean up the resources after our test
728 await pool.destroy()
729 })
730
6c6afb84
JB
731 it('Verify LEAST_ELU strategy default policy', async () => {
732 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_ELU
733 let pool = new FixedThreadPool(
734 max,
735 './tests/worker-files/thread/testWorker.js',
736 { workerChoiceStrategy }
737 )
738 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
b1aae695
JB
739 dynamicWorkerUsage: false,
740 dynamicWorkerReady: true
6c6afb84
JB
741 })
742 await pool.destroy()
743 pool = new DynamicThreadPool(
744 min,
745 max,
746 './tests/worker-files/thread/testWorker.js',
747 { workerChoiceStrategy }
748 )
749 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
b1aae695
JB
750 dynamicWorkerUsage: false,
751 dynamicWorkerReady: true
6c6afb84
JB
752 })
753 // We need to clean up the resources after our test
754 await pool.destroy()
755 })
756
757 it('Verify LEAST_ELU strategy default tasks statistics requirements', async () => {
a7bbf44a
JB
758 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_ELU
759 let pool = new FixedThreadPool(
760 max,
761 './tests/worker-files/thread/testWorker.js',
762 { workerChoiceStrategy }
763 )
05302647
JB
764 expect(
765 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
766 ).toStrictEqual({
e460940e
JB
767 runTime: {
768 aggregate: false,
769 average: false,
770 median: false
771 },
772 waitTime: {
773 aggregate: false,
774 average: false,
775 median: false
776 },
5df69fab
JB
777 elu: {
778 aggregate: true,
779 average: false,
780 median: false
781 }
a7bbf44a
JB
782 })
783 await pool.destroy()
784 pool = new DynamicThreadPool(
785 min,
786 max,
787 './tests/worker-files/thread/testWorker.js',
788 { workerChoiceStrategy }
789 )
05302647
JB
790 expect(
791 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
792 ).toStrictEqual({
e460940e
JB
793 runTime: {
794 aggregate: false,
795 average: false,
796 median: false
797 },
798 waitTime: {
799 aggregate: false,
800 average: false,
801 median: false
802 },
5df69fab
JB
803 elu: {
804 aggregate: true,
805 average: false,
806 median: false
807 }
a7bbf44a
JB
808 })
809 // We need to clean up the resources after our test
810 await pool.destroy()
811 })
812
ae9cf3c8 813 it('Verify LEAST_ELU strategy can be run in a fixed pool', async () => {
c5ad42cd
JB
814 const pool = new FixedThreadPool(
815 max,
816 './tests/worker-files/thread/testWorker.js',
817 { workerChoiceStrategy: WorkerChoiceStrategies.LEAST_ELU }
818 )
819 // TODO: Create a better test to cover `LeastEluWorkerChoiceStrategy#choose`
dd38581f 820 const promises = new Set()
c5ad42cd
JB
821 const maxMultiplier = 2
822 for (let i = 0; i < max * maxMultiplier; i++) {
dd38581f 823 promises.add(pool.execute())
c5ad42cd 824 }
dd38581f 825 await Promise.all(promises)
c5ad42cd 826 for (const workerNode of pool.workerNodes) {
71514351 827 expect(workerNode.usage).toMatchObject({
c5ad42cd
JB
828 tasks: {
829 executed: expect.any(Number),
830 executing: 0,
831 queued: 0,
df593701 832 maxQueued: 0,
c5ad42cd
JB
833 failed: 0
834 },
835 runTime: {
c5ad42cd 836 history: expect.any(CircularArray)
a1347286
JB
837 },
838 waitTime: {
a1347286 839 history: expect.any(CircularArray)
5df69fab
JB
840 },
841 elu: {
71514351 842 idle: expect.objectContaining({
5df69fab 843 history: expect.any(CircularArray)
71514351
JB
844 }),
845 active: expect.objectContaining({
5df69fab 846 history: expect.any(CircularArray)
71514351 847 })
a1347286 848 }
5df69fab 849 })
465b2940
JB
850 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
851 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
a1347286
JB
852 max * maxMultiplier
853 )
71514351
JB
854 if (workerNode.usage.elu.utilization == null) {
855 expect(workerNode.usage.elu.utilization).toBeUndefined()
856 } else {
857 expect(workerNode.usage.elu.utilization).toBeGreaterThanOrEqual(0)
858 expect(workerNode.usage.elu.utilization).toBeLessThanOrEqual(1)
859 }
a1347286
JB
860 }
861 // We need to clean up the resources after our test
862 await pool.destroy()
863 })
864
865 it('Verify LEAST_ELU strategy can be run in a dynamic pool', async () => {
866 const pool = new DynamicThreadPool(
867 min,
868 max,
869 './tests/worker-files/thread/testWorker.js',
870 { workerChoiceStrategy: WorkerChoiceStrategies.LEAST_ELU }
871 )
872 // TODO: Create a better test to cover `LeastEluWorkerChoiceStrategy#choose`
dd38581f 873 const promises = new Set()
a1347286
JB
874 const maxMultiplier = 2
875 for (let i = 0; i < max * maxMultiplier; i++) {
dd38581f 876 promises.add(pool.execute())
a1347286 877 }
dd38581f 878 await Promise.all(promises)
a1347286 879 for (const workerNode of pool.workerNodes) {
71514351 880 expect(workerNode.usage).toMatchObject({
a1347286
JB
881 tasks: {
882 executed: expect.any(Number),
883 executing: 0,
884 queued: 0,
df593701 885 maxQueued: 0,
a1347286
JB
886 failed: 0
887 },
888 runTime: {
a1347286 889 history: expect.any(CircularArray)
c5ad42cd
JB
890 },
891 waitTime: {
c5ad42cd 892 history: expect.any(CircularArray)
5df69fab
JB
893 },
894 elu: {
71514351 895 idle: expect.objectContaining({
5df69fab 896 history: expect.any(CircularArray)
71514351
JB
897 }),
898 active: expect.objectContaining({
5df69fab 899 history: expect.any(CircularArray)
71514351 900 })
c5ad42cd 901 }
5df69fab 902 })
465b2940
JB
903 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
904 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
c5ad42cd
JB
905 max * maxMultiplier
906 )
71514351
JB
907 if (workerNode.usage.elu.utilization == null) {
908 expect(workerNode.usage.elu.utilization).toBeUndefined()
909 } else {
910 expect(workerNode.usage.elu.utilization).toBeGreaterThanOrEqual(0)
911 expect(workerNode.usage.elu.utilization).toBeLessThanOrEqual(1)
912 }
c5ad42cd
JB
913 }
914 // We need to clean up the resources after our test
915 await pool.destroy()
916 })
917
6c6afb84
JB
918 it('Verify FAIR_SHARE strategy default policy', async () => {
919 const workerChoiceStrategy = WorkerChoiceStrategies.FAIR_SHARE
920 let pool = new FixedThreadPool(
921 max,
922 './tests/worker-files/thread/testWorker.js',
923 { workerChoiceStrategy }
924 )
925 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
b1aae695
JB
926 dynamicWorkerUsage: false,
927 dynamicWorkerReady: true
6c6afb84
JB
928 })
929 await pool.destroy()
930 pool = new DynamicThreadPool(
931 min,
932 max,
933 './tests/worker-files/thread/testWorker.js',
934 { workerChoiceStrategy }
935 )
936 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
b1aae695
JB
937 dynamicWorkerUsage: false,
938 dynamicWorkerReady: true
6c6afb84
JB
939 })
940 // We need to clean up the resources after our test
941 await pool.destroy()
942 })
943
944 it('Verify FAIR_SHARE strategy default tasks statistics requirements', async () => {
594bfb84 945 const workerChoiceStrategy = WorkerChoiceStrategies.FAIR_SHARE
10fcfaf4
JB
946 let pool = new FixedThreadPool(
947 max,
d710242d 948 './tests/worker-files/thread/testWorker.js',
594bfb84 949 { workerChoiceStrategy }
10fcfaf4 950 )
87de9ff5
JB
951 expect(
952 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
953 ).toStrictEqual({
932fc8be
JB
954 runTime: {
955 aggregate: true,
956 average: true,
957 median: false
958 },
959 waitTime: {
960 aggregate: false,
961 average: false,
962 median: false
963 },
5df69fab 964 elu: {
9adcefab
JB
965 aggregate: true,
966 average: true,
5df69fab
JB
967 median: false
968 }
86bf340d 969 })
fd7ebd49 970 await pool.destroy()
10fcfaf4
JB
971 pool = new DynamicThreadPool(
972 min,
973 max,
d710242d 974 './tests/worker-files/thread/testWorker.js',
594bfb84 975 { workerChoiceStrategy }
10fcfaf4 976 )
87de9ff5
JB
977 expect(
978 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
979 ).toStrictEqual({
932fc8be
JB
980 runTime: {
981 aggregate: true,
982 average: true,
983 median: false
984 },
985 waitTime: {
986 aggregate: false,
987 average: false,
988 median: false
989 },
5df69fab 990 elu: {
9adcefab
JB
991 aggregate: true,
992 average: true,
5df69fab
JB
993 median: false
994 }
86bf340d 995 })
10fcfaf4
JB
996 // We need to clean up the resources after our test
997 await pool.destroy()
998 })
999
23ff945a 1000 it('Verify FAIR_SHARE strategy can be run in a fixed pool', async () => {
23ff945a
JB
1001 const pool = new FixedThreadPool(
1002 max,
1003 './tests/worker-files/thread/testWorker.js',
1004 { workerChoiceStrategy: WorkerChoiceStrategies.FAIR_SHARE }
1005 )
1006 // TODO: Create a better test to cover `FairShareChoiceStrategy#choose`
ee9f5295 1007 const promises = new Set()
a20f0ba5
JB
1008 const maxMultiplier = 2
1009 for (let i = 0; i < max * maxMultiplier; i++) {
ee9f5295 1010 promises.add(pool.execute())
23ff945a 1011 }
e211bc18 1012 await Promise.all(promises)
138d29a8 1013 for (const workerNode of pool.workerNodes) {
71514351 1014 expect(workerNode.usage).toMatchObject({
a4e07f72 1015 tasks: {
d33be430 1016 executed: expect.any(Number),
a4e07f72
JB
1017 executing: 0,
1018 queued: 0,
df593701 1019 maxQueued: 0,
a4e07f72
JB
1020 failed: 0
1021 },
71514351 1022 runTime: expect.objectContaining({
a4e07f72 1023 history: expect.any(CircularArray)
71514351 1024 }),
a4e07f72 1025 waitTime: {
a4e07f72
JB
1026 history: expect.any(CircularArray)
1027 },
5df69fab 1028 elu: {
71514351 1029 idle: expect.objectContaining({
5df69fab 1030 history: expect.any(CircularArray)
71514351
JB
1031 }),
1032 active: expect.objectContaining({
5df69fab 1033 history: expect.any(CircularArray)
71514351 1034 })
5df69fab 1035 }
86bf340d 1036 })
465b2940
JB
1037 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
1038 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
d33be430
JB
1039 max * maxMultiplier
1040 )
71514351
JB
1041 if (workerNode.usage.runTime.aggregate == null) {
1042 expect(workerNode.usage.runTime.aggregate).toBeUndefined()
1043 } else {
1044 expect(workerNode.usage.runTime.aggregate).toBeGreaterThan(0)
1045 }
1046 if (workerNode.usage.runTime.average == null) {
1047 expect(workerNode.usage.runTime.average).toBeUndefined()
1048 } else {
1049 expect(workerNode.usage.runTime.average).toBeGreaterThan(0)
1050 }
1051 if (workerNode.usage.elu.utilization == null) {
1052 expect(workerNode.usage.elu.utilization).toBeUndefined()
1053 } else {
1054 expect(workerNode.usage.elu.utilization).toBeGreaterThanOrEqual(0)
1055 expect(workerNode.usage.elu.utilization).toBeLessThanOrEqual(1)
1056 }
138d29a8 1057 }
97a2abc3 1058 expect(
95c83464 1059 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
d710242d 1060 pool.workerChoiceStrategyContext.workerChoiceStrategy
b0d6ed8f 1061 ).workersVirtualTaskEndTimestamp.length
f06e48d8 1062 ).toBe(pool.workerNodes.length)
23ff945a
JB
1063 // We need to clean up the resources after our test
1064 await pool.destroy()
1065 })
1066
1067 it('Verify FAIR_SHARE strategy can be run in a dynamic pool', async () => {
23ff945a
JB
1068 const pool = new DynamicThreadPool(
1069 min,
1070 max,
1071 './tests/worker-files/thread/testWorker.js',
1072 { workerChoiceStrategy: WorkerChoiceStrategies.FAIR_SHARE }
1073 )
1074 // TODO: Create a better test to cover `FairShareChoiceStrategy#choose`
ee9f5295 1075 const promises = new Set()
f7070eee 1076 const maxMultiplier = 2
804a889e 1077 for (let i = 0; i < max * maxMultiplier; i++) {
ee9f5295 1078 promises.add(pool.execute())
23ff945a 1079 }
e211bc18 1080 await Promise.all(promises)
138d29a8 1081 for (const workerNode of pool.workerNodes) {
71514351 1082 expect(workerNode.usage).toMatchObject({
a4e07f72 1083 tasks: {
6c6afb84 1084 executed: expect.any(Number),
a4e07f72
JB
1085 executing: 0,
1086 queued: 0,
df593701 1087 maxQueued: 0,
a4e07f72
JB
1088 failed: 0
1089 },
71514351 1090 runTime: expect.objectContaining({
a4e07f72 1091 history: expect.any(CircularArray)
71514351 1092 }),
a4e07f72 1093 waitTime: {
a4e07f72
JB
1094 history: expect.any(CircularArray)
1095 },
5df69fab 1096 elu: {
71514351 1097 idle: expect.objectContaining({
5df69fab 1098 history: expect.any(CircularArray)
71514351
JB
1099 }),
1100 active: expect.objectContaining({
5df69fab 1101 history: expect.any(CircularArray)
71514351 1102 })
5df69fab 1103 }
86bf340d 1104 })
465b2940
JB
1105 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
1106 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
6c6afb84
JB
1107 max * maxMultiplier
1108 )
71514351
JB
1109 if (workerNode.usage.runTime.aggregate == null) {
1110 expect(workerNode.usage.runTime.aggregate).toBeUndefined()
1111 } else {
1112 expect(workerNode.usage.runTime.aggregate).toBeGreaterThan(0)
1113 }
1114 if (workerNode.usage.runTime.average == null) {
1115 expect(workerNode.usage.runTime.average).toBeUndefined()
1116 } else {
1117 expect(workerNode.usage.runTime.average).toBeGreaterThan(0)
1118 }
1119 if (workerNode.usage.elu.utilization == null) {
1120 expect(workerNode.usage.elu.utilization).toBeUndefined()
1121 } else {
1122 expect(workerNode.usage.elu.utilization).toBeGreaterThanOrEqual(0)
1123 expect(workerNode.usage.elu.utilization).toBeLessThanOrEqual(1)
1124 }
138d29a8 1125 }
2b4fddb8
JB
1126 expect(
1127 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1128 pool.workerChoiceStrategyContext.workerChoiceStrategy
b0d6ed8f 1129 ).workersVirtualTaskEndTimestamp.length
2b4fddb8 1130 ).toBe(pool.workerNodes.length)
23ff945a
JB
1131 // We need to clean up the resources after our test
1132 await pool.destroy()
1133 })
1134
9e775f96 1135 it('Verify FAIR_SHARE strategy can be run in a dynamic pool with median runtime statistic', async () => {
010d7020
JB
1136 const pool = new DynamicThreadPool(
1137 min,
1138 max,
1139 './tests/worker-files/thread/testWorker.js',
1140 {
1141 workerChoiceStrategy: WorkerChoiceStrategies.FAIR_SHARE,
1142 workerChoiceStrategyOptions: {
932fc8be 1143 runTime: { median: true }
010d7020
JB
1144 }
1145 }
1146 )
1147 // TODO: Create a better test to cover `FairShareChoiceStrategy#choose`
ee9f5295 1148 const promises = new Set()
010d7020
JB
1149 const maxMultiplier = 2
1150 for (let i = 0; i < max * maxMultiplier; i++) {
ee9f5295 1151 promises.add(pool.execute())
010d7020 1152 }
e211bc18 1153 await Promise.all(promises)
010d7020 1154 for (const workerNode of pool.workerNodes) {
71514351 1155 expect(workerNode.usage).toMatchObject({
a4e07f72 1156 tasks: {
6c6afb84 1157 executed: expect.any(Number),
a4e07f72
JB
1158 executing: 0,
1159 queued: 0,
df593701 1160 maxQueued: 0,
a4e07f72
JB
1161 failed: 0
1162 },
71514351 1163 runTime: expect.objectContaining({
a4e07f72 1164 history: expect.any(CircularArray)
71514351 1165 }),
a4e07f72 1166 waitTime: {
a4e07f72
JB
1167 history: expect.any(CircularArray)
1168 },
5df69fab 1169 elu: {
71514351 1170 idle: expect.objectContaining({
5df69fab 1171 history: expect.any(CircularArray)
71514351
JB
1172 }),
1173 active: expect.objectContaining({
5df69fab 1174 history: expect.any(CircularArray)
71514351 1175 })
5df69fab 1176 }
86bf340d 1177 })
465b2940
JB
1178 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
1179 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
6c6afb84
JB
1180 max * maxMultiplier
1181 )
71514351
JB
1182 if (workerNode.usage.runTime.aggregate == null) {
1183 expect(workerNode.usage.runTime.aggregate).toBeUndefined()
1184 } else {
1185 expect(workerNode.usage.runTime.aggregate).toBeGreaterThan(0)
1186 }
1187 if (workerNode.usage.runTime.median == null) {
1188 expect(workerNode.usage.runTime.median).toBeUndefined()
1189 } else {
1190 expect(workerNode.usage.runTime.median).toBeGreaterThan(0)
1191 }
1192 if (workerNode.usage.elu.utilization == null) {
1193 expect(workerNode.usage.elu.utilization).toBeUndefined()
1194 } else {
1195 expect(workerNode.usage.elu.utilization).toBeGreaterThanOrEqual(0)
1196 expect(workerNode.usage.elu.utilization).toBeLessThanOrEqual(1)
1197 }
010d7020 1198 }
2b4fddb8
JB
1199 expect(
1200 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1201 pool.workerChoiceStrategyContext.workerChoiceStrategy
b0d6ed8f 1202 ).workersVirtualTaskEndTimestamp.length
2b4fddb8 1203 ).toBe(pool.workerNodes.length)
010d7020
JB
1204 // We need to clean up the resources after our test
1205 await pool.destroy()
1206 })
1207
a6f7f1b4 1208 it('Verify FAIR_SHARE strategy internals are resets after setting it', async () => {
594bfb84 1209 const workerChoiceStrategy = WorkerChoiceStrategies.FAIR_SHARE
f0829c53 1210 let pool = new FixedThreadPool(
caeb9817
JB
1211 max,
1212 './tests/worker-files/thread/testWorker.js'
1213 )
1214 expect(
95c83464 1215 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 1216 workerChoiceStrategy
b0d6ed8f 1217 ).workersVirtualTaskEndTimestamp
08f3f44c
JB
1218 ).toBeInstanceOf(Array)
1219 expect(
1220 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1221 workerChoiceStrategy
b0d6ed8f 1222 ).workersVirtualTaskEndTimestamp.length
08f3f44c 1223 ).toBe(0)
2b4fddb8
JB
1224 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1225 workerChoiceStrategy
b0d6ed8f 1226 ).workersVirtualTaskEndTimestamp[0] = performance.now()
2b4fddb8
JB
1227 expect(
1228 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1229 workerChoiceStrategy
b0d6ed8f 1230 ).workersVirtualTaskEndTimestamp.length
2b4fddb8 1231 ).toBe(1)
594bfb84 1232 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
08f3f44c
JB
1233 expect(
1234 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1235 workerChoiceStrategy
b0d6ed8f 1236 ).workersVirtualTaskEndTimestamp
08f3f44c 1237 ).toBeInstanceOf(Array)
08f3f44c
JB
1238 expect(
1239 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1240 workerChoiceStrategy
b0d6ed8f 1241 ).workersVirtualTaskEndTimestamp.length
2b4fddb8 1242 ).toBe(0)
f0829c53
JB
1243 await pool.destroy()
1244 pool = new DynamicThreadPool(
1245 min,
1246 max,
1247 './tests/worker-files/thread/testWorker.js'
1248 )
1249 expect(
95c83464 1250 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 1251 workerChoiceStrategy
b0d6ed8f 1252 ).workersVirtualTaskEndTimestamp
08f3f44c 1253 ).toBeInstanceOf(Array)
2b4fddb8
JB
1254 expect(
1255 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1256 workerChoiceStrategy
b0d6ed8f 1257 ).workersVirtualTaskEndTimestamp.length
2b4fddb8 1258 ).toBe(0)
08f3f44c
JB
1259 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1260 workerChoiceStrategy
b0d6ed8f 1261 ).workersVirtualTaskEndTimestamp[0] = performance.now()
08f3f44c
JB
1262 expect(
1263 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1264 workerChoiceStrategy
b0d6ed8f 1265 ).workersVirtualTaskEndTimestamp.length
08f3f44c 1266 ).toBe(1)
594bfb84 1267 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
08f3f44c
JB
1268 expect(
1269 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1270 workerChoiceStrategy
b0d6ed8f 1271 ).workersVirtualTaskEndTimestamp
08f3f44c
JB
1272 ).toBeInstanceOf(Array)
1273 expect(
1274 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1275 workerChoiceStrategy
b0d6ed8f 1276 ).workersVirtualTaskEndTimestamp.length
08f3f44c 1277 ).toBe(0)
caeb9817
JB
1278 // We need to clean up the resources after our test
1279 await pool.destroy()
1280 })
1281
6c6afb84
JB
1282 it('Verify WEIGHTED_ROUND_ROBIN strategy default policy', async () => {
1283 const workerChoiceStrategy = WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
1284 let pool = new FixedThreadPool(
1285 max,
1286 './tests/worker-files/thread/testWorker.js',
1287 { workerChoiceStrategy }
1288 )
1289 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
b1aae695
JB
1290 dynamicWorkerUsage: false,
1291 dynamicWorkerReady: true
6c6afb84
JB
1292 })
1293 await pool.destroy()
1294 pool = new DynamicThreadPool(
1295 min,
1296 max,
1297 './tests/worker-files/thread/testWorker.js',
1298 { workerChoiceStrategy }
1299 )
1300 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
b1aae695
JB
1301 dynamicWorkerUsage: false,
1302 dynamicWorkerReady: true
6c6afb84
JB
1303 })
1304 // We need to clean up the resources after our test
1305 await pool.destroy()
1306 })
1307
1308 it('Verify WEIGHTED_ROUND_ROBIN strategy default tasks statistics requirements', async () => {
594bfb84 1309 const workerChoiceStrategy = WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
10fcfaf4
JB
1310 let pool = new FixedThreadPool(
1311 max,
d710242d 1312 './tests/worker-files/thread/testWorker.js',
594bfb84 1313 { workerChoiceStrategy }
10fcfaf4 1314 )
87de9ff5
JB
1315 expect(
1316 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
1317 ).toStrictEqual({
932fc8be
JB
1318 runTime: {
1319 aggregate: true,
1320 average: true,
1321 median: false
1322 },
1323 waitTime: {
1324 aggregate: false,
1325 average: false,
1326 median: false
1327 },
5df69fab
JB
1328 elu: {
1329 aggregate: false,
1330 average: false,
1331 median: false
1332 }
86bf340d 1333 })
fd7ebd49 1334 await pool.destroy()
10fcfaf4
JB
1335 pool = new DynamicThreadPool(
1336 min,
1337 max,
d710242d 1338 './tests/worker-files/thread/testWorker.js',
594bfb84 1339 { workerChoiceStrategy }
10fcfaf4 1340 )
87de9ff5
JB
1341 expect(
1342 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
1343 ).toStrictEqual({
932fc8be
JB
1344 runTime: {
1345 aggregate: true,
1346 average: true,
1347 median: false
1348 },
1349 waitTime: {
1350 aggregate: false,
1351 average: false,
1352 median: false
1353 },
5df69fab
JB
1354 elu: {
1355 aggregate: false,
1356 average: false,
1357 median: false
1358 }
86bf340d 1359 })
10fcfaf4
JB
1360 // We need to clean up the resources after our test
1361 await pool.destroy()
1362 })
1363
b3432a63 1364 it('Verify WEIGHTED_ROUND_ROBIN strategy can be run in a fixed pool', async () => {
b3432a63
JB
1365 const pool = new FixedThreadPool(
1366 max,
1367 './tests/worker-files/thread/testWorker.js',
1368 { workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN }
1369 )
1370 // TODO: Create a better test to cover `WeightedRoundRobinWorkerChoiceStrategy#choose`
ee9f5295 1371 const promises = new Set()
a20f0ba5
JB
1372 const maxMultiplier = 2
1373 for (let i = 0; i < max * maxMultiplier; i++) {
ee9f5295 1374 promises.add(pool.execute())
b3432a63 1375 }
e211bc18 1376 await Promise.all(promises)
138d29a8 1377 for (const workerNode of pool.workerNodes) {
465b2940 1378 expect(workerNode.usage).toStrictEqual({
a4e07f72
JB
1379 tasks: {
1380 executed: expect.any(Number),
1381 executing: 0,
1382 queued: 0,
df593701 1383 maxQueued: 0,
a4e07f72
JB
1384 failed: 0
1385 },
71514351 1386 runTime: expect.objectContaining({
a4e07f72 1387 history: expect.any(CircularArray)
71514351 1388 }),
a4e07f72 1389 waitTime: {
a4e07f72
JB
1390 history: expect.any(CircularArray)
1391 },
5df69fab
JB
1392 elu: {
1393 idle: {
5df69fab
JB
1394 history: expect.any(CircularArray)
1395 },
1396 active: {
5df69fab 1397 history: expect.any(CircularArray)
71514351 1398 }
5df69fab 1399 }
86bf340d 1400 })
465b2940
JB
1401 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
1402 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
a4e07f72
JB
1403 max * maxMultiplier
1404 )
71514351
JB
1405 if (workerNode.usage.runTime.aggregate == null) {
1406 expect(workerNode.usage.runTime.aggregate).toBeUndefined()
1407 } else {
1408 expect(workerNode.usage.runTime.aggregate).toBeGreaterThan(0)
1409 }
1410 if (workerNode.usage.runTime.average == null) {
1411 expect(workerNode.usage.runTime.average).toBeUndefined()
1412 } else {
1413 expect(workerNode.usage.runTime.average).toBeGreaterThan(0)
1414 }
138d29a8 1415 }
97a2abc3 1416 expect(
95c83464 1417 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
d710242d 1418 pool.workerChoiceStrategyContext.workerChoiceStrategy
08f3f44c
JB
1419 ).defaultWorkerWeight
1420 ).toBeGreaterThan(0)
1421 expect(
1422 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1423 pool.workerChoiceStrategyContext.workerChoiceStrategy
1424 ).workerVirtualTaskRunTime
1425 ).toBeGreaterThanOrEqual(0)
b3432a63
JB
1426 // We need to clean up the resources after our test
1427 await pool.destroy()
1428 })
1429
1430 it('Verify WEIGHTED_ROUND_ROBIN strategy can be run in a dynamic pool', async () => {
b3432a63
JB
1431 const pool = new DynamicThreadPool(
1432 min,
1433 max,
1434 './tests/worker-files/thread/testWorker.js',
1435 { workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN }
1436 )
1437 // TODO: Create a better test to cover `WeightedRoundRobinWorkerChoiceStrategy#choose`
ee9f5295 1438 const promises = new Set()
138d29a8 1439 const maxMultiplier = 2
5502c07c 1440 for (let i = 0; i < max * maxMultiplier; i++) {
ee9f5295 1441 promises.add(pool.execute())
b3432a63 1442 }
e211bc18 1443 await Promise.all(promises)
138d29a8 1444 for (const workerNode of pool.workerNodes) {
465b2940 1445 expect(workerNode.usage).toStrictEqual({
a4e07f72
JB
1446 tasks: {
1447 executed: expect.any(Number),
1448 executing: 0,
1449 queued: 0,
df593701 1450 maxQueued: 0,
a4e07f72
JB
1451 failed: 0
1452 },
b1aae695 1453 runTime: expect.objectContaining({
a4e07f72 1454 history: expect.any(CircularArray)
b1aae695 1455 }),
a4e07f72 1456 waitTime: {
a4e07f72
JB
1457 history: expect.any(CircularArray)
1458 },
5df69fab
JB
1459 elu: {
1460 idle: {
5df69fab
JB
1461 history: expect.any(CircularArray)
1462 },
1463 active: {
5df69fab 1464 history: expect.any(CircularArray)
71514351 1465 }
5df69fab 1466 }
86bf340d 1467 })
465b2940
JB
1468 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
1469 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
a4e07f72
JB
1470 max * maxMultiplier
1471 )
b1aae695
JB
1472 if (workerNode.usage.runTime.aggregate == null) {
1473 expect(workerNode.usage.runTime.aggregate).toBeUndefined()
1474 } else {
1475 expect(workerNode.usage.runTime.aggregate).toBeGreaterThan(0)
1476 }
1477 if (workerNode.usage.runTime.average == null) {
1478 expect(workerNode.usage.runTime.average).toBeUndefined()
1479 } else {
1480 expect(workerNode.usage.runTime.average).toBeGreaterThan(0)
1481 }
138d29a8 1482 }
2b4fddb8
JB
1483 expect(
1484 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1485 pool.workerChoiceStrategyContext.workerChoiceStrategy
1486 ).defaultWorkerWeight
1487 ).toBeGreaterThan(0)
1488 expect(
1489 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1490 pool.workerChoiceStrategyContext.workerChoiceStrategy
1491 ).workerVirtualTaskRunTime
1492 ).toBeGreaterThanOrEqual(0)
b3432a63
JB
1493 // We need to clean up the resources after our test
1494 await pool.destroy()
1495 })
1496
9e775f96 1497 it('Verify WEIGHTED_ROUND_ROBIN strategy can be run in a dynamic pool with median runtime statistic', async () => {
010d7020
JB
1498 const pool = new DynamicThreadPool(
1499 min,
1500 max,
1501 './tests/worker-files/thread/testWorker.js',
1502 {
1503 workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN,
1504 workerChoiceStrategyOptions: {
932fc8be 1505 runTime: { median: true }
010d7020
JB
1506 }
1507 }
1508 )
1509 // TODO: Create a better test to cover `WeightedRoundRobinWorkerChoiceStrategy#choose`
ee9f5295 1510 const promises = new Set()
010d7020
JB
1511 const maxMultiplier = 2
1512 for (let i = 0; i < max * maxMultiplier; i++) {
ee9f5295 1513 promises.add(pool.execute())
010d7020 1514 }
e211bc18 1515 await Promise.all(promises)
010d7020 1516 for (const workerNode of pool.workerNodes) {
465b2940 1517 expect(workerNode.usage).toStrictEqual({
a4e07f72
JB
1518 tasks: {
1519 executed: expect.any(Number),
1520 executing: 0,
1521 queued: 0,
df593701 1522 maxQueued: 0,
a4e07f72
JB
1523 failed: 0
1524 },
b1aae695 1525 runTime: expect.objectContaining({
a4e07f72 1526 history: expect.any(CircularArray)
b1aae695 1527 }),
a4e07f72 1528 waitTime: {
a4e07f72
JB
1529 history: expect.any(CircularArray)
1530 },
5df69fab
JB
1531 elu: {
1532 idle: {
5df69fab
JB
1533 history: expect.any(CircularArray)
1534 },
1535 active: {
5df69fab 1536 history: expect.any(CircularArray)
71514351 1537 }
5df69fab 1538 }
86bf340d 1539 })
465b2940
JB
1540 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
1541 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
a4e07f72
JB
1542 max * maxMultiplier
1543 )
b1aae695
JB
1544 if (workerNode.usage.runTime.aggregate == null) {
1545 expect(workerNode.usage.runTime.aggregate).toBeUndefined()
1546 } else {
1547 expect(workerNode.usage.runTime.aggregate).toBeGreaterThan(0)
1548 }
1549 if (workerNode.usage.runTime.median == null) {
1550 expect(workerNode.usage.runTime.median).toBeUndefined()
1551 } else {
1552 expect(workerNode.usage.runTime.median).toBeGreaterThan(0)
1553 }
010d7020 1554 }
08f3f44c
JB
1555 expect(
1556 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1557 pool.workerChoiceStrategyContext.workerChoiceStrategy
1558 ).defaultWorkerWeight
1559 ).toBeGreaterThan(0)
1560 expect(
1561 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1562 pool.workerChoiceStrategyContext.workerChoiceStrategy
1563 ).workerVirtualTaskRunTime
1564 ).toBeGreaterThanOrEqual(0)
010d7020
JB
1565 // We need to clean up the resources after our test
1566 await pool.destroy()
1567 })
1568
a6f7f1b4 1569 it('Verify WEIGHTED_ROUND_ROBIN strategy internals are resets after setting it', async () => {
594bfb84 1570 const workerChoiceStrategy = WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
f0829c53 1571 let pool = new FixedThreadPool(
caeb9817
JB
1572 max,
1573 './tests/worker-files/thread/testWorker.js'
1574 )
38f6e859 1575 expect(
95c83464 1576 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 1577 workerChoiceStrategy
9b106837 1578 ).nextWorkerNodeKey
b529c323 1579 ).toBeDefined()
38f6e859 1580 expect(
95c83464 1581 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 1582 workerChoiceStrategy
b529c323
JB
1583 ).defaultWorkerWeight
1584 ).toBeDefined()
caeb9817 1585 expect(
95c83464 1586 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 1587 workerChoiceStrategy
08f3f44c 1588 ).workerVirtualTaskRunTime
b529c323 1589 ).toBeDefined()
594bfb84 1590 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
a6f7f1b4 1591 expect(
95c83464 1592 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
d710242d 1593 pool.workerChoiceStrategyContext.workerChoiceStrategy
9b106837 1594 ).nextWorkerNodeKey
a6f7f1b4
JB
1595 ).toBe(0)
1596 expect(
95c83464 1597 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
d710242d 1598 pool.workerChoiceStrategyContext.workerChoiceStrategy
95c83464 1599 ).defaultWorkerWeight
a6f7f1b4 1600 ).toBeGreaterThan(0)
08f3f44c
JB
1601 expect(
1602 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1603 workerChoiceStrategy
1604 ).workerVirtualTaskRunTime
1605 ).toBe(0)
f0829c53
JB
1606 await pool.destroy()
1607 pool = new DynamicThreadPool(
1608 min,
1609 max,
1610 './tests/worker-files/thread/testWorker.js'
1611 )
38f6e859 1612 expect(
95c83464 1613 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 1614 workerChoiceStrategy
9b106837 1615 ).nextWorkerNodeKey
b529c323 1616 ).toBeDefined()
38f6e859 1617 expect(
95c83464 1618 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 1619 workerChoiceStrategy
b529c323
JB
1620 ).defaultWorkerWeight
1621 ).toBeDefined()
f0829c53 1622 expect(
95c83464 1623 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 1624 workerChoiceStrategy
08f3f44c 1625 ).workerVirtualTaskRunTime
b529c323 1626 ).toBeDefined()
594bfb84 1627 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
a6f7f1b4 1628 expect(
95c83464 1629 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
d710242d 1630 pool.workerChoiceStrategyContext.workerChoiceStrategy
9b106837 1631 ).nextWorkerNodeKey
a6f7f1b4
JB
1632 ).toBe(0)
1633 expect(
95c83464 1634 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
d710242d 1635 pool.workerChoiceStrategyContext.workerChoiceStrategy
95c83464 1636 ).defaultWorkerWeight
a6f7f1b4 1637 ).toBeGreaterThan(0)
08f3f44c
JB
1638 expect(
1639 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1640 workerChoiceStrategy
1641 ).workerVirtualTaskRunTime
1642 ).toBe(0)
caeb9817
JB
1643 // We need to clean up the resources after our test
1644 await pool.destroy()
1645 })
1646
6c6afb84
JB
1647 it('Verify INTERLEAVED_WEIGHTED_ROUND_ROBIN strategy default policy', async () => {
1648 const workerChoiceStrategy =
1649 WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
1650 let pool = new FixedThreadPool(
1651 max,
1652 './tests/worker-files/thread/testWorker.js',
1653 { workerChoiceStrategy }
1654 )
1655 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
b1aae695
JB
1656 dynamicWorkerUsage: false,
1657 dynamicWorkerReady: true
6c6afb84
JB
1658 })
1659 await pool.destroy()
1660 pool = new DynamicThreadPool(
1661 min,
1662 max,
1663 './tests/worker-files/thread/testWorker.js',
1664 { workerChoiceStrategy }
1665 )
1666 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
b1aae695
JB
1667 dynamicWorkerUsage: false,
1668 dynamicWorkerReady: true
6c6afb84
JB
1669 })
1670 // We need to clean up the resources after our test
1671 await pool.destroy()
1672 })
1673
1674 it('Verify INTERLEAVED_WEIGHTED_ROUND_ROBIN strategy default tasks statistics requirements', async () => {
e52fb978
JB
1675 const workerChoiceStrategy =
1676 WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
1677 let pool = new FixedThreadPool(
1678 max,
1679 './tests/worker-files/thread/testWorker.js',
1680 { workerChoiceStrategy }
1681 )
87de9ff5
JB
1682 expect(
1683 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
1684 ).toStrictEqual({
932fc8be
JB
1685 runTime: {
1686 aggregate: false,
1687 average: false,
1688 median: false
1689 },
1690 waitTime: {
1691 aggregate: false,
1692 average: false,
1693 median: false
1694 },
5df69fab
JB
1695 elu: {
1696 aggregate: false,
1697 average: false,
1698 median: false
1699 }
e52fb978
JB
1700 })
1701 await pool.destroy()
1702 pool = new DynamicThreadPool(
1703 min,
1704 max,
1705 './tests/worker-files/thread/testWorker.js',
1706 { workerChoiceStrategy }
1707 )
87de9ff5
JB
1708 expect(
1709 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
1710 ).toStrictEqual({
932fc8be
JB
1711 runTime: {
1712 aggregate: false,
1713 average: false,
1714 median: false
1715 },
1716 waitTime: {
1717 aggregate: false,
1718 average: false,
1719 median: false
1720 },
5df69fab
JB
1721 elu: {
1722 aggregate: false,
1723 average: false,
1724 median: false
1725 }
e52fb978
JB
1726 })
1727 // We need to clean up the resources after our test
1728 await pool.destroy()
1729 })
1730
e62e7646
JB
1731 it('Verify INTERLEAVED_WEIGHTED_ROUND_ROBIN strategy can be run in a fixed pool', async () => {
1732 const pool = new FixedThreadPool(
1733 max,
1734 './tests/worker-files/thread/testWorker.js',
1735 {
1736 workerChoiceStrategy:
1737 WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
1738 }
1739 )
1740 // TODO: Create a better test to cover `InterleavedWeightedRoundRobinWorkerChoiceStrategy#choose`
1741 const promises = new Set()
1742 const maxMultiplier = 2
1743 for (let i = 0; i < max * maxMultiplier; i++) {
1744 promises.add(pool.execute())
1745 }
1746 await Promise.all(promises)
1747 for (const workerNode of pool.workerNodes) {
465b2940 1748 expect(workerNode.usage).toStrictEqual({
a4e07f72
JB
1749 tasks: {
1750 executed: maxMultiplier,
1751 executing: 0,
1752 queued: 0,
df593701 1753 maxQueued: 0,
a4e07f72
JB
1754 failed: 0
1755 },
1756 runTime: {
a4e07f72
JB
1757 history: expect.any(CircularArray)
1758 },
1759 waitTime: {
a4e07f72
JB
1760 history: expect.any(CircularArray)
1761 },
5df69fab
JB
1762 elu: {
1763 idle: {
5df69fab
JB
1764 history: expect.any(CircularArray)
1765 },
1766 active: {
5df69fab 1767 history: expect.any(CircularArray)
71514351 1768 }
5df69fab 1769 }
e62e7646
JB
1770 })
1771 }
1772 expect(
1773 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1774 pool.workerChoiceStrategyContext.workerChoiceStrategy
1775 ).defaultWorkerWeight
1776 ).toBeGreaterThan(0)
1777 expect(
1778 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1779 pool.workerChoiceStrategyContext.workerChoiceStrategy
d33be430 1780 ).roundId
e62e7646
JB
1781 ).toBe(0)
1782 expect(
1783 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1784 pool.workerChoiceStrategyContext.workerChoiceStrategy
9b106837 1785 ).nextWorkerNodeKey
e62e7646
JB
1786 ).toBe(0)
1787 expect(
1788 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1789 pool.workerChoiceStrategyContext.workerChoiceStrategy
1790 ).roundWeights
1791 ).toStrictEqual([
1792 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1793 pool.workerChoiceStrategyContext.workerChoiceStrategy
1794 ).defaultWorkerWeight
1795 ])
1796 // We need to clean up the resources after our test
1797 await pool.destroy()
1798 })
1799
1800 it('Verify INTERLEAVED_WEIGHTED_ROUND_ROBIN strategy can be run in a dynamic pool', async () => {
1801 const pool = new DynamicThreadPool(
1802 min,
1803 max,
1804 './tests/worker-files/thread/testWorker.js',
1805 {
1806 workerChoiceStrategy:
1807 WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
1808 }
1809 )
1810 // TODO: Create a better test to cover `InterleavedWeightedRoundRobinWorkerChoiceStrategy#choose`
1811 const promises = new Set()
1812 const maxMultiplier = 2
1813 for (let i = 0; i < max * maxMultiplier; i++) {
1814 promises.add(pool.execute())
1815 }
1816 await Promise.all(promises)
1817 for (const workerNode of pool.workerNodes) {
465b2940 1818 expect(workerNode.usage).toStrictEqual({
a4e07f72 1819 tasks: {
b1aae695 1820 executed: expect.any(Number),
a4e07f72
JB
1821 executing: 0,
1822 queued: 0,
df593701 1823 maxQueued: 0,
a4e07f72
JB
1824 failed: 0
1825 },
1826 runTime: {
a4e07f72
JB
1827 history: expect.any(CircularArray)
1828 },
1829 waitTime: {
a4e07f72
JB
1830 history: expect.any(CircularArray)
1831 },
5df69fab
JB
1832 elu: {
1833 idle: {
5df69fab
JB
1834 history: expect.any(CircularArray)
1835 },
1836 active: {
5df69fab 1837 history: expect.any(CircularArray)
71514351 1838 }
5df69fab 1839 }
e62e7646
JB
1840 })
1841 }
1842 expect(
1843 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1844 pool.workerChoiceStrategyContext.workerChoiceStrategy
1845 ).defaultWorkerWeight
1846 ).toBeGreaterThan(0)
1847 expect(
1848 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1849 pool.workerChoiceStrategyContext.workerChoiceStrategy
d33be430 1850 ).roundId
e62e7646
JB
1851 ).toBe(0)
1852 expect(
1853 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1854 pool.workerChoiceStrategyContext.workerChoiceStrategy
9b106837 1855 ).nextWorkerNodeKey
d2c73f82 1856 ).toBe(0)
e62e7646
JB
1857 expect(
1858 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1859 pool.workerChoiceStrategyContext.workerChoiceStrategy
1860 ).roundWeights
1861 ).toStrictEqual([
1862 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1863 pool.workerChoiceStrategyContext.workerChoiceStrategy
1864 ).defaultWorkerWeight
1865 ])
1866 // We need to clean up the resources after our test
1867 await pool.destroy()
1868 })
1869
8c3ec188
JB
1870 it('Verify INTERLEAVED_WEIGHTED_ROUND_ROBIN strategy internals are resets after setting it', async () => {
1871 const workerChoiceStrategy =
1872 WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
1873 let pool = new FixedThreadPool(
1874 max,
1875 './tests/worker-files/thread/testWorker.js'
1876 )
1877 expect(
1878 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1879 workerChoiceStrategy
d33be430 1880 ).roundId
8c3ec188
JB
1881 ).toBeDefined()
1882 expect(
1883 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1884 workerChoiceStrategy
9b106837 1885 ).nextWorkerNodeKey
8c3ec188
JB
1886 ).toBeDefined()
1887 expect(
1888 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1889 workerChoiceStrategy
1890 ).defaultWorkerWeight
1891 ).toBeDefined()
1892 expect(
1893 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1894 workerChoiceStrategy
1895 ).roundWeights
1896 ).toBeDefined()
1897 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
1898 expect(
1899 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1900 workerChoiceStrategy
d33be430 1901 ).roundId
8c3ec188
JB
1902 ).toBe(0)
1903 expect(
1904 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1905 pool.workerChoiceStrategyContext.workerChoiceStrategy
9b106837 1906 ).nextWorkerNodeKey
8c3ec188
JB
1907 ).toBe(0)
1908 expect(
1909 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1910 pool.workerChoiceStrategyContext.workerChoiceStrategy
1911 ).defaultWorkerWeight
1912 ).toBeGreaterThan(0)
1913 expect(
1914 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1915 workerChoiceStrategy
1916 ).roundWeights
1917 ).toStrictEqual([
1918 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1919 pool.workerChoiceStrategyContext.workerChoiceStrategy
1920 ).defaultWorkerWeight
1921 ])
1922 await pool.destroy()
1923 pool = new DynamicThreadPool(
1924 min,
1925 max,
1926 './tests/worker-files/thread/testWorker.js'
1927 )
1928 expect(
1929 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1930 workerChoiceStrategy
d33be430 1931 ).roundId
8c3ec188
JB
1932 ).toBeDefined()
1933 expect(
1934 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1935 workerChoiceStrategy
9b106837 1936 ).nextWorkerNodeKey
8c3ec188
JB
1937 ).toBeDefined()
1938 expect(
1939 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1940 workerChoiceStrategy
1941 ).defaultWorkerWeight
1942 ).toBeDefined()
1943 expect(
1944 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1945 workerChoiceStrategy
1946 ).roundWeights
1947 ).toBeDefined()
1948 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
1949 expect(
1950 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1951 pool.workerChoiceStrategyContext.workerChoiceStrategy
9b106837 1952 ).nextWorkerNodeKey
8c3ec188
JB
1953 ).toBe(0)
1954 expect(
1955 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1956 pool.workerChoiceStrategyContext.workerChoiceStrategy
1957 ).defaultWorkerWeight
1958 ).toBeGreaterThan(0)
1959 expect(
1960 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1961 workerChoiceStrategy
1962 ).roundWeights
1963 ).toStrictEqual([
1964 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1965 pool.workerChoiceStrategyContext.workerChoiceStrategy
1966 ).defaultWorkerWeight
1967 ])
1968 // We need to clean up the resources after our test
1969 await pool.destroy()
1970 })
1971
89b09b26 1972 it('Verify unknown strategy throw error', () => {
a35560ba
S
1973 expect(
1974 () =>
1975 new DynamicThreadPool(
1976 min,
1977 max,
1978 './tests/worker-files/thread/testWorker.js',
1927ee67 1979 { workerChoiceStrategy: 'UNKNOWN_STRATEGY' }
a35560ba 1980 )
d4aeae5a 1981 ).toThrowError("Invalid worker choice strategy 'UNKNOWN_STRATEGY'")
a35560ba
S
1982 })
1983})