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