refactor: align worker choice strategy options namespace
[poolifier.git] / tests / pools / selection-strategies / selection-strategies.test.js
CommitLineData
a61a0724 1const { expect } = require('expect')
a35560ba
S
2const {
3 WorkerChoiceStrategies,
4 DynamicThreadPool,
2ced693a
JB
5 FixedThreadPool,
6 FixedClusterPool
cdace0e5 7} = require('../../../lib')
86bf340d 8const { CircularArray } = require('../../../lib/circular-array')
a35560ba
S
9
10describe('Selection strategies test suite', () => {
e1ffb94f
JB
11 const min = 0
12 const max = 3
13
a35560ba
S
14 it('Verify that WorkerChoiceStrategies enumeration provides string values', () => {
15 expect(WorkerChoiceStrategies.ROUND_ROBIN).toBe('ROUND_ROBIN')
e4543b14
JB
16 expect(WorkerChoiceStrategies.LEAST_USED).toBe('LEAST_USED')
17 expect(WorkerChoiceStrategies.LEAST_BUSY).toBe('LEAST_BUSY')
23ff945a 18 expect(WorkerChoiceStrategies.FAIR_SHARE).toBe('FAIR_SHARE')
b3432a63
JB
19 expect(WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN).toBe(
20 'WEIGHTED_ROUND_ROBIN'
21 )
feec6e8c
JB
22 expect(WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN).toBe(
23 'INTERLEAVED_WEIGHTED_ROUND_ROBIN'
24 )
a35560ba
S
25 })
26
e843b904 27 it('Verify ROUND_ROBIN strategy is the default at pool creation', async () => {
e843b904
JB
28 const pool = new DynamicThreadPool(
29 min,
30 max,
31 './tests/worker-files/thread/testWorker.js'
32 )
33 expect(pool.opts.workerChoiceStrategy).toBe(
34 WorkerChoiceStrategies.ROUND_ROBIN
35 )
36 // We need to clean up the resources after our test
37 await pool.destroy()
38 })
39
594bfb84
JB
40 it('Verify available strategies are taken at pool creation', async () => {
41 for (const workerChoiceStrategy of Object.values(WorkerChoiceStrategies)) {
42 const pool = new FixedThreadPool(
43 max,
44 './tests/worker-files/thread/testWorker.js',
45 { workerChoiceStrategy }
46 )
47 expect(pool.opts.workerChoiceStrategy).toBe(workerChoiceStrategy)
48 expect(pool.workerChoiceStrategyContext.workerChoiceStrategy).toBe(
49 workerChoiceStrategy
50 )
51 await pool.destroy()
52 }
d2f7b7a2
JB
53 })
54
594bfb84
JB
55 it('Verify available strategies can be set after pool creation', async () => {
56 for (const workerChoiceStrategy of Object.values(WorkerChoiceStrategies)) {
57 const pool = new DynamicThreadPool(
58 min,
59 max,
ec82cfa1 60 './tests/worker-files/thread/testWorker.js'
594bfb84
JB
61 )
62 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
63 expect(pool.opts.workerChoiceStrategy).toBe(workerChoiceStrategy)
64 expect(pool.workerChoiceStrategyContext.workerChoiceStrategy).toBe(
65 workerChoiceStrategy
66 )
67 await pool.destroy()
68 }
69 })
70
71 it('Verify available strategies default internals at pool creation', async () => {
72 const pool = new FixedThreadPool(
e843b904
JB
73 max,
74 './tests/worker-files/thread/testWorker.js'
75 )
594bfb84
JB
76 for (const workerChoiceStrategy of Object.values(WorkerChoiceStrategies)) {
77 if (workerChoiceStrategy === WorkerChoiceStrategies.ROUND_ROBIN) {
78 expect(
79 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
80 workerChoiceStrategy
81 ).nextWorkerNodeId
82 ).toBe(0)
83 } else if (workerChoiceStrategy === WorkerChoiceStrategies.FAIR_SHARE) {
08f3f44c
JB
84 expect(
85 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
86 workerChoiceStrategy
b0d6ed8f 87 ).workersVirtualTaskEndTimestamp
08f3f44c
JB
88 ).toBeInstanceOf(Array)
89 expect(
90 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
91 workerChoiceStrategy
b0d6ed8f 92 ).workersVirtualTaskEndTimestamp.length
08f3f44c 93 ).toBe(0)
594bfb84
JB
94 } else if (
95 workerChoiceStrategy === WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
96 ) {
97 expect(
98 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
99 workerChoiceStrategy
100 ).currentWorkerNodeId
101 ).toBe(0)
102 expect(
103 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
104 workerChoiceStrategy
105 ).defaultWorkerWeight
106 ).toBeGreaterThan(0)
08f3f44c
JB
107 expect(
108 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
109 workerChoiceStrategy
110 ).workerVirtualTaskRunTime
111 ).toBe(0)
594bfb84
JB
112 }
113 }
e843b904
JB
114 await pool.destroy()
115 })
116
10fcfaf4 117 it('Verify ROUND_ROBIN strategy default tasks usage statistics requirements', async () => {
594bfb84 118 const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN
10fcfaf4
JB
119 let pool = new FixedThreadPool(
120 max,
d710242d 121 './tests/worker-files/thread/testWorker.js',
594bfb84 122 { workerChoiceStrategy }
10fcfaf4 123 )
87de9ff5
JB
124 expect(
125 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
126 ).toStrictEqual({
932fc8be
JB
127 runTime: {
128 aggregate: false,
129 average: false,
130 median: false
131 },
132 waitTime: {
133 aggregate: false,
134 average: false,
135 median: false
136 },
d44d5953 137 elu: false
86bf340d 138 })
fd7ebd49 139 await pool.destroy()
10fcfaf4
JB
140 pool = new DynamicThreadPool(
141 min,
142 max,
d710242d 143 './tests/worker-files/thread/testWorker.js',
594bfb84 144 { workerChoiceStrategy }
10fcfaf4 145 )
87de9ff5
JB
146 expect(
147 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
148 ).toStrictEqual({
932fc8be
JB
149 runTime: {
150 aggregate: false,
151 average: false,
152 median: false
153 },
154 waitTime: {
155 aggregate: false,
156 average: false,
157 median: false
158 },
d44d5953 159 elu: false
86bf340d 160 })
10fcfaf4
JB
161 // We need to clean up the resources after our test
162 await pool.destroy()
163 })
164
bdaf31cd 165 it('Verify ROUND_ROBIN strategy can be run in a fixed pool', async () => {
bdaf31cd
JB
166 const pool = new FixedThreadPool(
167 max,
168 './tests/worker-files/thread/testWorker.js',
169 { workerChoiceStrategy: WorkerChoiceStrategies.ROUND_ROBIN }
170 )
bdaf31cd 171 // TODO: Create a better test to cover `RoundRobinWorkerChoiceStrategy#choose`
ee9f5295 172 const promises = new Set()
a20f0ba5
JB
173 const maxMultiplier = 2
174 for (let i = 0; i < max * maxMultiplier; i++) {
ee9f5295 175 promises.add(pool.execute())
e211bc18
JB
176 }
177 await Promise.all(promises)
178 for (const workerNode of pool.workerNodes) {
a4e07f72
JB
179 expect(workerNode.workerUsage).toStrictEqual({
180 tasks: {
181 executed: maxMultiplier,
182 executing: 0,
183 queued: 0,
184 failed: 0
185 },
186 runTime: {
932fc8be 187 aggregate: 0,
a4e07f72
JB
188 average: 0,
189 median: 0,
190 history: expect.any(CircularArray)
191 },
192 waitTime: {
932fc8be 193 aggregate: 0,
a4e07f72
JB
194 average: 0,
195 median: 0,
196 history: expect.any(CircularArray)
197 },
d44d5953 198 elu: undefined
e211bc18 199 })
bdaf31cd 200 }
9458090a
JB
201 expect(
202 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
203 WorkerChoiceStrategies.ROUND_ROBIN
204 ).nextWorkerNodeId
205 ).toBe(0)
bdaf31cd
JB
206 // We need to clean up the resources after our test
207 await pool.destroy()
208 })
209
210 it('Verify ROUND_ROBIN strategy can be run in a dynamic pool', async () => {
bdaf31cd
JB
211 const pool = new DynamicThreadPool(
212 min,
213 max,
214 './tests/worker-files/thread/testWorker.js',
215 { workerChoiceStrategy: WorkerChoiceStrategies.ROUND_ROBIN }
216 )
bdaf31cd 217 // TODO: Create a better test to cover `RoundRobinWorkerChoiceStrategy#choose`
ee9f5295 218 const promises = new Set()
a20f0ba5
JB
219 const maxMultiplier = 2
220 for (let i = 0; i < max * maxMultiplier; i++) {
ee9f5295 221 promises.add(pool.execute())
e211bc18
JB
222 }
223 await Promise.all(promises)
224 for (const workerNode of pool.workerNodes) {
a4e07f72
JB
225 expect(workerNode.workerUsage).toStrictEqual({
226 tasks: {
227 executed: maxMultiplier,
228 executing: 0,
229 queued: 0,
230 failed: 0
231 },
232 runTime: {
932fc8be 233 aggregate: 0,
a4e07f72
JB
234 average: 0,
235 median: 0,
236 history: expect.any(CircularArray)
237 },
238 waitTime: {
932fc8be 239 aggregate: 0,
a4e07f72
JB
240 average: 0,
241 median: 0,
242 history: expect.any(CircularArray)
243 },
d44d5953 244 elu: undefined
e211bc18 245 })
bdaf31cd 246 }
9458090a
JB
247 expect(
248 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
249 WorkerChoiceStrategies.ROUND_ROBIN
250 ).nextWorkerNodeId
251 ).toBe(0)
bdaf31cd
JB
252 // We need to clean up the resources after our test
253 await pool.destroy()
254 })
255
2ced693a 256 it('Verify ROUND_ROBIN strategy runtime behavior', async () => {
594bfb84 257 const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN
2ced693a
JB
258 let pool = new FixedClusterPool(
259 max,
594bfb84
JB
260 './tests/worker-files/cluster/testWorker.js',
261 { workerChoiceStrategy }
2ced693a
JB
262 )
263 let results = new Set()
264 for (let i = 0; i < max; i++) {
20dcad1a 265 results.add(pool.workerNodes[pool.chooseWorkerNode()].worker.id)
2ced693a
JB
266 }
267 expect(results.size).toBe(max)
268 await pool.destroy()
594bfb84
JB
269 pool = new FixedThreadPool(
270 max,
271 './tests/worker-files/thread/testWorker.js',
272 { workerChoiceStrategy }
273 )
2ced693a
JB
274 results = new Set()
275 for (let i = 0; i < max; i++) {
20dcad1a 276 results.add(pool.workerNodes[pool.chooseWorkerNode()].worker.threadId)
2ced693a
JB
277 }
278 expect(results.size).toBe(max)
279 await pool.destroy()
280 })
281
a6f7f1b4 282 it('Verify ROUND_ROBIN strategy internals are resets after setting it', async () => {
594bfb84 283 const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN
a6f7f1b4
JB
284 let pool = new FixedThreadPool(
285 max,
286 './tests/worker-files/thread/testWorker.js',
287 { workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN }
288 )
38f6e859 289 expect(
95c83464 290 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 291 workerChoiceStrategy
f06e48d8 292 ).nextWorkerNodeId
b529c323 293 ).toBeDefined()
594bfb84 294 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
a6f7f1b4 295 expect(
95c83464 296 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
d710242d 297 pool.workerChoiceStrategyContext.workerChoiceStrategy
f06e48d8 298 ).nextWorkerNodeId
a6f7f1b4
JB
299 ).toBe(0)
300 await pool.destroy()
301 pool = new DynamicThreadPool(
302 min,
303 max,
304 './tests/worker-files/thread/testWorker.js',
305 { workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN }
306 )
38f6e859 307 expect(
95c83464 308 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 309 workerChoiceStrategy
f06e48d8 310 ).nextWorkerNodeId
b529c323 311 ).toBeDefined()
594bfb84 312 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
a6f7f1b4 313 expect(
95c83464 314 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
d710242d 315 pool.workerChoiceStrategyContext.workerChoiceStrategy
f06e48d8 316 ).nextWorkerNodeId
a6f7f1b4
JB
317 ).toBe(0)
318 // We need to clean up the resources after our test
319 await pool.destroy()
320 })
321
e4543b14
JB
322 it('Verify LEAST_USED strategy default tasks usage statistics requirements', async () => {
323 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_USED
10fcfaf4
JB
324 let pool = new FixedThreadPool(
325 max,
d710242d 326 './tests/worker-files/thread/testWorker.js',
594bfb84 327 { workerChoiceStrategy }
10fcfaf4 328 )
87de9ff5
JB
329 expect(
330 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
331 ).toStrictEqual({
932fc8be
JB
332 runTime: {
333 aggregate: false,
334 average: false,
335 median: false
336 },
337 waitTime: {
338 aggregate: false,
339 average: false,
340 median: false
341 },
d44d5953 342 elu: false
86bf340d 343 })
fd7ebd49 344 await pool.destroy()
10fcfaf4
JB
345 pool = new DynamicThreadPool(
346 min,
347 max,
d710242d 348 './tests/worker-files/thread/testWorker.js',
594bfb84 349 { workerChoiceStrategy }
10fcfaf4 350 )
87de9ff5
JB
351 expect(
352 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
353 ).toStrictEqual({
932fc8be
JB
354 runTime: {
355 aggregate: false,
356 average: false,
357 median: false
358 },
359 waitTime: {
360 aggregate: false,
361 average: false,
362 median: false
363 },
d44d5953 364 elu: false
86bf340d 365 })
10fcfaf4
JB
366 // We need to clean up the resources after our test
367 await pool.destroy()
368 })
369
e4543b14 370 it('Verify LEAST_USED strategy can be run in a fixed pool', async () => {
b98ec2e6
JB
371 const pool = new FixedThreadPool(
372 max,
373 './tests/worker-files/thread/testWorker.js',
e4543b14 374 { workerChoiceStrategy: WorkerChoiceStrategies.LEAST_USED }
b98ec2e6 375 )
e4543b14 376 // TODO: Create a better test to cover `LeastUsedWorkerChoiceStrategy#choose`
ee9f5295 377 const promises = new Set()
a20f0ba5
JB
378 const maxMultiplier = 2
379 for (let i = 0; i < max * maxMultiplier; i++) {
ee9f5295 380 promises.add(pool.execute())
e211bc18
JB
381 }
382 await Promise.all(promises)
383 for (const workerNode of pool.workerNodes) {
a4e07f72
JB
384 expect(workerNode.workerUsage).toStrictEqual({
385 tasks: {
386 executed: maxMultiplier,
387 executing: 0,
388 queued: 0,
389 failed: 0
390 },
391 runTime: {
932fc8be 392 aggregate: 0,
a4e07f72
JB
393 average: 0,
394 median: 0,
395 history: expect.any(CircularArray)
396 },
397 waitTime: {
932fc8be 398 aggregate: 0,
a4e07f72
JB
399 average: 0,
400 median: 0,
401 history: expect.any(CircularArray)
402 },
d44d5953 403 elu: undefined
e211bc18 404 })
a35560ba 405 }
a35560ba
S
406 // We need to clean up the resources after our test
407 await pool.destroy()
408 })
409
e4543b14 410 it('Verify LEAST_USED strategy can be run in a dynamic pool', async () => {
ff5e76e1
JB
411 const pool = new DynamicThreadPool(
412 min,
413 max,
414 './tests/worker-files/thread/testWorker.js',
e4543b14 415 { workerChoiceStrategy: WorkerChoiceStrategies.LEAST_USED }
ff5e76e1 416 )
e4543b14 417 // TODO: Create a better test to cover `LeastUsedWorkerChoiceStrategy#choose`
ee9f5295 418 const promises = new Set()
a20f0ba5
JB
419 const maxMultiplier = 2
420 for (let i = 0; i < max * maxMultiplier; i++) {
ee9f5295 421 promises.add(pool.execute())
e211bc18
JB
422 }
423 await Promise.all(promises)
424 for (const workerNode of pool.workerNodes) {
a4e07f72
JB
425 expect(workerNode.workerUsage).toStrictEqual({
426 tasks: {
427 executed: maxMultiplier,
428 executing: 0,
429 queued: 0,
430 failed: 0
431 },
432 runTime: {
932fc8be 433 aggregate: 0,
a4e07f72
JB
434 average: 0,
435 median: 0,
436 history: expect.any(CircularArray)
437 },
438 waitTime: {
932fc8be 439 aggregate: 0,
a4e07f72
JB
440 average: 0,
441 median: 0,
442 history: expect.any(CircularArray)
443 },
444
d44d5953 445 elu: undefined
e211bc18 446 })
168c526f 447 }
168c526f
JB
448 // We need to clean up the resources after our test
449 await pool.destroy()
450 })
451
e4543b14
JB
452 it('Verify LEAST_BUSY strategy default tasks usage statistics requirements', async () => {
453 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_BUSY
168c526f
JB
454 let pool = new FixedThreadPool(
455 max,
d710242d 456 './tests/worker-files/thread/testWorker.js',
594bfb84 457 { workerChoiceStrategy }
168c526f 458 )
87de9ff5
JB
459 expect(
460 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
461 ).toStrictEqual({
932fc8be
JB
462 runTime: {
463 aggregate: true,
464 average: false,
465 median: false
466 },
467 waitTime: {
468 aggregate: true,
469 average: false,
470 median: false
471 },
d44d5953 472 elu: false
86bf340d 473 })
168c526f
JB
474 await pool.destroy()
475 pool = new DynamicThreadPool(
476 min,
477 max,
d710242d 478 './tests/worker-files/thread/testWorker.js',
594bfb84 479 { workerChoiceStrategy }
168c526f 480 )
87de9ff5
JB
481 expect(
482 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
483 ).toStrictEqual({
932fc8be
JB
484 runTime: {
485 aggregate: true,
486 average: false,
487 median: false
488 },
489 waitTime: {
490 aggregate: true,
491 average: false,
492 median: false
493 },
d44d5953 494 elu: false
86bf340d 495 })
168c526f
JB
496 // We need to clean up the resources after our test
497 await pool.destroy()
498 })
499
e4543b14 500 it('Verify LEAST_BUSY strategy can be run in a fixed pool', async () => {
168c526f
JB
501 const pool = new FixedThreadPool(
502 max,
503 './tests/worker-files/thread/testWorker.js',
e4543b14 504 { workerChoiceStrategy: WorkerChoiceStrategies.LEAST_BUSY }
168c526f 505 )
e4543b14 506 // TODO: Create a better test to cover `LeastBusyWorkerChoiceStrategy#choose`
ee9f5295 507 const promises = new Set()
a20f0ba5
JB
508 const maxMultiplier = 2
509 for (let i = 0; i < max * maxMultiplier; i++) {
ee9f5295 510 promises.add(pool.execute())
e211bc18
JB
511 }
512 await Promise.all(promises)
513 for (const workerNode of pool.workerNodes) {
a4e07f72
JB
514 expect(workerNode.workerUsage).toStrictEqual({
515 tasks: {
516 executed: expect.any(Number),
517 executing: 0,
518 queued: 0,
519 failed: 0
520 },
521 runTime: {
932fc8be 522 aggregate: expect.any(Number),
a4e07f72
JB
523 average: 0,
524 median: 0,
525 history: expect.any(CircularArray)
526 },
527 waitTime: {
932fc8be 528 aggregate: expect.any(Number),
a4e07f72
JB
529 average: 0,
530 median: 0,
531 history: expect.any(CircularArray)
532 },
d44d5953 533 elu: undefined
e211bc18 534 })
a4e07f72
JB
535 expect(workerNode.workerUsage.tasks.executed).toBeGreaterThanOrEqual(0)
536 expect(workerNode.workerUsage.tasks.executed).toBeLessThanOrEqual(
537 max * maxMultiplier
538 )
932fc8be
JB
539 expect(workerNode.workerUsage.runTime.aggregate).toBeGreaterThanOrEqual(0)
540 expect(workerNode.workerUsage.waitTime.aggregate).toBeGreaterThanOrEqual(
a4e07f72
JB
541 0
542 )
168c526f 543 }
168c526f
JB
544 // We need to clean up the resources after our test
545 await pool.destroy()
546 })
547
e4543b14 548 it('Verify LEAST_BUSY strategy can be run in a dynamic pool', async () => {
168c526f
JB
549 const pool = new DynamicThreadPool(
550 min,
551 max,
552 './tests/worker-files/thread/testWorker.js',
e4543b14 553 { workerChoiceStrategy: WorkerChoiceStrategies.LEAST_BUSY }
168c526f 554 )
e4543b14 555 // TODO: Create a better test to cover `LeastBusyWorkerChoiceStrategy#choose`
ee9f5295 556 const promises = new Set()
a20f0ba5
JB
557 const maxMultiplier = 2
558 for (let i = 0; i < max * maxMultiplier; i++) {
ee9f5295 559 promises.add(pool.execute())
e211bc18
JB
560 }
561 await Promise.all(promises)
562 for (const workerNode of pool.workerNodes) {
a4e07f72
JB
563 expect(workerNode.workerUsage).toStrictEqual({
564 tasks: {
565 executed: expect.any(Number),
566 executing: 0,
567 queued: 0,
568 failed: 0
569 },
570 runTime: {
932fc8be 571 aggregate: expect.any(Number),
a4e07f72
JB
572 average: 0,
573 median: 0,
574 history: expect.any(CircularArray)
575 },
576 waitTime: {
932fc8be 577 aggregate: expect.any(Number),
a4e07f72
JB
578 average: 0,
579 median: 0,
580 history: expect.any(CircularArray)
581 },
d44d5953 582 elu: undefined
e211bc18 583 })
a4e07f72
JB
584 expect(workerNode.workerUsage.tasks.executed).toBeGreaterThan(0)
585 expect(workerNode.workerUsage.tasks.executed).toBeLessThanOrEqual(
586 max * maxMultiplier
587 )
932fc8be
JB
588 expect(workerNode.workerUsage.runTime.aggregate).toBeGreaterThan(0)
589 expect(workerNode.workerUsage.waitTime.aggregate).toBeGreaterThan(0)
ff5e76e1 590 }
ff5e76e1
JB
591 // We need to clean up the resources after our test
592 await pool.destroy()
593 })
594
10fcfaf4 595 it('Verify FAIR_SHARE strategy default tasks usage statistics requirements', async () => {
594bfb84 596 const workerChoiceStrategy = WorkerChoiceStrategies.FAIR_SHARE
10fcfaf4
JB
597 let pool = new FixedThreadPool(
598 max,
d710242d 599 './tests/worker-files/thread/testWorker.js',
594bfb84 600 { workerChoiceStrategy }
10fcfaf4 601 )
87de9ff5
JB
602 expect(
603 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
604 ).toStrictEqual({
932fc8be
JB
605 runTime: {
606 aggregate: true,
607 average: true,
608 median: false
609 },
610 waitTime: {
611 aggregate: false,
612 average: false,
613 median: false
614 },
d44d5953 615 elu: false
86bf340d 616 })
fd7ebd49 617 await pool.destroy()
10fcfaf4
JB
618 pool = new DynamicThreadPool(
619 min,
620 max,
d710242d 621 './tests/worker-files/thread/testWorker.js',
594bfb84 622 { workerChoiceStrategy }
10fcfaf4 623 )
87de9ff5
JB
624 expect(
625 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
626 ).toStrictEqual({
932fc8be
JB
627 runTime: {
628 aggregate: true,
629 average: true,
630 median: false
631 },
632 waitTime: {
633 aggregate: false,
634 average: false,
635 median: false
636 },
d44d5953 637 elu: false
86bf340d 638 })
10fcfaf4
JB
639 // We need to clean up the resources after our test
640 await pool.destroy()
641 })
642
23ff945a 643 it('Verify FAIR_SHARE strategy can be run in a fixed pool', async () => {
23ff945a
JB
644 const pool = new FixedThreadPool(
645 max,
646 './tests/worker-files/thread/testWorker.js',
647 { workerChoiceStrategy: WorkerChoiceStrategies.FAIR_SHARE }
648 )
649 // TODO: Create a better test to cover `FairShareChoiceStrategy#choose`
ee9f5295 650 const promises = new Set()
a20f0ba5
JB
651 const maxMultiplier = 2
652 for (let i = 0; i < max * maxMultiplier; i++) {
ee9f5295 653 promises.add(pool.execute())
23ff945a 654 }
e211bc18 655 await Promise.all(promises)
138d29a8 656 for (const workerNode of pool.workerNodes) {
a4e07f72
JB
657 expect(workerNode.workerUsage).toStrictEqual({
658 tasks: {
659 executed: maxMultiplier,
660 executing: 0,
661 queued: 0,
662 failed: 0
663 },
664 runTime: {
932fc8be 665 aggregate: expect.any(Number),
a4e07f72
JB
666 average: expect.any(Number),
667 median: 0,
668 history: expect.any(CircularArray)
669 },
670 waitTime: {
932fc8be 671 aggregate: 0,
a4e07f72
JB
672 average: 0,
673 median: 0,
674 history: expect.any(CircularArray)
675 },
d44d5953 676 elu: undefined
86bf340d 677 })
932fc8be 678 expect(workerNode.workerUsage.runTime.aggregate).toBeGreaterThan(0)
a4e07f72 679 expect(workerNode.workerUsage.runTime.average).toBeGreaterThan(0)
138d29a8 680 }
97a2abc3 681 expect(
95c83464 682 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
d710242d 683 pool.workerChoiceStrategyContext.workerChoiceStrategy
b0d6ed8f 684 ).workersVirtualTaskEndTimestamp.length
f06e48d8 685 ).toBe(pool.workerNodes.length)
23ff945a
JB
686 // We need to clean up the resources after our test
687 await pool.destroy()
688 })
689
690 it('Verify FAIR_SHARE strategy can be run in a dynamic pool', async () => {
23ff945a
JB
691 const pool = new DynamicThreadPool(
692 min,
693 max,
694 './tests/worker-files/thread/testWorker.js',
695 { workerChoiceStrategy: WorkerChoiceStrategies.FAIR_SHARE }
696 )
697 // TODO: Create a better test to cover `FairShareChoiceStrategy#choose`
ee9f5295 698 const promises = new Set()
f7070eee 699 const maxMultiplier = 2
804a889e 700 for (let i = 0; i < max * maxMultiplier; i++) {
ee9f5295 701 promises.add(pool.execute())
23ff945a 702 }
e211bc18 703 await Promise.all(promises)
138d29a8 704 for (const workerNode of pool.workerNodes) {
a4e07f72
JB
705 expect(workerNode.workerUsage).toStrictEqual({
706 tasks: {
707 executed: maxMultiplier,
708 executing: 0,
709 queued: 0,
710 failed: 0
711 },
712 runTime: {
932fc8be 713 aggregate: expect.any(Number),
a4e07f72
JB
714 average: expect.any(Number),
715 median: 0,
716 history: expect.any(CircularArray)
717 },
718 waitTime: {
932fc8be 719 aggregate: 0,
a4e07f72
JB
720 average: 0,
721 median: 0,
722 history: expect.any(CircularArray)
723 },
d44d5953 724 elu: undefined
86bf340d 725 })
932fc8be 726 expect(workerNode.workerUsage.runTime.aggregate).toBeGreaterThan(0)
a4e07f72 727 expect(workerNode.workerUsage.runTime.average).toBeGreaterThan(0)
138d29a8 728 }
2b4fddb8
JB
729 expect(
730 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
731 pool.workerChoiceStrategyContext.workerChoiceStrategy
b0d6ed8f 732 ).workersVirtualTaskEndTimestamp.length
2b4fddb8 733 ).toBe(pool.workerNodes.length)
23ff945a
JB
734 // We need to clean up the resources after our test
735 await pool.destroy()
736 })
737
9e775f96 738 it('Verify FAIR_SHARE strategy can be run in a dynamic pool with median runtime statistic', async () => {
010d7020
JB
739 const pool = new DynamicThreadPool(
740 min,
741 max,
742 './tests/worker-files/thread/testWorker.js',
743 {
744 workerChoiceStrategy: WorkerChoiceStrategies.FAIR_SHARE,
745 workerChoiceStrategyOptions: {
932fc8be 746 runTime: { median: true }
010d7020
JB
747 }
748 }
749 )
750 // TODO: Create a better test to cover `FairShareChoiceStrategy#choose`
ee9f5295 751 const promises = new Set()
010d7020
JB
752 const maxMultiplier = 2
753 for (let i = 0; i < max * maxMultiplier; i++) {
ee9f5295 754 promises.add(pool.execute())
010d7020 755 }
e211bc18 756 await Promise.all(promises)
010d7020 757 for (const workerNode of pool.workerNodes) {
a4e07f72
JB
758 expect(workerNode.workerUsage).toStrictEqual({
759 tasks: {
760 executed: maxMultiplier,
761 executing: 0,
762 queued: 0,
763 failed: 0
764 },
765 runTime: {
932fc8be 766 aggregate: expect.any(Number),
a4e07f72
JB
767 average: 0,
768 median: expect.any(Number),
769 history: expect.any(CircularArray)
770 },
771 waitTime: {
932fc8be 772 aggregate: 0,
a4e07f72
JB
773 average: 0,
774 median: 0,
775 history: expect.any(CircularArray)
776 },
d44d5953 777 elu: undefined
86bf340d 778 })
932fc8be 779 expect(workerNode.workerUsage.runTime.aggregate).toBeGreaterThan(0)
a4e07f72 780 expect(workerNode.workerUsage.runTime.median).toBeGreaterThan(0)
010d7020 781 }
2b4fddb8
JB
782 expect(
783 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
784 pool.workerChoiceStrategyContext.workerChoiceStrategy
b0d6ed8f 785 ).workersVirtualTaskEndTimestamp.length
2b4fddb8 786 ).toBe(pool.workerNodes.length)
010d7020
JB
787 // We need to clean up the resources after our test
788 await pool.destroy()
789 })
790
a6f7f1b4 791 it('Verify FAIR_SHARE strategy internals are resets after setting it', async () => {
594bfb84 792 const workerChoiceStrategy = WorkerChoiceStrategies.FAIR_SHARE
f0829c53 793 let pool = new FixedThreadPool(
caeb9817
JB
794 max,
795 './tests/worker-files/thread/testWorker.js'
796 )
797 expect(
95c83464 798 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 799 workerChoiceStrategy
b0d6ed8f 800 ).workersVirtualTaskEndTimestamp
08f3f44c
JB
801 ).toBeInstanceOf(Array)
802 expect(
803 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
804 workerChoiceStrategy
b0d6ed8f 805 ).workersVirtualTaskEndTimestamp.length
08f3f44c 806 ).toBe(0)
2b4fddb8
JB
807 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
808 workerChoiceStrategy
b0d6ed8f 809 ).workersVirtualTaskEndTimestamp[0] = performance.now()
2b4fddb8
JB
810 expect(
811 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
812 workerChoiceStrategy
b0d6ed8f 813 ).workersVirtualTaskEndTimestamp.length
2b4fddb8 814 ).toBe(1)
594bfb84 815 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
08f3f44c
JB
816 expect(
817 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
818 workerChoiceStrategy
b0d6ed8f 819 ).workersVirtualTaskEndTimestamp
08f3f44c 820 ).toBeInstanceOf(Array)
08f3f44c
JB
821 expect(
822 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
823 workerChoiceStrategy
b0d6ed8f 824 ).workersVirtualTaskEndTimestamp.length
2b4fddb8 825 ).toBe(0)
f0829c53
JB
826 await pool.destroy()
827 pool = new DynamicThreadPool(
828 min,
829 max,
830 './tests/worker-files/thread/testWorker.js'
831 )
832 expect(
95c83464 833 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 834 workerChoiceStrategy
b0d6ed8f 835 ).workersVirtualTaskEndTimestamp
08f3f44c 836 ).toBeInstanceOf(Array)
2b4fddb8
JB
837 expect(
838 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
839 workerChoiceStrategy
b0d6ed8f 840 ).workersVirtualTaskEndTimestamp.length
2b4fddb8 841 ).toBe(0)
08f3f44c
JB
842 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
843 workerChoiceStrategy
b0d6ed8f 844 ).workersVirtualTaskEndTimestamp[0] = performance.now()
08f3f44c
JB
845 expect(
846 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
847 workerChoiceStrategy
b0d6ed8f 848 ).workersVirtualTaskEndTimestamp.length
08f3f44c 849 ).toBe(1)
594bfb84 850 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
08f3f44c
JB
851 expect(
852 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
853 workerChoiceStrategy
b0d6ed8f 854 ).workersVirtualTaskEndTimestamp
08f3f44c
JB
855 ).toBeInstanceOf(Array)
856 expect(
857 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
858 workerChoiceStrategy
b0d6ed8f 859 ).workersVirtualTaskEndTimestamp.length
08f3f44c 860 ).toBe(0)
caeb9817
JB
861 // We need to clean up the resources after our test
862 await pool.destroy()
863 })
864
10fcfaf4 865 it('Verify WEIGHTED_ROUND_ROBIN strategy default tasks usage statistics requirements', async () => {
594bfb84 866 const workerChoiceStrategy = WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
10fcfaf4
JB
867 let pool = new FixedThreadPool(
868 max,
d710242d 869 './tests/worker-files/thread/testWorker.js',
594bfb84 870 { workerChoiceStrategy }
10fcfaf4 871 )
87de9ff5
JB
872 expect(
873 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
874 ).toStrictEqual({
932fc8be
JB
875 runTime: {
876 aggregate: true,
877 average: true,
878 median: false
879 },
880 waitTime: {
881 aggregate: false,
882 average: false,
883 median: false
884 },
d44d5953 885 elu: false
86bf340d 886 })
fd7ebd49 887 await pool.destroy()
10fcfaf4
JB
888 pool = new DynamicThreadPool(
889 min,
890 max,
d710242d 891 './tests/worker-files/thread/testWorker.js',
594bfb84 892 { workerChoiceStrategy }
10fcfaf4 893 )
87de9ff5
JB
894 expect(
895 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
896 ).toStrictEqual({
932fc8be
JB
897 runTime: {
898 aggregate: true,
899 average: true,
900 median: false
901 },
902 waitTime: {
903 aggregate: false,
904 average: false,
905 median: false
906 },
d44d5953 907 elu: false
86bf340d 908 })
10fcfaf4
JB
909 // We need to clean up the resources after our test
910 await pool.destroy()
911 })
912
b3432a63 913 it('Verify WEIGHTED_ROUND_ROBIN strategy can be run in a fixed pool', async () => {
b3432a63
JB
914 const pool = new FixedThreadPool(
915 max,
916 './tests/worker-files/thread/testWorker.js',
917 { workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN }
918 )
919 // TODO: Create a better test to cover `WeightedRoundRobinWorkerChoiceStrategy#choose`
ee9f5295 920 const promises = new Set()
a20f0ba5
JB
921 const maxMultiplier = 2
922 for (let i = 0; i < max * maxMultiplier; i++) {
ee9f5295 923 promises.add(pool.execute())
b3432a63 924 }
e211bc18 925 await Promise.all(promises)
138d29a8 926 for (const workerNode of pool.workerNodes) {
a4e07f72
JB
927 expect(workerNode.workerUsage).toStrictEqual({
928 tasks: {
929 executed: expect.any(Number),
930 executing: 0,
931 queued: 0,
932 failed: 0
933 },
934 runTime: {
932fc8be 935 aggregate: expect.any(Number),
a4e07f72
JB
936 average: expect.any(Number),
937 median: 0,
938 history: expect.any(CircularArray)
939 },
940 waitTime: {
932fc8be 941 aggregate: 0,
a4e07f72
JB
942 average: 0,
943 median: 0,
944 history: expect.any(CircularArray)
945 },
d44d5953 946 elu: undefined
86bf340d 947 })
a4e07f72
JB
948 expect(workerNode.workerUsage.tasks.executed).toBeGreaterThanOrEqual(0)
949 expect(workerNode.workerUsage.tasks.executed).toBeLessThanOrEqual(
950 max * maxMultiplier
951 )
932fc8be 952 expect(workerNode.workerUsage.runTime.aggregate).toBeGreaterThanOrEqual(0)
a4e07f72 953 expect(workerNode.workerUsage.runTime.average).toBeGreaterThanOrEqual(0)
138d29a8 954 }
97a2abc3 955 expect(
95c83464 956 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
d710242d 957 pool.workerChoiceStrategyContext.workerChoiceStrategy
08f3f44c
JB
958 ).defaultWorkerWeight
959 ).toBeGreaterThan(0)
960 expect(
961 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
962 pool.workerChoiceStrategyContext.workerChoiceStrategy
963 ).workerVirtualTaskRunTime
964 ).toBeGreaterThanOrEqual(0)
b3432a63
JB
965 // We need to clean up the resources after our test
966 await pool.destroy()
967 })
968
969 it('Verify WEIGHTED_ROUND_ROBIN strategy can be run in a dynamic pool', async () => {
b3432a63
JB
970 const pool = new DynamicThreadPool(
971 min,
972 max,
973 './tests/worker-files/thread/testWorker.js',
974 { workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN }
975 )
976 // TODO: Create a better test to cover `WeightedRoundRobinWorkerChoiceStrategy#choose`
ee9f5295 977 const promises = new Set()
138d29a8 978 const maxMultiplier = 2
5502c07c 979 for (let i = 0; i < max * maxMultiplier; i++) {
ee9f5295 980 promises.add(pool.execute())
b3432a63 981 }
e211bc18 982 await Promise.all(promises)
138d29a8 983 for (const workerNode of pool.workerNodes) {
a4e07f72
JB
984 expect(workerNode.workerUsage).toStrictEqual({
985 tasks: {
986 executed: expect.any(Number),
987 executing: 0,
988 queued: 0,
989 failed: 0
990 },
991 runTime: {
932fc8be 992 aggregate: expect.any(Number),
a4e07f72
JB
993 average: expect.any(Number),
994 median: 0,
995 history: expect.any(CircularArray)
996 },
997 waitTime: {
932fc8be 998 aggregate: 0,
a4e07f72
JB
999 average: 0,
1000 median: 0,
1001 history: expect.any(CircularArray)
1002 },
d44d5953 1003 elu: undefined
86bf340d 1004 })
a4e07f72
JB
1005 expect(workerNode.workerUsage.tasks.executed).toBeGreaterThan(0)
1006 expect(workerNode.workerUsage.tasks.executed).toBeLessThanOrEqual(
1007 max * maxMultiplier
1008 )
932fc8be 1009 expect(workerNode.workerUsage.runTime.aggregate).toBeGreaterThan(0)
a4e07f72 1010 expect(workerNode.workerUsage.runTime.average).toBeGreaterThan(0)
138d29a8 1011 }
2b4fddb8
JB
1012 expect(
1013 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1014 pool.workerChoiceStrategyContext.workerChoiceStrategy
1015 ).defaultWorkerWeight
1016 ).toBeGreaterThan(0)
1017 expect(
1018 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1019 pool.workerChoiceStrategyContext.workerChoiceStrategy
1020 ).workerVirtualTaskRunTime
1021 ).toBeGreaterThanOrEqual(0)
b3432a63
JB
1022 // We need to clean up the resources after our test
1023 await pool.destroy()
1024 })
1025
9e775f96 1026 it('Verify WEIGHTED_ROUND_ROBIN strategy can be run in a dynamic pool with median runtime statistic', async () => {
010d7020
JB
1027 const pool = new DynamicThreadPool(
1028 min,
1029 max,
1030 './tests/worker-files/thread/testWorker.js',
1031 {
1032 workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN,
1033 workerChoiceStrategyOptions: {
932fc8be 1034 runTime: { median: true }
010d7020
JB
1035 }
1036 }
1037 )
1038 // TODO: Create a better test to cover `WeightedRoundRobinWorkerChoiceStrategy#choose`
ee9f5295 1039 const promises = new Set()
010d7020
JB
1040 const maxMultiplier = 2
1041 for (let i = 0; i < max * maxMultiplier; i++) {
ee9f5295 1042 promises.add(pool.execute())
010d7020 1043 }
e211bc18 1044 await Promise.all(promises)
010d7020 1045 for (const workerNode of pool.workerNodes) {
a4e07f72
JB
1046 expect(workerNode.workerUsage).toStrictEqual({
1047 tasks: {
1048 executed: expect.any(Number),
1049 executing: 0,
1050 queued: 0,
1051 failed: 0
1052 },
1053 runTime: {
932fc8be 1054 aggregate: expect.any(Number),
a4e07f72
JB
1055 average: 0,
1056 median: expect.any(Number),
1057 history: expect.any(CircularArray)
1058 },
1059 waitTime: {
932fc8be 1060 aggregate: 0,
a4e07f72
JB
1061 average: 0,
1062 median: 0,
1063 history: expect.any(CircularArray)
1064 },
d44d5953 1065 elu: undefined
86bf340d 1066 })
a4e07f72
JB
1067 expect(workerNode.workerUsage.tasks.executed).toBeGreaterThan(0)
1068 expect(workerNode.workerUsage.tasks.executed).toBeLessThanOrEqual(
1069 max * maxMultiplier
1070 )
932fc8be 1071 expect(workerNode.workerUsage.runTime.aggregate).toBeGreaterThan(0)
a4e07f72 1072 expect(workerNode.workerUsage.runTime.median).toBeGreaterThan(0)
010d7020 1073 }
08f3f44c
JB
1074 expect(
1075 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1076 pool.workerChoiceStrategyContext.workerChoiceStrategy
1077 ).defaultWorkerWeight
1078 ).toBeGreaterThan(0)
1079 expect(
1080 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1081 pool.workerChoiceStrategyContext.workerChoiceStrategy
1082 ).workerVirtualTaskRunTime
1083 ).toBeGreaterThanOrEqual(0)
010d7020
JB
1084 // We need to clean up the resources after our test
1085 await pool.destroy()
1086 })
1087
a6f7f1b4 1088 it('Verify WEIGHTED_ROUND_ROBIN strategy internals are resets after setting it', async () => {
594bfb84 1089 const workerChoiceStrategy = WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
f0829c53 1090 let pool = new FixedThreadPool(
caeb9817
JB
1091 max,
1092 './tests/worker-files/thread/testWorker.js'
1093 )
38f6e859 1094 expect(
95c83464 1095 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 1096 workerChoiceStrategy
f06e48d8 1097 ).currentWorkerNodeId
b529c323 1098 ).toBeDefined()
38f6e859 1099 expect(
95c83464 1100 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 1101 workerChoiceStrategy
b529c323
JB
1102 ).defaultWorkerWeight
1103 ).toBeDefined()
caeb9817 1104 expect(
95c83464 1105 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 1106 workerChoiceStrategy
08f3f44c 1107 ).workerVirtualTaskRunTime
b529c323 1108 ).toBeDefined()
594bfb84 1109 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
a6f7f1b4 1110 expect(
95c83464 1111 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
d710242d 1112 pool.workerChoiceStrategyContext.workerChoiceStrategy
f06e48d8 1113 ).currentWorkerNodeId
a6f7f1b4
JB
1114 ).toBe(0)
1115 expect(
95c83464 1116 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
d710242d 1117 pool.workerChoiceStrategyContext.workerChoiceStrategy
95c83464 1118 ).defaultWorkerWeight
a6f7f1b4 1119 ).toBeGreaterThan(0)
08f3f44c
JB
1120 expect(
1121 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1122 workerChoiceStrategy
1123 ).workerVirtualTaskRunTime
1124 ).toBe(0)
f0829c53
JB
1125 await pool.destroy()
1126 pool = new DynamicThreadPool(
1127 min,
1128 max,
1129 './tests/worker-files/thread/testWorker.js'
1130 )
38f6e859 1131 expect(
95c83464 1132 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 1133 workerChoiceStrategy
f06e48d8 1134 ).currentWorkerNodeId
b529c323 1135 ).toBeDefined()
38f6e859 1136 expect(
95c83464 1137 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 1138 workerChoiceStrategy
b529c323
JB
1139 ).defaultWorkerWeight
1140 ).toBeDefined()
f0829c53 1141 expect(
95c83464 1142 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 1143 workerChoiceStrategy
08f3f44c 1144 ).workerVirtualTaskRunTime
b529c323 1145 ).toBeDefined()
594bfb84 1146 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
a6f7f1b4 1147 expect(
95c83464 1148 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
d710242d 1149 pool.workerChoiceStrategyContext.workerChoiceStrategy
f06e48d8 1150 ).currentWorkerNodeId
a6f7f1b4
JB
1151 ).toBe(0)
1152 expect(
95c83464 1153 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
d710242d 1154 pool.workerChoiceStrategyContext.workerChoiceStrategy
95c83464 1155 ).defaultWorkerWeight
a6f7f1b4 1156 ).toBeGreaterThan(0)
08f3f44c
JB
1157 expect(
1158 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1159 workerChoiceStrategy
1160 ).workerVirtualTaskRunTime
1161 ).toBe(0)
caeb9817
JB
1162 // We need to clean up the resources after our test
1163 await pool.destroy()
1164 })
1165
e52fb978
JB
1166 it('Verify INTERLEAVED_WEIGHTED_ROUND_ROBIN strategy default tasks usage statistics requirements', async () => {
1167 const workerChoiceStrategy =
1168 WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
1169 let pool = new FixedThreadPool(
1170 max,
1171 './tests/worker-files/thread/testWorker.js',
1172 { workerChoiceStrategy }
1173 )
87de9ff5
JB
1174 expect(
1175 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
1176 ).toStrictEqual({
932fc8be
JB
1177 runTime: {
1178 aggregate: false,
1179 average: false,
1180 median: false
1181 },
1182 waitTime: {
1183 aggregate: false,
1184 average: false,
1185 median: false
1186 },
d44d5953 1187 elu: false
e52fb978
JB
1188 })
1189 await pool.destroy()
1190 pool = new DynamicThreadPool(
1191 min,
1192 max,
1193 './tests/worker-files/thread/testWorker.js',
1194 { workerChoiceStrategy }
1195 )
87de9ff5
JB
1196 expect(
1197 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
1198 ).toStrictEqual({
932fc8be
JB
1199 runTime: {
1200 aggregate: false,
1201 average: false,
1202 median: false
1203 },
1204 waitTime: {
1205 aggregate: false,
1206 average: false,
1207 median: false
1208 },
d44d5953 1209 elu: false
e52fb978
JB
1210 })
1211 // We need to clean up the resources after our test
1212 await pool.destroy()
1213 })
1214
e62e7646
JB
1215 it('Verify INTERLEAVED_WEIGHTED_ROUND_ROBIN strategy can be run in a fixed pool', async () => {
1216 const pool = new FixedThreadPool(
1217 max,
1218 './tests/worker-files/thread/testWorker.js',
1219 {
1220 workerChoiceStrategy:
1221 WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
1222 }
1223 )
1224 // TODO: Create a better test to cover `InterleavedWeightedRoundRobinWorkerChoiceStrategy#choose`
1225 const promises = new Set()
1226 const maxMultiplier = 2
1227 for (let i = 0; i < max * maxMultiplier; i++) {
1228 promises.add(pool.execute())
1229 }
1230 await Promise.all(promises)
1231 for (const workerNode of pool.workerNodes) {
a4e07f72
JB
1232 expect(workerNode.workerUsage).toStrictEqual({
1233 tasks: {
1234 executed: maxMultiplier,
1235 executing: 0,
1236 queued: 0,
1237 failed: 0
1238 },
1239 runTime: {
932fc8be 1240 aggregate: 0,
a4e07f72
JB
1241 average: 0,
1242 median: 0,
1243 history: expect.any(CircularArray)
1244 },
1245 waitTime: {
932fc8be 1246 aggregate: 0,
a4e07f72
JB
1247 average: 0,
1248 median: 0,
1249 history: expect.any(CircularArray)
1250 },
d44d5953 1251 elu: undefined
e62e7646
JB
1252 })
1253 }
1254 expect(
1255 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1256 pool.workerChoiceStrategyContext.workerChoiceStrategy
1257 ).defaultWorkerWeight
1258 ).toBeGreaterThan(0)
1259 expect(
1260 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1261 pool.workerChoiceStrategyContext.workerChoiceStrategy
1262 ).currentRoundId
1263 ).toBe(0)
1264 expect(
1265 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1266 pool.workerChoiceStrategyContext.workerChoiceStrategy
1267 ).currentWorkerNodeId
1268 ).toBe(0)
1269 expect(
1270 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1271 pool.workerChoiceStrategyContext.workerChoiceStrategy
1272 ).roundWeights
1273 ).toStrictEqual([
1274 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1275 pool.workerChoiceStrategyContext.workerChoiceStrategy
1276 ).defaultWorkerWeight
1277 ])
1278 // We need to clean up the resources after our test
1279 await pool.destroy()
1280 })
1281
1282 it('Verify INTERLEAVED_WEIGHTED_ROUND_ROBIN strategy can be run in a dynamic pool', async () => {
1283 const pool = new DynamicThreadPool(
1284 min,
1285 max,
1286 './tests/worker-files/thread/testWorker.js',
1287 {
1288 workerChoiceStrategy:
1289 WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
1290 }
1291 )
1292 // TODO: Create a better test to cover `InterleavedWeightedRoundRobinWorkerChoiceStrategy#choose`
1293 const promises = new Set()
1294 const maxMultiplier = 2
1295 for (let i = 0; i < max * maxMultiplier; i++) {
1296 promises.add(pool.execute())
1297 }
1298 await Promise.all(promises)
1299 for (const workerNode of pool.workerNodes) {
a4e07f72
JB
1300 expect(workerNode.workerUsage).toStrictEqual({
1301 tasks: {
1302 executed: maxMultiplier,
1303 executing: 0,
1304 queued: 0,
1305 failed: 0
1306 },
1307 runTime: {
932fc8be 1308 aggregate: 0,
a4e07f72
JB
1309 average: 0,
1310 median: 0,
1311 history: expect.any(CircularArray)
1312 },
1313 waitTime: {
932fc8be 1314 aggregate: 0,
a4e07f72
JB
1315 average: 0,
1316 median: 0,
1317 history: expect.any(CircularArray)
1318 },
d44d5953 1319 elu: undefined
e62e7646
JB
1320 })
1321 }
1322 expect(
1323 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1324 pool.workerChoiceStrategyContext.workerChoiceStrategy
1325 ).defaultWorkerWeight
1326 ).toBeGreaterThan(0)
1327 expect(
1328 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1329 pool.workerChoiceStrategyContext.workerChoiceStrategy
1330 ).currentRoundId
1331 ).toBe(0)
1332 expect(
1333 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1334 pool.workerChoiceStrategyContext.workerChoiceStrategy
1335 ).currentWorkerNodeId
1336 ).toBe(0)
1337 expect(
1338 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1339 pool.workerChoiceStrategyContext.workerChoiceStrategy
1340 ).roundWeights
1341 ).toStrictEqual([
1342 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1343 pool.workerChoiceStrategyContext.workerChoiceStrategy
1344 ).defaultWorkerWeight
1345 ])
1346 // We need to clean up the resources after our test
1347 await pool.destroy()
1348 })
1349
8c3ec188
JB
1350 it('Verify INTERLEAVED_WEIGHTED_ROUND_ROBIN strategy internals are resets after setting it', async () => {
1351 const workerChoiceStrategy =
1352 WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
1353 let pool = new FixedThreadPool(
1354 max,
1355 './tests/worker-files/thread/testWorker.js'
1356 )
1357 expect(
1358 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1359 workerChoiceStrategy
1360 ).currentRoundId
1361 ).toBeDefined()
1362 expect(
1363 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1364 workerChoiceStrategy
1365 ).currentWorkerNodeId
1366 ).toBeDefined()
1367 expect(
1368 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1369 workerChoiceStrategy
1370 ).defaultWorkerWeight
1371 ).toBeDefined()
1372 expect(
1373 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1374 workerChoiceStrategy
1375 ).roundWeights
1376 ).toBeDefined()
1377 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
1378 expect(
1379 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1380 workerChoiceStrategy
1381 ).currentRoundId
1382 ).toBe(0)
1383 expect(
1384 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1385 pool.workerChoiceStrategyContext.workerChoiceStrategy
1386 ).currentWorkerNodeId
1387 ).toBe(0)
1388 expect(
1389 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1390 pool.workerChoiceStrategyContext.workerChoiceStrategy
1391 ).defaultWorkerWeight
1392 ).toBeGreaterThan(0)
1393 expect(
1394 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1395 workerChoiceStrategy
1396 ).roundWeights
1397 ).toStrictEqual([
1398 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1399 pool.workerChoiceStrategyContext.workerChoiceStrategy
1400 ).defaultWorkerWeight
1401 ])
1402 await pool.destroy()
1403 pool = new DynamicThreadPool(
1404 min,
1405 max,
1406 './tests/worker-files/thread/testWorker.js'
1407 )
1408 expect(
1409 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1410 workerChoiceStrategy
1411 ).currentRoundId
1412 ).toBeDefined()
1413 expect(
1414 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1415 workerChoiceStrategy
1416 ).currentWorkerNodeId
1417 ).toBeDefined()
1418 expect(
1419 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1420 workerChoiceStrategy
1421 ).defaultWorkerWeight
1422 ).toBeDefined()
1423 expect(
1424 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1425 workerChoiceStrategy
1426 ).roundWeights
1427 ).toBeDefined()
1428 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
1429 expect(
1430 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1431 pool.workerChoiceStrategyContext.workerChoiceStrategy
1432 ).currentWorkerNodeId
1433 ).toBe(0)
1434 expect(
1435 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1436 pool.workerChoiceStrategyContext.workerChoiceStrategy
1437 ).defaultWorkerWeight
1438 ).toBeGreaterThan(0)
1439 expect(
1440 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1441 workerChoiceStrategy
1442 ).roundWeights
1443 ).toStrictEqual([
1444 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1445 pool.workerChoiceStrategyContext.workerChoiceStrategy
1446 ).defaultWorkerWeight
1447 ])
1448 // We need to clean up the resources after our test
1449 await pool.destroy()
1450 })
1451
89b09b26 1452 it('Verify unknown strategy throw error', () => {
a35560ba
S
1453 expect(
1454 () =>
1455 new DynamicThreadPool(
1456 min,
1457 max,
1458 './tests/worker-files/thread/testWorker.js',
1927ee67 1459 { workerChoiceStrategy: 'UNKNOWN_STRATEGY' }
a35560ba 1460 )
d4aeae5a 1461 ).toThrowError("Invalid worker choice strategy 'UNKNOWN_STRATEGY'")
a35560ba
S
1462 })
1463})