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