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