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