Merge branch 'master' 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 )
05302647
JB
577 expect(
578 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
579 ).toStrictEqual({
a7bbf44a
JB
580 runTime: false,
581 avgRunTime: false,
582 medRunTime: false,
583 waitTime: false,
584 avgWaitTime: false,
585 medWaitTime: false,
586 elu: true
587 })
588 await pool.destroy()
589 pool = new DynamicThreadPool(
590 min,
591 max,
592 './tests/worker-files/thread/testWorker.js',
593 { workerChoiceStrategy }
594 )
05302647
JB
595 expect(
596 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
597 ).toStrictEqual({
a7bbf44a
JB
598 runTime: false,
599 avgRunTime: false,
600 medRunTime: false,
601 waitTime: false,
602 avgWaitTime: false,
603 medWaitTime: false,
604 elu: true
605 })
606 // We need to clean up the resources after our test
607 await pool.destroy()
608 })
609
10fcfaf4 610 it('Verify FAIR_SHARE strategy default tasks usage statistics requirements', async () => {
594bfb84 611 const workerChoiceStrategy = WorkerChoiceStrategies.FAIR_SHARE
10fcfaf4
JB
612 let pool = new FixedThreadPool(
613 max,
d710242d 614 './tests/worker-files/thread/testWorker.js',
594bfb84 615 { workerChoiceStrategy }
10fcfaf4 616 )
87de9ff5
JB
617 expect(
618 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
619 ).toStrictEqual({
86bf340d
JB
620 runTime: true,
621 avgRunTime: true,
622 medRunTime: false,
623 waitTime: false,
624 avgWaitTime: false,
d44d5953
JB
625 medWaitTime: false,
626 elu: false
86bf340d 627 })
fd7ebd49 628 await pool.destroy()
10fcfaf4
JB
629 pool = new DynamicThreadPool(
630 min,
631 max,
d710242d 632 './tests/worker-files/thread/testWorker.js',
594bfb84 633 { workerChoiceStrategy }
10fcfaf4 634 )
87de9ff5
JB
635 expect(
636 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
637 ).toStrictEqual({
86bf340d
JB
638 runTime: true,
639 avgRunTime: true,
640 medRunTime: false,
641 waitTime: false,
642 avgWaitTime: false,
d44d5953
JB
643 medWaitTime: false,
644 elu: false
86bf340d 645 })
10fcfaf4
JB
646 // We need to clean up the resources after our test
647 await pool.destroy()
648 })
649
23ff945a 650 it('Verify FAIR_SHARE strategy can be run in a fixed pool', async () => {
23ff945a
JB
651 const pool = new FixedThreadPool(
652 max,
653 './tests/worker-files/thread/testWorker.js',
654 { workerChoiceStrategy: WorkerChoiceStrategies.FAIR_SHARE }
655 )
656 // TODO: Create a better test to cover `FairShareChoiceStrategy#choose`
ee9f5295 657 const promises = new Set()
a20f0ba5
JB
658 const maxMultiplier = 2
659 for (let i = 0; i < max * maxMultiplier; i++) {
ee9f5295 660 promises.add(pool.execute())
23ff945a 661 }
e211bc18 662 await Promise.all(promises)
138d29a8 663 for (const workerNode of pool.workerNodes) {
a4e07f72
JB
664 expect(workerNode.workerUsage).toStrictEqual({
665 tasks: {
666 executed: maxMultiplier,
667 executing: 0,
668 queued: 0,
669 failed: 0
670 },
671 runTime: {
672 aggregation: expect.any(Number),
673 average: expect.any(Number),
674 median: 0,
675 history: expect.any(CircularArray)
676 },
677 waitTime: {
678 aggregation: 0,
679 average: 0,
680 median: 0,
681 history: expect.any(CircularArray)
682 },
d44d5953 683 elu: undefined
86bf340d 684 })
a4e07f72
JB
685 expect(workerNode.workerUsage.runTime.aggregation).toBeGreaterThan(0)
686 expect(workerNode.workerUsage.runTime.average).toBeGreaterThan(0)
138d29a8 687 }
97a2abc3 688 expect(
95c83464 689 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
d710242d 690 pool.workerChoiceStrategyContext.workerChoiceStrategy
b0d6ed8f 691 ).workersVirtualTaskEndTimestamp.length
f06e48d8 692 ).toBe(pool.workerNodes.length)
23ff945a
JB
693 // We need to clean up the resources after our test
694 await pool.destroy()
695 })
696
697 it('Verify FAIR_SHARE strategy can be run in a dynamic pool', async () => {
23ff945a
JB
698 const pool = new DynamicThreadPool(
699 min,
700 max,
701 './tests/worker-files/thread/testWorker.js',
702 { workerChoiceStrategy: WorkerChoiceStrategies.FAIR_SHARE }
703 )
704 // TODO: Create a better test to cover `FairShareChoiceStrategy#choose`
ee9f5295 705 const promises = new Set()
f7070eee 706 const maxMultiplier = 2
804a889e 707 for (let i = 0; i < max * maxMultiplier; i++) {
ee9f5295 708 promises.add(pool.execute())
23ff945a 709 }
e211bc18 710 await Promise.all(promises)
138d29a8 711 for (const workerNode of pool.workerNodes) {
a4e07f72
JB
712 expect(workerNode.workerUsage).toStrictEqual({
713 tasks: {
714 executed: maxMultiplier,
715 executing: 0,
716 queued: 0,
717 failed: 0
718 },
719 runTime: {
720 aggregation: expect.any(Number),
721 average: expect.any(Number),
722 median: 0,
723 history: expect.any(CircularArray)
724 },
725 waitTime: {
726 aggregation: 0,
727 average: 0,
728 median: 0,
729 history: expect.any(CircularArray)
730 },
d44d5953 731 elu: undefined
86bf340d 732 })
a4e07f72
JB
733 expect(workerNode.workerUsage.runTime.aggregation).toBeGreaterThan(0)
734 expect(workerNode.workerUsage.runTime.average).toBeGreaterThan(0)
138d29a8 735 }
2b4fddb8
JB
736 expect(
737 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
738 pool.workerChoiceStrategyContext.workerChoiceStrategy
b0d6ed8f 739 ).workersVirtualTaskEndTimestamp.length
2b4fddb8 740 ).toBe(pool.workerNodes.length)
23ff945a
JB
741 // We need to clean up the resources after our test
742 await pool.destroy()
743 })
744
9e775f96 745 it('Verify FAIR_SHARE strategy can be run in a dynamic pool with median runtime statistic', async () => {
010d7020
JB
746 const pool = new DynamicThreadPool(
747 min,
748 max,
749 './tests/worker-files/thread/testWorker.js',
750 {
751 workerChoiceStrategy: WorkerChoiceStrategies.FAIR_SHARE,
752 workerChoiceStrategyOptions: {
753 medRunTime: true
754 }
755 }
756 )
757 // TODO: Create a better test to cover `FairShareChoiceStrategy#choose`
ee9f5295 758 const promises = new Set()
010d7020
JB
759 const maxMultiplier = 2
760 for (let i = 0; i < max * maxMultiplier; i++) {
ee9f5295 761 promises.add(pool.execute())
010d7020 762 }
e211bc18 763 await Promise.all(promises)
010d7020 764 for (const workerNode of pool.workerNodes) {
a4e07f72
JB
765 expect(workerNode.workerUsage).toStrictEqual({
766 tasks: {
767 executed: maxMultiplier,
768 executing: 0,
769 queued: 0,
770 failed: 0
771 },
772 runTime: {
773 aggregation: expect.any(Number),
774 average: 0,
775 median: expect.any(Number),
776 history: expect.any(CircularArray)
777 },
778 waitTime: {
779 aggregation: 0,
780 average: 0,
781 median: 0,
782 history: expect.any(CircularArray)
783 },
d44d5953 784 elu: undefined
86bf340d 785 })
a4e07f72
JB
786 expect(workerNode.workerUsage.runTime.aggregation).toBeGreaterThan(0)
787 expect(workerNode.workerUsage.runTime.median).toBeGreaterThan(0)
010d7020 788 }
2b4fddb8
JB
789 expect(
790 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
791 pool.workerChoiceStrategyContext.workerChoiceStrategy
b0d6ed8f 792 ).workersVirtualTaskEndTimestamp.length
2b4fddb8 793 ).toBe(pool.workerNodes.length)
010d7020
JB
794 // We need to clean up the resources after our test
795 await pool.destroy()
796 })
797
a6f7f1b4 798 it('Verify FAIR_SHARE strategy internals are resets after setting it', async () => {
594bfb84 799 const workerChoiceStrategy = WorkerChoiceStrategies.FAIR_SHARE
f0829c53 800 let pool = new FixedThreadPool(
caeb9817
JB
801 max,
802 './tests/worker-files/thread/testWorker.js'
803 )
804 expect(
95c83464 805 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 806 workerChoiceStrategy
b0d6ed8f 807 ).workersVirtualTaskEndTimestamp
08f3f44c
JB
808 ).toBeInstanceOf(Array)
809 expect(
810 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
811 workerChoiceStrategy
b0d6ed8f 812 ).workersVirtualTaskEndTimestamp.length
08f3f44c 813 ).toBe(0)
2b4fddb8
JB
814 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
815 workerChoiceStrategy
b0d6ed8f 816 ).workersVirtualTaskEndTimestamp[0] = performance.now()
2b4fddb8
JB
817 expect(
818 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
819 workerChoiceStrategy
b0d6ed8f 820 ).workersVirtualTaskEndTimestamp.length
2b4fddb8 821 ).toBe(1)
594bfb84 822 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
08f3f44c
JB
823 expect(
824 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
825 workerChoiceStrategy
b0d6ed8f 826 ).workersVirtualTaskEndTimestamp
08f3f44c 827 ).toBeInstanceOf(Array)
08f3f44c
JB
828 expect(
829 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
830 workerChoiceStrategy
b0d6ed8f 831 ).workersVirtualTaskEndTimestamp.length
2b4fddb8 832 ).toBe(0)
f0829c53
JB
833 await pool.destroy()
834 pool = new DynamicThreadPool(
835 min,
836 max,
837 './tests/worker-files/thread/testWorker.js'
838 )
839 expect(
95c83464 840 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 841 workerChoiceStrategy
b0d6ed8f 842 ).workersVirtualTaskEndTimestamp
08f3f44c 843 ).toBeInstanceOf(Array)
2b4fddb8
JB
844 expect(
845 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
846 workerChoiceStrategy
b0d6ed8f 847 ).workersVirtualTaskEndTimestamp.length
2b4fddb8 848 ).toBe(0)
08f3f44c
JB
849 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
850 workerChoiceStrategy
b0d6ed8f 851 ).workersVirtualTaskEndTimestamp[0] = performance.now()
08f3f44c
JB
852 expect(
853 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
854 workerChoiceStrategy
b0d6ed8f 855 ).workersVirtualTaskEndTimestamp.length
08f3f44c 856 ).toBe(1)
594bfb84 857 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
08f3f44c
JB
858 expect(
859 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
860 workerChoiceStrategy
b0d6ed8f 861 ).workersVirtualTaskEndTimestamp
08f3f44c
JB
862 ).toBeInstanceOf(Array)
863 expect(
864 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
865 workerChoiceStrategy
b0d6ed8f 866 ).workersVirtualTaskEndTimestamp.length
08f3f44c 867 ).toBe(0)
caeb9817
JB
868 // We need to clean up the resources after our test
869 await pool.destroy()
870 })
871
10fcfaf4 872 it('Verify WEIGHTED_ROUND_ROBIN strategy default tasks usage statistics requirements', async () => {
594bfb84 873 const workerChoiceStrategy = WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
10fcfaf4
JB
874 let pool = new FixedThreadPool(
875 max,
d710242d 876 './tests/worker-files/thread/testWorker.js',
594bfb84 877 { workerChoiceStrategy }
10fcfaf4 878 )
87de9ff5
JB
879 expect(
880 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
881 ).toStrictEqual({
86bf340d
JB
882 runTime: true,
883 avgRunTime: true,
884 medRunTime: false,
885 waitTime: false,
886 avgWaitTime: false,
d44d5953
JB
887 medWaitTime: false,
888 elu: false
86bf340d 889 })
fd7ebd49 890 await pool.destroy()
10fcfaf4
JB
891 pool = new DynamicThreadPool(
892 min,
893 max,
d710242d 894 './tests/worker-files/thread/testWorker.js',
594bfb84 895 { workerChoiceStrategy }
10fcfaf4 896 )
87de9ff5
JB
897 expect(
898 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
899 ).toStrictEqual({
86bf340d
JB
900 runTime: true,
901 avgRunTime: true,
902 medRunTime: false,
903 waitTime: false,
904 avgWaitTime: false,
d44d5953
JB
905 medWaitTime: false,
906 elu: false
86bf340d 907 })
10fcfaf4
JB
908 // We need to clean up the resources after our test
909 await pool.destroy()
910 })
911
b3432a63 912 it('Verify WEIGHTED_ROUND_ROBIN strategy can be run in a fixed pool', async () => {
b3432a63
JB
913 const pool = new FixedThreadPool(
914 max,
915 './tests/worker-files/thread/testWorker.js',
916 { workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN }
917 )
918 // TODO: Create a better test to cover `WeightedRoundRobinWorkerChoiceStrategy#choose`
ee9f5295 919 const promises = new Set()
a20f0ba5
JB
920 const maxMultiplier = 2
921 for (let i = 0; i < max * maxMultiplier; i++) {
ee9f5295 922 promises.add(pool.execute())
b3432a63 923 }
e211bc18 924 await Promise.all(promises)
138d29a8 925 for (const workerNode of pool.workerNodes) {
a4e07f72
JB
926 expect(workerNode.workerUsage).toStrictEqual({
927 tasks: {
928 executed: expect.any(Number),
929 executing: 0,
930 queued: 0,
931 failed: 0
932 },
933 runTime: {
934 aggregation: expect.any(Number),
935 average: expect.any(Number),
936 median: 0,
937 history: expect.any(CircularArray)
938 },
939 waitTime: {
940 aggregation: 0,
941 average: 0,
942 median: 0,
943 history: expect.any(CircularArray)
944 },
d44d5953 945 elu: undefined
86bf340d 946 })
a4e07f72
JB
947 expect(workerNode.workerUsage.tasks.executed).toBeGreaterThanOrEqual(0)
948 expect(workerNode.workerUsage.tasks.executed).toBeLessThanOrEqual(
949 max * maxMultiplier
950 )
951 expect(workerNode.workerUsage.runTime.aggregation).toBeGreaterThanOrEqual(
952 0
953 )
954 expect(workerNode.workerUsage.runTime.average).toBeGreaterThanOrEqual(0)
138d29a8 955 }
97a2abc3 956 expect(
95c83464 957 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
d710242d 958 pool.workerChoiceStrategyContext.workerChoiceStrategy
08f3f44c
JB
959 ).defaultWorkerWeight
960 ).toBeGreaterThan(0)
961 expect(
962 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
963 pool.workerChoiceStrategyContext.workerChoiceStrategy
964 ).workerVirtualTaskRunTime
965 ).toBeGreaterThanOrEqual(0)
b3432a63
JB
966 // We need to clean up the resources after our test
967 await pool.destroy()
968 })
969
970 it('Verify WEIGHTED_ROUND_ROBIN strategy can be run in a dynamic pool', async () => {
b3432a63
JB
971 const pool = new DynamicThreadPool(
972 min,
973 max,
974 './tests/worker-files/thread/testWorker.js',
975 { workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN }
976 )
977 // TODO: Create a better test to cover `WeightedRoundRobinWorkerChoiceStrategy#choose`
ee9f5295 978 const promises = new Set()
138d29a8 979 const maxMultiplier = 2
5502c07c 980 for (let i = 0; i < max * maxMultiplier; i++) {
ee9f5295 981 promises.add(pool.execute())
b3432a63 982 }
e211bc18 983 await Promise.all(promises)
138d29a8 984 for (const workerNode of pool.workerNodes) {
a4e07f72
JB
985 expect(workerNode.workerUsage).toStrictEqual({
986 tasks: {
987 executed: expect.any(Number),
988 executing: 0,
989 queued: 0,
990 failed: 0
991 },
992 runTime: {
993 aggregation: expect.any(Number),
994 average: expect.any(Number),
995 median: 0,
996 history: expect.any(CircularArray)
997 },
998 waitTime: {
999 aggregation: 0,
1000 average: 0,
1001 median: 0,
1002 history: expect.any(CircularArray)
1003 },
d44d5953 1004 elu: undefined
86bf340d 1005 })
a4e07f72
JB
1006 expect(workerNode.workerUsage.tasks.executed).toBeGreaterThan(0)
1007 expect(workerNode.workerUsage.tasks.executed).toBeLessThanOrEqual(
1008 max * maxMultiplier
1009 )
1010 expect(workerNode.workerUsage.runTime.aggregation).toBeGreaterThan(0)
1011 expect(workerNode.workerUsage.runTime.average).toBeGreaterThan(0)
138d29a8 1012 }
2b4fddb8
JB
1013 expect(
1014 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1015 pool.workerChoiceStrategyContext.workerChoiceStrategy
1016 ).defaultWorkerWeight
1017 ).toBeGreaterThan(0)
1018 expect(
1019 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1020 pool.workerChoiceStrategyContext.workerChoiceStrategy
1021 ).workerVirtualTaskRunTime
1022 ).toBeGreaterThanOrEqual(0)
b3432a63
JB
1023 // We need to clean up the resources after our test
1024 await pool.destroy()
1025 })
1026
9e775f96 1027 it('Verify WEIGHTED_ROUND_ROBIN strategy can be run in a dynamic pool with median runtime statistic', async () => {
010d7020
JB
1028 const pool = new DynamicThreadPool(
1029 min,
1030 max,
1031 './tests/worker-files/thread/testWorker.js',
1032 {
1033 workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN,
1034 workerChoiceStrategyOptions: {
1035 medRunTime: true
1036 }
1037 }
1038 )
1039 // TODO: Create a better test to cover `WeightedRoundRobinWorkerChoiceStrategy#choose`
ee9f5295 1040 const promises = new Set()
010d7020
JB
1041 const maxMultiplier = 2
1042 for (let i = 0; i < max * maxMultiplier; i++) {
ee9f5295 1043 promises.add(pool.execute())
010d7020 1044 }
e211bc18 1045 await Promise.all(promises)
010d7020 1046 for (const workerNode of pool.workerNodes) {
a4e07f72
JB
1047 expect(workerNode.workerUsage).toStrictEqual({
1048 tasks: {
1049 executed: expect.any(Number),
1050 executing: 0,
1051 queued: 0,
1052 failed: 0
1053 },
1054 runTime: {
1055 aggregation: expect.any(Number),
1056 average: 0,
1057 median: expect.any(Number),
1058 history: expect.any(CircularArray)
1059 },
1060 waitTime: {
1061 aggregation: 0,
1062 average: 0,
1063 median: 0,
1064 history: expect.any(CircularArray)
1065 },
d44d5953 1066 elu: undefined
86bf340d 1067 })
a4e07f72
JB
1068 expect(workerNode.workerUsage.tasks.executed).toBeGreaterThan(0)
1069 expect(workerNode.workerUsage.tasks.executed).toBeLessThanOrEqual(
1070 max * maxMultiplier
1071 )
1072 expect(workerNode.workerUsage.runTime.aggregation).toBeGreaterThan(0)
1073 expect(workerNode.workerUsage.runTime.median).toBeGreaterThan(0)
010d7020 1074 }
08f3f44c
JB
1075 expect(
1076 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1077 pool.workerChoiceStrategyContext.workerChoiceStrategy
1078 ).defaultWorkerWeight
1079 ).toBeGreaterThan(0)
1080 expect(
1081 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1082 pool.workerChoiceStrategyContext.workerChoiceStrategy
1083 ).workerVirtualTaskRunTime
1084 ).toBeGreaterThanOrEqual(0)
010d7020
JB
1085 // We need to clean up the resources after our test
1086 await pool.destroy()
1087 })
1088
a6f7f1b4 1089 it('Verify WEIGHTED_ROUND_ROBIN strategy internals are resets after setting it', async () => {
594bfb84 1090 const workerChoiceStrategy = WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
f0829c53 1091 let pool = new FixedThreadPool(
caeb9817
JB
1092 max,
1093 './tests/worker-files/thread/testWorker.js'
1094 )
38f6e859 1095 expect(
95c83464 1096 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 1097 workerChoiceStrategy
f06e48d8 1098 ).currentWorkerNodeId
b529c323 1099 ).toBeDefined()
38f6e859 1100 expect(
95c83464 1101 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 1102 workerChoiceStrategy
b529c323
JB
1103 ).defaultWorkerWeight
1104 ).toBeDefined()
caeb9817 1105 expect(
95c83464 1106 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 1107 workerChoiceStrategy
08f3f44c 1108 ).workerVirtualTaskRunTime
b529c323 1109 ).toBeDefined()
594bfb84 1110 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
a6f7f1b4 1111 expect(
95c83464 1112 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
d710242d 1113 pool.workerChoiceStrategyContext.workerChoiceStrategy
f06e48d8 1114 ).currentWorkerNodeId
a6f7f1b4
JB
1115 ).toBe(0)
1116 expect(
95c83464 1117 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
d710242d 1118 pool.workerChoiceStrategyContext.workerChoiceStrategy
95c83464 1119 ).defaultWorkerWeight
a6f7f1b4 1120 ).toBeGreaterThan(0)
08f3f44c
JB
1121 expect(
1122 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1123 workerChoiceStrategy
1124 ).workerVirtualTaskRunTime
1125 ).toBe(0)
f0829c53
JB
1126 await pool.destroy()
1127 pool = new DynamicThreadPool(
1128 min,
1129 max,
1130 './tests/worker-files/thread/testWorker.js'
1131 )
38f6e859 1132 expect(
95c83464 1133 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 1134 workerChoiceStrategy
f06e48d8 1135 ).currentWorkerNodeId
b529c323 1136 ).toBeDefined()
38f6e859 1137 expect(
95c83464 1138 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 1139 workerChoiceStrategy
b529c323
JB
1140 ).defaultWorkerWeight
1141 ).toBeDefined()
f0829c53 1142 expect(
95c83464 1143 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 1144 workerChoiceStrategy
08f3f44c 1145 ).workerVirtualTaskRunTime
b529c323 1146 ).toBeDefined()
594bfb84 1147 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
a6f7f1b4 1148 expect(
95c83464 1149 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
d710242d 1150 pool.workerChoiceStrategyContext.workerChoiceStrategy
f06e48d8 1151 ).currentWorkerNodeId
a6f7f1b4
JB
1152 ).toBe(0)
1153 expect(
95c83464 1154 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
d710242d 1155 pool.workerChoiceStrategyContext.workerChoiceStrategy
95c83464 1156 ).defaultWorkerWeight
a6f7f1b4 1157 ).toBeGreaterThan(0)
08f3f44c
JB
1158 expect(
1159 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1160 workerChoiceStrategy
1161 ).workerVirtualTaskRunTime
1162 ).toBe(0)
caeb9817
JB
1163 // We need to clean up the resources after our test
1164 await pool.destroy()
1165 })
1166
e52fb978
JB
1167 it('Verify INTERLEAVED_WEIGHTED_ROUND_ROBIN strategy default tasks usage statistics requirements', async () => {
1168 const workerChoiceStrategy =
1169 WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
1170 let pool = new FixedThreadPool(
1171 max,
1172 './tests/worker-files/thread/testWorker.js',
1173 { workerChoiceStrategy }
1174 )
87de9ff5
JB
1175 expect(
1176 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
1177 ).toStrictEqual({
e52fb978
JB
1178 runTime: false,
1179 avgRunTime: false,
1180 medRunTime: false,
1181 waitTime: false,
1182 avgWaitTime: false,
d44d5953
JB
1183 medWaitTime: false,
1184 elu: false
e52fb978
JB
1185 })
1186 await pool.destroy()
1187 pool = new DynamicThreadPool(
1188 min,
1189 max,
1190 './tests/worker-files/thread/testWorker.js',
1191 { workerChoiceStrategy }
1192 )
87de9ff5
JB
1193 expect(
1194 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
1195 ).toStrictEqual({
e52fb978
JB
1196 runTime: false,
1197 avgRunTime: false,
1198 medRunTime: false,
1199 waitTime: false,
1200 avgWaitTime: false,
d44d5953
JB
1201 medWaitTime: false,
1202 elu: false
e52fb978
JB
1203 })
1204 // We need to clean up the resources after our test
1205 await pool.destroy()
1206 })
1207
e62e7646
JB
1208 it('Verify INTERLEAVED_WEIGHTED_ROUND_ROBIN strategy can be run in a fixed pool', async () => {
1209 const pool = new FixedThreadPool(
1210 max,
1211 './tests/worker-files/thread/testWorker.js',
1212 {
1213 workerChoiceStrategy:
1214 WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
1215 }
1216 )
1217 // TODO: Create a better test to cover `InterleavedWeightedRoundRobinWorkerChoiceStrategy#choose`
1218 const promises = new Set()
1219 const maxMultiplier = 2
1220 for (let i = 0; i < max * maxMultiplier; i++) {
1221 promises.add(pool.execute())
1222 }
1223 await Promise.all(promises)
1224 for (const workerNode of pool.workerNodes) {
a4e07f72
JB
1225 expect(workerNode.workerUsage).toStrictEqual({
1226 tasks: {
1227 executed: maxMultiplier,
1228 executing: 0,
1229 queued: 0,
1230 failed: 0
1231 },
1232 runTime: {
1233 aggregation: 0,
1234 average: 0,
1235 median: 0,
1236 history: expect.any(CircularArray)
1237 },
1238 waitTime: {
1239 aggregation: 0,
1240 average: 0,
1241 median: 0,
1242 history: expect.any(CircularArray)
1243 },
d44d5953 1244 elu: undefined
e62e7646
JB
1245 })
1246 }
1247 expect(
1248 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1249 pool.workerChoiceStrategyContext.workerChoiceStrategy
1250 ).defaultWorkerWeight
1251 ).toBeGreaterThan(0)
1252 expect(
1253 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1254 pool.workerChoiceStrategyContext.workerChoiceStrategy
1255 ).currentRoundId
1256 ).toBe(0)
1257 expect(
1258 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1259 pool.workerChoiceStrategyContext.workerChoiceStrategy
1260 ).currentWorkerNodeId
1261 ).toBe(0)
1262 expect(
1263 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1264 pool.workerChoiceStrategyContext.workerChoiceStrategy
1265 ).roundWeights
1266 ).toStrictEqual([
1267 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1268 pool.workerChoiceStrategyContext.workerChoiceStrategy
1269 ).defaultWorkerWeight
1270 ])
1271 // We need to clean up the resources after our test
1272 await pool.destroy()
1273 })
1274
1275 it('Verify INTERLEAVED_WEIGHTED_ROUND_ROBIN strategy can be run in a dynamic pool', async () => {
1276 const pool = new DynamicThreadPool(
1277 min,
1278 max,
1279 './tests/worker-files/thread/testWorker.js',
1280 {
1281 workerChoiceStrategy:
1282 WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
1283 }
1284 )
1285 // TODO: Create a better test to cover `InterleavedWeightedRoundRobinWorkerChoiceStrategy#choose`
1286 const promises = new Set()
1287 const maxMultiplier = 2
1288 for (let i = 0; i < max * maxMultiplier; i++) {
1289 promises.add(pool.execute())
1290 }
1291 await Promise.all(promises)
1292 for (const workerNode of pool.workerNodes) {
a4e07f72
JB
1293 expect(workerNode.workerUsage).toStrictEqual({
1294 tasks: {
1295 executed: maxMultiplier,
1296 executing: 0,
1297 queued: 0,
1298 failed: 0
1299 },
1300 runTime: {
1301 aggregation: 0,
1302 average: 0,
1303 median: 0,
1304 history: expect.any(CircularArray)
1305 },
1306 waitTime: {
1307 aggregation: 0,
1308 average: 0,
1309 median: 0,
1310 history: expect.any(CircularArray)
1311 },
d44d5953 1312 elu: undefined
e62e7646
JB
1313 })
1314 }
1315 expect(
1316 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1317 pool.workerChoiceStrategyContext.workerChoiceStrategy
1318 ).defaultWorkerWeight
1319 ).toBeGreaterThan(0)
1320 expect(
1321 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1322 pool.workerChoiceStrategyContext.workerChoiceStrategy
1323 ).currentRoundId
1324 ).toBe(0)
1325 expect(
1326 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1327 pool.workerChoiceStrategyContext.workerChoiceStrategy
1328 ).currentWorkerNodeId
1329 ).toBe(0)
1330 expect(
1331 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1332 pool.workerChoiceStrategyContext.workerChoiceStrategy
1333 ).roundWeights
1334 ).toStrictEqual([
1335 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1336 pool.workerChoiceStrategyContext.workerChoiceStrategy
1337 ).defaultWorkerWeight
1338 ])
1339 // We need to clean up the resources after our test
1340 await pool.destroy()
1341 })
1342
8c3ec188
JB
1343 it('Verify INTERLEAVED_WEIGHTED_ROUND_ROBIN strategy internals are resets after setting it', async () => {
1344 const workerChoiceStrategy =
1345 WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
1346 let pool = new FixedThreadPool(
1347 max,
1348 './tests/worker-files/thread/testWorker.js'
1349 )
1350 expect(
1351 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1352 workerChoiceStrategy
1353 ).currentRoundId
1354 ).toBeDefined()
1355 expect(
1356 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1357 workerChoiceStrategy
1358 ).currentWorkerNodeId
1359 ).toBeDefined()
1360 expect(
1361 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1362 workerChoiceStrategy
1363 ).defaultWorkerWeight
1364 ).toBeDefined()
1365 expect(
1366 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1367 workerChoiceStrategy
1368 ).roundWeights
1369 ).toBeDefined()
1370 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
1371 expect(
1372 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1373 workerChoiceStrategy
1374 ).currentRoundId
1375 ).toBe(0)
1376 expect(
1377 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1378 pool.workerChoiceStrategyContext.workerChoiceStrategy
1379 ).currentWorkerNodeId
1380 ).toBe(0)
1381 expect(
1382 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1383 pool.workerChoiceStrategyContext.workerChoiceStrategy
1384 ).defaultWorkerWeight
1385 ).toBeGreaterThan(0)
1386 expect(
1387 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1388 workerChoiceStrategy
1389 ).roundWeights
1390 ).toStrictEqual([
1391 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1392 pool.workerChoiceStrategyContext.workerChoiceStrategy
1393 ).defaultWorkerWeight
1394 ])
1395 await pool.destroy()
1396 pool = new DynamicThreadPool(
1397 min,
1398 max,
1399 './tests/worker-files/thread/testWorker.js'
1400 )
1401 expect(
1402 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1403 workerChoiceStrategy
1404 ).currentRoundId
1405 ).toBeDefined()
1406 expect(
1407 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1408 workerChoiceStrategy
1409 ).currentWorkerNodeId
1410 ).toBeDefined()
1411 expect(
1412 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1413 workerChoiceStrategy
1414 ).defaultWorkerWeight
1415 ).toBeDefined()
1416 expect(
1417 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1418 workerChoiceStrategy
1419 ).roundWeights
1420 ).toBeDefined()
1421 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
1422 expect(
1423 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1424 pool.workerChoiceStrategyContext.workerChoiceStrategy
1425 ).currentWorkerNodeId
1426 ).toBe(0)
1427 expect(
1428 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1429 pool.workerChoiceStrategyContext.workerChoiceStrategy
1430 ).defaultWorkerWeight
1431 ).toBeGreaterThan(0)
1432 expect(
1433 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1434 workerChoiceStrategy
1435 ).roundWeights
1436 ).toStrictEqual([
1437 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1438 pool.workerChoiceStrategyContext.workerChoiceStrategy
1439 ).defaultWorkerWeight
1440 ])
1441 // We need to clean up the resources after our test
1442 await pool.destroy()
1443 })
1444
89b09b26 1445 it('Verify unknown strategy throw error', () => {
a35560ba
S
1446 expect(
1447 () =>
1448 new DynamicThreadPool(
1449 min,
1450 max,
1451 './tests/worker-files/thread/testWorker.js',
1927ee67 1452 { workerChoiceStrategy: 'UNKNOWN_STRATEGY' }
a35560ba 1453 )
d4aeae5a 1454 ).toThrowError("Invalid worker choice strategy 'UNKNOWN_STRATEGY'")
a35560ba
S
1455 })
1456})