test: improve WCS coverage
[poolifier.git] / tests / pools / selection-strategies / selection-strategies.test.js
CommitLineData
a61a0724 1const { expect } = require('expect')
a35560ba 2const {
999ef664 3 DynamicClusterPool,
a35560ba 4 DynamicThreadPool,
3d6dd312 5 FixedClusterPool,
2ced693a 6 FixedThreadPool,
3d6dd312 7 WorkerChoiceStrategies
cdace0e5 8} = require('../../../lib')
86bf340d 9const { CircularArray } = require('../../../lib/circular-array')
a35560ba
S
10
11describe('Selection strategies test suite', () => {
e1ffb94f
JB
12 const min = 0
13 const max = 3
14
a35560ba
S
15 it('Verify that WorkerChoiceStrategies enumeration provides string values', () => {
16 expect(WorkerChoiceStrategies.ROUND_ROBIN).toBe('ROUND_ROBIN')
e4543b14
JB
17 expect(WorkerChoiceStrategies.LEAST_USED).toBe('LEAST_USED')
18 expect(WorkerChoiceStrategies.LEAST_BUSY).toBe('LEAST_BUSY')
a7bbf44a 19 expect(WorkerChoiceStrategies.LEAST_ELU).toBe('LEAST_ELU')
23ff945a 20 expect(WorkerChoiceStrategies.FAIR_SHARE).toBe('FAIR_SHARE')
b3432a63
JB
21 expect(WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN).toBe(
22 'WEIGHTED_ROUND_ROBIN'
23 )
feec6e8c
JB
24 expect(WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN).toBe(
25 'INTERLEAVED_WEIGHTED_ROUND_ROBIN'
26 )
a35560ba
S
27 })
28
e843b904 29 it('Verify ROUND_ROBIN strategy is the default at pool creation', async () => {
e843b904
JB
30 const pool = new DynamicThreadPool(
31 min,
32 max,
33 './tests/worker-files/thread/testWorker.js'
34 )
35 expect(pool.opts.workerChoiceStrategy).toBe(
36 WorkerChoiceStrategies.ROUND_ROBIN
37 )
38 // We need to clean up the resources after our test
39 await pool.destroy()
40 })
41
594bfb84
JB
42 it('Verify available strategies are taken at pool creation', async () => {
43 for (const workerChoiceStrategy of Object.values(WorkerChoiceStrategies)) {
44 const pool = new FixedThreadPool(
45 max,
46 './tests/worker-files/thread/testWorker.js',
47 { workerChoiceStrategy }
48 )
49 expect(pool.opts.workerChoiceStrategy).toBe(workerChoiceStrategy)
50 expect(pool.workerChoiceStrategyContext.workerChoiceStrategy).toBe(
51 workerChoiceStrategy
52 )
53 await pool.destroy()
54 }
d2f7b7a2
JB
55 })
56
594bfb84
JB
57 it('Verify available strategies can be set after pool creation', async () => {
58 for (const workerChoiceStrategy of Object.values(WorkerChoiceStrategies)) {
59 const pool = new DynamicThreadPool(
60 min,
61 max,
ec82cfa1 62 './tests/worker-files/thread/testWorker.js'
594bfb84
JB
63 )
64 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
65 expect(pool.opts.workerChoiceStrategy).toBe(workerChoiceStrategy)
66 expect(pool.workerChoiceStrategyContext.workerChoiceStrategy).toBe(
67 workerChoiceStrategy
68 )
999ef664
JB
69 expect(pool.opts.workerChoiceStrategyOptions).toStrictEqual({
70 retries: 6,
71 runTime: { median: false },
72 waitTime: { median: false },
73 elu: { median: false }
74 })
75 expect(pool.workerChoiceStrategyContext.opts).toStrictEqual({
76 retries: 6,
77 runTime: { median: false },
78 waitTime: { median: false },
79 elu: { median: false }
80 })
81 await pool.destroy()
82 }
83 for (const workerChoiceStrategy of Object.values(WorkerChoiceStrategies)) {
84 const pool = new DynamicClusterPool(
85 min,
86 max,
87 './tests/worker-files/cluster/testWorker.js'
88 )
89 pool.setWorkerChoiceStrategy(workerChoiceStrategy, { retries: 3 })
90 expect(pool.opts.workerChoiceStrategy).toBe(workerChoiceStrategy)
91 expect(pool.workerChoiceStrategyContext.workerChoiceStrategy).toBe(
92 workerChoiceStrategy
93 )
94 expect(pool.opts.workerChoiceStrategyOptions).toStrictEqual({
95 retries: 3,
96 runTime: { median: false },
97 waitTime: { median: false },
98 elu: { median: false }
99 })
100 expect(pool.workerChoiceStrategyContext.opts).toStrictEqual({
101 retries: 3,
102 runTime: { median: false },
103 waitTime: { median: false },
104 elu: { median: false }
105 })
594bfb84
JB
106 await pool.destroy()
107 }
108 })
109
110 it('Verify available strategies default internals at pool creation', async () => {
111 const pool = new FixedThreadPool(
e843b904
JB
112 max,
113 './tests/worker-files/thread/testWorker.js'
114 )
594bfb84 115 for (const workerChoiceStrategy of Object.values(WorkerChoiceStrategies)) {
54f4e726
JB
116 expect(
117 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
118 workerChoiceStrategy
119 ).nextWorkerNodeKey
120 ).toBe(0)
121 expect(
122 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
123 workerChoiceStrategy
124 ).previousWorkerNodeKey
125 ).toBe(0)
126 if (workerChoiceStrategy === WorkerChoiceStrategies.FAIR_SHARE) {
08f3f44c
JB
127 expect(
128 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
129 workerChoiceStrategy
b0d6ed8f 130 ).workersVirtualTaskEndTimestamp
08f3f44c
JB
131 ).toBeInstanceOf(Array)
132 expect(
133 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
134 workerChoiceStrategy
b0d6ed8f 135 ).workersVirtualTaskEndTimestamp.length
08f3f44c 136 ).toBe(0)
594bfb84
JB
137 } else if (
138 workerChoiceStrategy === WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
139 ) {
140 expect(
141 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
142 workerChoiceStrategy
54f4e726
JB
143 ).defaultWorkerWeight
144 ).toBeGreaterThan(0)
145 expect(
146 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
147 workerChoiceStrategy
148 ).workerVirtualTaskRunTime
594bfb84 149 ).toBe(0)
54f4e726
JB
150 } else if (
151 workerChoiceStrategy ===
152 WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
153 ) {
594bfb84
JB
154 expect(
155 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
156 workerChoiceStrategy
157 ).defaultWorkerWeight
158 ).toBeGreaterThan(0)
08f3f44c
JB
159 expect(
160 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
161 workerChoiceStrategy
162 ).workerVirtualTaskRunTime
163 ).toBe(0)
54f4e726
JB
164 expect(
165 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
166 workerChoiceStrategy
167 ).roundId
168 ).toBe(0)
169 expect(
170 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
171 workerChoiceStrategy
172 ).workerNodeId
173 ).toBe(0)
174 expect(
175 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
176 workerChoiceStrategy
177 ).roundWeights
178 ).toStrictEqual([
179 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
180 workerChoiceStrategy
181 ).defaultWorkerWeight
182 ])
594bfb84
JB
183 }
184 }
e843b904
JB
185 await pool.destroy()
186 })
187
6c6afb84
JB
188 it('Verify ROUND_ROBIN strategy default policy', async () => {
189 const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN
190 let pool = new FixedThreadPool(
191 max,
192 './tests/worker-files/thread/testWorker.js',
193 { workerChoiceStrategy }
194 )
195 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
94407def 196 dynamicWorkerUsage: false,
b1aae695 197 dynamicWorkerReady: true
6c6afb84
JB
198 })
199 await pool.destroy()
200 pool = new DynamicThreadPool(
201 min,
202 max,
203 './tests/worker-files/thread/testWorker.js',
204 { workerChoiceStrategy }
205 )
206 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
94407def 207 dynamicWorkerUsage: false,
b1aae695 208 dynamicWorkerReady: true
6c6afb84
JB
209 })
210 // We need to clean up the resources after our test
211 await pool.destroy()
212 })
213
214 it('Verify ROUND_ROBIN strategy default tasks statistics requirements', async () => {
594bfb84 215 const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN
10fcfaf4
JB
216 let pool = new FixedThreadPool(
217 max,
d710242d 218 './tests/worker-files/thread/testWorker.js',
594bfb84 219 { workerChoiceStrategy }
10fcfaf4 220 )
87de9ff5
JB
221 expect(
222 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
223 ).toStrictEqual({
932fc8be
JB
224 runTime: {
225 aggregate: false,
226 average: false,
227 median: false
228 },
229 waitTime: {
230 aggregate: false,
231 average: false,
232 median: false
233 },
5df69fab
JB
234 elu: {
235 aggregate: false,
236 average: false,
237 median: false
238 }
86bf340d 239 })
fd7ebd49 240 await pool.destroy()
10fcfaf4
JB
241 pool = new DynamicThreadPool(
242 min,
243 max,
d710242d 244 './tests/worker-files/thread/testWorker.js',
594bfb84 245 { workerChoiceStrategy }
10fcfaf4 246 )
87de9ff5
JB
247 expect(
248 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
249 ).toStrictEqual({
932fc8be
JB
250 runTime: {
251 aggregate: false,
252 average: false,
253 median: false
254 },
255 waitTime: {
256 aggregate: false,
257 average: false,
258 median: false
259 },
5df69fab
JB
260 elu: {
261 aggregate: false,
262 average: false,
263 median: false
264 }
86bf340d 265 })
10fcfaf4
JB
266 // We need to clean up the resources after our test
267 await pool.destroy()
268 })
269
bdaf31cd 270 it('Verify ROUND_ROBIN strategy can be run in a fixed pool', async () => {
bdaf31cd
JB
271 const pool = new FixedThreadPool(
272 max,
273 './tests/worker-files/thread/testWorker.js',
274 { workerChoiceStrategy: WorkerChoiceStrategies.ROUND_ROBIN }
275 )
bdaf31cd 276 // TODO: Create a better test to cover `RoundRobinWorkerChoiceStrategy#choose`
ee9f5295 277 const promises = new Set()
a20f0ba5
JB
278 const maxMultiplier = 2
279 for (let i = 0; i < max * maxMultiplier; i++) {
ee9f5295 280 promises.add(pool.execute())
e211bc18
JB
281 }
282 await Promise.all(promises)
283 for (const workerNode of pool.workerNodes) {
465b2940 284 expect(workerNode.usage).toStrictEqual({
a4e07f72
JB
285 tasks: {
286 executed: maxMultiplier,
287 executing: 0,
288 queued: 0,
df593701 289 maxQueued: 0,
68cbdc84 290 stolen: 0,
a4e07f72
JB
291 failed: 0
292 },
293 runTime: {
4ba4c7f9 294 history: new CircularArray()
a4e07f72
JB
295 },
296 waitTime: {
4ba4c7f9 297 history: new CircularArray()
a4e07f72 298 },
5df69fab
JB
299 elu: {
300 idle: {
4ba4c7f9 301 history: new CircularArray()
5df69fab
JB
302 },
303 active: {
4ba4c7f9 304 history: new CircularArray()
71514351 305 }
5df69fab 306 }
e211bc18 307 })
bdaf31cd 308 }
9458090a
JB
309 expect(
310 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
311 WorkerChoiceStrategies.ROUND_ROBIN
9b106837 312 ).nextWorkerNodeKey
9458090a 313 ).toBe(0)
086fd843
JB
314 expect(
315 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
316 WorkerChoiceStrategies.ROUND_ROBIN
317 ).previousWorkerNodeKey
318 ).toBe(pool.workerNodes.length - 1)
bdaf31cd
JB
319 // We need to clean up the resources after our test
320 await pool.destroy()
321 })
322
323 it('Verify ROUND_ROBIN strategy can be run in a dynamic pool', async () => {
bdaf31cd
JB
324 const pool = new DynamicThreadPool(
325 min,
326 max,
327 './tests/worker-files/thread/testWorker.js',
328 { workerChoiceStrategy: WorkerChoiceStrategies.ROUND_ROBIN }
329 )
bdaf31cd 330 // TODO: Create a better test to cover `RoundRobinWorkerChoiceStrategy#choose`
ee9f5295 331 const promises = new Set()
a20f0ba5
JB
332 const maxMultiplier = 2
333 for (let i = 0; i < max * maxMultiplier; i++) {
ee9f5295 334 promises.add(pool.execute())
e211bc18
JB
335 }
336 await Promise.all(promises)
337 for (const workerNode of pool.workerNodes) {
465b2940 338 expect(workerNode.usage).toStrictEqual({
a4e07f72 339 tasks: {
94407def 340 executed: expect.any(Number),
a4e07f72
JB
341 executing: 0,
342 queued: 0,
df593701 343 maxQueued: 0,
68cbdc84 344 stolen: 0,
a4e07f72
JB
345 failed: 0
346 },
347 runTime: {
4ba4c7f9 348 history: new CircularArray()
a4e07f72
JB
349 },
350 waitTime: {
4ba4c7f9 351 history: new CircularArray()
a4e07f72 352 },
5df69fab
JB
353 elu: {
354 idle: {
4ba4c7f9 355 history: new CircularArray()
5df69fab
JB
356 },
357 active: {
4ba4c7f9 358 history: new CircularArray()
71514351 359 }
5df69fab 360 }
e211bc18 361 })
94407def
JB
362 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
363 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
364 max * maxMultiplier
365 )
bdaf31cd 366 }
9458090a
JB
367 expect(
368 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
369 WorkerChoiceStrategies.ROUND_ROBIN
9b106837 370 ).nextWorkerNodeKey
9458090a 371 ).toBe(0)
086fd843
JB
372 expect(
373 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
374 WorkerChoiceStrategies.ROUND_ROBIN
375 ).previousWorkerNodeKey
376 ).toBe(pool.workerNodes.length - 1)
bdaf31cd
JB
377 // We need to clean up the resources after our test
378 await pool.destroy()
379 })
380
2ced693a 381 it('Verify ROUND_ROBIN strategy runtime behavior', async () => {
594bfb84 382 const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN
2ced693a
JB
383 let pool = new FixedClusterPool(
384 max,
594bfb84
JB
385 './tests/worker-files/cluster/testWorker.js',
386 { workerChoiceStrategy }
2ced693a
JB
387 )
388 let results = new Set()
389 for (let i = 0; i < max; i++) {
20dcad1a 390 results.add(pool.workerNodes[pool.chooseWorkerNode()].worker.id)
2ced693a
JB
391 }
392 expect(results.size).toBe(max)
393 await pool.destroy()
594bfb84
JB
394 pool = new FixedThreadPool(
395 max,
396 './tests/worker-files/thread/testWorker.js',
397 { workerChoiceStrategy }
398 )
2ced693a
JB
399 results = new Set()
400 for (let i = 0; i < max; i++) {
20dcad1a 401 results.add(pool.workerNodes[pool.chooseWorkerNode()].worker.threadId)
2ced693a
JB
402 }
403 expect(results.size).toBe(max)
404 await pool.destroy()
405 })
406
a6f7f1b4 407 it('Verify ROUND_ROBIN strategy internals are resets after setting it', async () => {
594bfb84 408 const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN
a6f7f1b4
JB
409 let pool = new FixedThreadPool(
410 max,
411 './tests/worker-files/thread/testWorker.js',
412 { workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN }
413 )
086fd843 414 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
38f6e859 415 expect(
95c83464 416 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
086fd843 417 pool.workerChoiceStrategyContext.workerChoiceStrategy
9b106837 418 ).nextWorkerNodeKey
086fd843 419 ).toBe(0)
a6f7f1b4 420 expect(
95c83464 421 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
d710242d 422 pool.workerChoiceStrategyContext.workerChoiceStrategy
086fd843 423 ).previousWorkerNodeKey
a6f7f1b4
JB
424 ).toBe(0)
425 await pool.destroy()
426 pool = new DynamicThreadPool(
427 min,
428 max,
429 './tests/worker-files/thread/testWorker.js',
430 { workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN }
431 )
086fd843 432 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
38f6e859 433 expect(
95c83464 434 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
086fd843 435 pool.workerChoiceStrategyContext.workerChoiceStrategy
9b106837 436 ).nextWorkerNodeKey
086fd843 437 ).toBe(0)
a6f7f1b4 438 expect(
95c83464 439 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
d710242d 440 pool.workerChoiceStrategyContext.workerChoiceStrategy
086fd843 441 ).previousWorkerNodeKey
a6f7f1b4
JB
442 ).toBe(0)
443 // We need to clean up the resources after our test
444 await pool.destroy()
445 })
446
6c6afb84
JB
447 it('Verify LEAST_USED strategy default policy', async () => {
448 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_USED
449 let pool = new FixedThreadPool(
450 max,
451 './tests/worker-files/thread/testWorker.js',
452 { workerChoiceStrategy }
453 )
454 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
b1aae695
JB
455 dynamicWorkerUsage: false,
456 dynamicWorkerReady: true
6c6afb84
JB
457 })
458 await pool.destroy()
459 pool = new DynamicThreadPool(
460 min,
461 max,
462 './tests/worker-files/thread/testWorker.js',
463 { workerChoiceStrategy }
464 )
465 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
b1aae695
JB
466 dynamicWorkerUsage: false,
467 dynamicWorkerReady: true
6c6afb84
JB
468 })
469 // We need to clean up the resources after our test
470 await pool.destroy()
471 })
472
473 it('Verify LEAST_USED strategy default tasks statistics requirements', async () => {
e4543b14 474 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_USED
10fcfaf4
JB
475 let pool = new FixedThreadPool(
476 max,
d710242d 477 './tests/worker-files/thread/testWorker.js',
594bfb84 478 { workerChoiceStrategy }
10fcfaf4 479 )
87de9ff5
JB
480 expect(
481 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
482 ).toStrictEqual({
932fc8be
JB
483 runTime: {
484 aggregate: false,
485 average: false,
486 median: false
487 },
488 waitTime: {
489 aggregate: false,
490 average: false,
491 median: false
492 },
5df69fab
JB
493 elu: {
494 aggregate: false,
495 average: false,
496 median: false
497 }
86bf340d 498 })
fd7ebd49 499 await pool.destroy()
10fcfaf4
JB
500 pool = new DynamicThreadPool(
501 min,
502 max,
d710242d 503 './tests/worker-files/thread/testWorker.js',
594bfb84 504 { workerChoiceStrategy }
10fcfaf4 505 )
87de9ff5
JB
506 expect(
507 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
508 ).toStrictEqual({
932fc8be
JB
509 runTime: {
510 aggregate: false,
511 average: false,
512 median: false
513 },
514 waitTime: {
515 aggregate: false,
516 average: false,
517 median: false
518 },
5df69fab
JB
519 elu: {
520 aggregate: false,
521 average: false,
522 median: false
523 }
86bf340d 524 })
10fcfaf4
JB
525 // We need to clean up the resources after our test
526 await pool.destroy()
527 })
528
e4543b14 529 it('Verify LEAST_USED strategy can be run in a fixed pool', async () => {
b98ec2e6
JB
530 const pool = new FixedThreadPool(
531 max,
532 './tests/worker-files/thread/testWorker.js',
e4543b14 533 { workerChoiceStrategy: WorkerChoiceStrategies.LEAST_USED }
b98ec2e6 534 )
e4543b14 535 // TODO: Create a better test to cover `LeastUsedWorkerChoiceStrategy#choose`
ee9f5295 536 const promises = new Set()
a20f0ba5
JB
537 const maxMultiplier = 2
538 for (let i = 0; i < max * maxMultiplier; i++) {
ee9f5295 539 promises.add(pool.execute())
e211bc18
JB
540 }
541 await Promise.all(promises)
542 for (const workerNode of pool.workerNodes) {
465b2940 543 expect(workerNode.usage).toStrictEqual({
a4e07f72 544 tasks: {
76407b8e 545 executed: expect.any(Number),
a4e07f72
JB
546 executing: 0,
547 queued: 0,
df593701 548 maxQueued: 0,
68cbdc84 549 stolen: 0,
a4e07f72
JB
550 failed: 0
551 },
552 runTime: {
4ba4c7f9 553 history: new CircularArray()
a4e07f72
JB
554 },
555 waitTime: {
4ba4c7f9 556 history: new CircularArray()
a4e07f72 557 },
5df69fab
JB
558 elu: {
559 idle: {
4ba4c7f9 560 history: new CircularArray()
5df69fab
JB
561 },
562 active: {
4ba4c7f9 563 history: new CircularArray()
71514351 564 }
5df69fab 565 }
e211bc18 566 })
465b2940
JB
567 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
568 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
76407b8e
JB
569 max * maxMultiplier
570 )
a35560ba 571 }
a35560ba
S
572 // We need to clean up the resources after our test
573 await pool.destroy()
574 })
575
e4543b14 576 it('Verify LEAST_USED strategy can be run in a dynamic pool', async () => {
ff5e76e1
JB
577 const pool = new DynamicThreadPool(
578 min,
579 max,
580 './tests/worker-files/thread/testWorker.js',
e4543b14 581 { workerChoiceStrategy: WorkerChoiceStrategies.LEAST_USED }
ff5e76e1 582 )
e4543b14 583 // TODO: Create a better test to cover `LeastUsedWorkerChoiceStrategy#choose`
ee9f5295 584 const promises = new Set()
a20f0ba5
JB
585 const maxMultiplier = 2
586 for (let i = 0; i < max * maxMultiplier; i++) {
ee9f5295 587 promises.add(pool.execute())
e211bc18
JB
588 }
589 await Promise.all(promises)
590 for (const workerNode of pool.workerNodes) {
465b2940 591 expect(workerNode.usage).toStrictEqual({
a4e07f72 592 tasks: {
76407b8e 593 executed: expect.any(Number),
a4e07f72
JB
594 executing: 0,
595 queued: 0,
df593701 596 maxQueued: 0,
68cbdc84 597 stolen: 0,
a4e07f72
JB
598 failed: 0
599 },
600 runTime: {
4ba4c7f9 601 history: new CircularArray()
a4e07f72
JB
602 },
603 waitTime: {
4ba4c7f9 604 history: new CircularArray()
a4e07f72 605 },
5df69fab
JB
606 elu: {
607 idle: {
4ba4c7f9 608 history: new CircularArray()
5df69fab
JB
609 },
610 active: {
4ba4c7f9 611 history: new CircularArray()
71514351 612 }
5df69fab 613 }
e211bc18 614 })
465b2940
JB
615 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
616 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
76407b8e
JB
617 max * maxMultiplier
618 )
168c526f 619 }
168c526f
JB
620 // We need to clean up the resources after our test
621 await pool.destroy()
622 })
623
6c6afb84
JB
624 it('Verify LEAST_BUSY strategy default policy', async () => {
625 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_BUSY
626 let pool = new FixedThreadPool(
627 max,
628 './tests/worker-files/thread/testWorker.js',
629 { workerChoiceStrategy }
630 )
631 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
b1aae695
JB
632 dynamicWorkerUsage: false,
633 dynamicWorkerReady: true
6c6afb84
JB
634 })
635 await pool.destroy()
636 pool = new DynamicThreadPool(
637 min,
638 max,
639 './tests/worker-files/thread/testWorker.js',
640 { workerChoiceStrategy }
641 )
642 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
b1aae695
JB
643 dynamicWorkerUsage: false,
644 dynamicWorkerReady: true
6c6afb84
JB
645 })
646 // We need to clean up the resources after our test
647 await pool.destroy()
648 })
649
650 it('Verify LEAST_BUSY strategy default tasks statistics requirements', async () => {
e4543b14 651 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_BUSY
168c526f
JB
652 let pool = new FixedThreadPool(
653 max,
d710242d 654 './tests/worker-files/thread/testWorker.js',
594bfb84 655 { workerChoiceStrategy }
168c526f 656 )
87de9ff5
JB
657 expect(
658 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
659 ).toStrictEqual({
932fc8be
JB
660 runTime: {
661 aggregate: true,
662 average: false,
663 median: false
664 },
665 waitTime: {
666 aggregate: true,
667 average: false,
668 median: false
669 },
5df69fab
JB
670 elu: {
671 aggregate: false,
672 average: false,
673 median: false
674 }
86bf340d 675 })
168c526f
JB
676 await pool.destroy()
677 pool = new DynamicThreadPool(
678 min,
679 max,
d710242d 680 './tests/worker-files/thread/testWorker.js',
594bfb84 681 { workerChoiceStrategy }
168c526f 682 )
87de9ff5
JB
683 expect(
684 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
685 ).toStrictEqual({
932fc8be
JB
686 runTime: {
687 aggregate: true,
688 average: false,
689 median: false
690 },
691 waitTime: {
692 aggregate: true,
693 average: false,
694 median: false
695 },
5df69fab
JB
696 elu: {
697 aggregate: false,
698 average: false,
699 median: false
700 }
86bf340d 701 })
168c526f
JB
702 // We need to clean up the resources after our test
703 await pool.destroy()
704 })
705
e4543b14 706 it('Verify LEAST_BUSY strategy can be run in a fixed pool', async () => {
168c526f
JB
707 const pool = new FixedThreadPool(
708 max,
709 './tests/worker-files/thread/testWorker.js',
e4543b14 710 { workerChoiceStrategy: WorkerChoiceStrategies.LEAST_BUSY }
168c526f 711 )
e4543b14 712 // TODO: Create a better test to cover `LeastBusyWorkerChoiceStrategy#choose`
ee9f5295 713 const promises = new Set()
a20f0ba5
JB
714 const maxMultiplier = 2
715 for (let i = 0; i < max * maxMultiplier; i++) {
ee9f5295 716 promises.add(pool.execute())
e211bc18
JB
717 }
718 await Promise.all(promises)
719 for (const workerNode of pool.workerNodes) {
619f403b 720 expect(workerNode.usage).toStrictEqual({
a4e07f72
JB
721 tasks: {
722 executed: expect.any(Number),
723 executing: 0,
724 queued: 0,
df593701 725 maxQueued: 0,
68cbdc84 726 stolen: 0,
a4e07f72
JB
727 failed: 0
728 },
619f403b 729 runTime: expect.objectContaining({
a4e07f72 730 history: expect.any(CircularArray)
619f403b
JB
731 }),
732 waitTime: expect.objectContaining({
a4e07f72 733 history: expect.any(CircularArray)
619f403b 734 }),
5df69fab
JB
735 elu: {
736 idle: {
619f403b 737 history: new CircularArray()
5df69fab
JB
738 },
739 active: {
619f403b 740 history: new CircularArray()
71514351 741 }
5df69fab 742 }
e211bc18 743 })
465b2940
JB
744 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
745 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
a4e07f72
JB
746 max * maxMultiplier
747 )
19dbc45b
JB
748 if (workerNode.usage.runTime.aggregate == null) {
749 expect(workerNode.usage.runTime.aggregate).toBeUndefined()
750 } else {
751 expect(workerNode.usage.runTime.aggregate).toBeGreaterThan(0)
752 }
753 if (workerNode.usage.waitTime.aggregate == null) {
754 expect(workerNode.usage.waitTime.aggregate).toBeUndefined()
755 } else {
756 expect(workerNode.usage.waitTime.aggregate).toBeGreaterThan(0)
757 }
168c526f 758 }
168c526f
JB
759 // We need to clean up the resources after our test
760 await pool.destroy()
761 })
762
e4543b14 763 it('Verify LEAST_BUSY strategy can be run in a dynamic pool', async () => {
168c526f
JB
764 const pool = new DynamicThreadPool(
765 min,
766 max,
767 './tests/worker-files/thread/testWorker.js',
e4543b14 768 { workerChoiceStrategy: WorkerChoiceStrategies.LEAST_BUSY }
168c526f 769 )
e4543b14 770 // TODO: Create a better test to cover `LeastBusyWorkerChoiceStrategy#choose`
ee9f5295 771 const promises = new Set()
a20f0ba5
JB
772 const maxMultiplier = 2
773 for (let i = 0; i < max * maxMultiplier; i++) {
ee9f5295 774 promises.add(pool.execute())
e211bc18
JB
775 }
776 await Promise.all(promises)
777 for (const workerNode of pool.workerNodes) {
619f403b 778 expect(workerNode.usage).toStrictEqual({
a4e07f72
JB
779 tasks: {
780 executed: expect.any(Number),
781 executing: 0,
782 queued: 0,
df593701 783 maxQueued: 0,
68cbdc84 784 stolen: 0,
a4e07f72
JB
785 failed: 0
786 },
619f403b 787 runTime: expect.objectContaining({
a4e07f72 788 history: expect.any(CircularArray)
619f403b
JB
789 }),
790 waitTime: expect.objectContaining({
a4e07f72 791 history: expect.any(CircularArray)
619f403b 792 }),
5df69fab
JB
793 elu: {
794 idle: {
619f403b 795 history: new CircularArray()
5df69fab
JB
796 },
797 active: {
619f403b 798 history: new CircularArray()
71514351 799 }
5df69fab 800 }
e211bc18 801 })
465b2940
JB
802 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
803 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
a4e07f72
JB
804 max * maxMultiplier
805 )
19dbc45b
JB
806 if (workerNode.usage.runTime.aggregate == null) {
807 expect(workerNode.usage.runTime.aggregate).toBeUndefined()
808 } else {
809 expect(workerNode.usage.runTime.aggregate).toBeGreaterThan(0)
810 }
811 if (workerNode.usage.waitTime.aggregate == null) {
812 expect(workerNode.usage.waitTime.aggregate).toBeUndefined()
813 } else {
814 expect(workerNode.usage.waitTime.aggregate).toBeGreaterThan(0)
815 }
ff5e76e1 816 }
ff5e76e1
JB
817 // We need to clean up the resources after our test
818 await pool.destroy()
819 })
820
6c6afb84
JB
821 it('Verify LEAST_ELU strategy default policy', async () => {
822 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_ELU
823 let pool = new FixedThreadPool(
824 max,
825 './tests/worker-files/thread/testWorker.js',
826 { workerChoiceStrategy }
827 )
828 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
b1aae695
JB
829 dynamicWorkerUsage: false,
830 dynamicWorkerReady: true
6c6afb84
JB
831 })
832 await pool.destroy()
833 pool = new DynamicThreadPool(
834 min,
835 max,
836 './tests/worker-files/thread/testWorker.js',
837 { workerChoiceStrategy }
838 )
839 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
b1aae695
JB
840 dynamicWorkerUsage: false,
841 dynamicWorkerReady: true
6c6afb84
JB
842 })
843 // We need to clean up the resources after our test
844 await pool.destroy()
845 })
846
847 it('Verify LEAST_ELU strategy default tasks statistics requirements', async () => {
a7bbf44a
JB
848 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_ELU
849 let pool = new FixedThreadPool(
850 max,
851 './tests/worker-files/thread/testWorker.js',
852 { workerChoiceStrategy }
853 )
05302647
JB
854 expect(
855 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
856 ).toStrictEqual({
e460940e
JB
857 runTime: {
858 aggregate: false,
859 average: false,
860 median: false
861 },
862 waitTime: {
863 aggregate: false,
864 average: false,
865 median: false
866 },
5df69fab
JB
867 elu: {
868 aggregate: true,
869 average: false,
870 median: false
871 }
a7bbf44a
JB
872 })
873 await pool.destroy()
874 pool = new DynamicThreadPool(
875 min,
876 max,
877 './tests/worker-files/thread/testWorker.js',
878 { workerChoiceStrategy }
879 )
05302647
JB
880 expect(
881 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
882 ).toStrictEqual({
e460940e
JB
883 runTime: {
884 aggregate: false,
885 average: false,
886 median: false
887 },
888 waitTime: {
889 aggregate: false,
890 average: false,
891 median: false
892 },
5df69fab
JB
893 elu: {
894 aggregate: true,
895 average: false,
896 median: false
897 }
a7bbf44a
JB
898 })
899 // We need to clean up the resources after our test
900 await pool.destroy()
901 })
902
ae9cf3c8 903 it('Verify LEAST_ELU strategy can be run in a fixed pool', async () => {
c5ad42cd
JB
904 const pool = new FixedThreadPool(
905 max,
906 './tests/worker-files/thread/testWorker.js',
907 { workerChoiceStrategy: WorkerChoiceStrategies.LEAST_ELU }
908 )
909 // TODO: Create a better test to cover `LeastEluWorkerChoiceStrategy#choose`
dd38581f 910 const promises = new Set()
c5ad42cd
JB
911 const maxMultiplier = 2
912 for (let i = 0; i < max * maxMultiplier; i++) {
dd38581f 913 promises.add(pool.execute())
c5ad42cd 914 }
dd38581f 915 await Promise.all(promises)
c5ad42cd 916 for (const workerNode of pool.workerNodes) {
619f403b 917 expect(workerNode.usage).toStrictEqual({
c5ad42cd
JB
918 tasks: {
919 executed: expect.any(Number),
920 executing: 0,
921 queued: 0,
df593701 922 maxQueued: 0,
68cbdc84 923 stolen: 0,
c5ad42cd
JB
924 failed: 0
925 },
926 runTime: {
619f403b 927 history: new CircularArray()
a1347286
JB
928 },
929 waitTime: {
619f403b 930 history: new CircularArray()
5df69fab 931 },
619f403b
JB
932 elu: expect.objectContaining({
933 idle: expect.objectContaining({
5df69fab 934 history: expect.any(CircularArray)
619f403b
JB
935 }),
936 active: expect.objectContaining({
5df69fab 937 history: expect.any(CircularArray)
619f403b
JB
938 })
939 })
5df69fab 940 })
465b2940
JB
941 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
942 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
a1347286
JB
943 max * maxMultiplier
944 )
7db63069
JB
945 if (workerNode.usage.elu.active.aggregate == null) {
946 expect(workerNode.usage.elu.active.aggregate).toBeUndefined()
947 } else {
948 expect(workerNode.usage.elu.active.aggregate).toBeGreaterThan(0)
949 }
950 if (workerNode.usage.elu.idle.aggregate == null) {
951 expect(workerNode.usage.elu.idle.aggregate).toBeUndefined()
952 } else {
953 expect(workerNode.usage.elu.idle.aggregate).toBeGreaterThanOrEqual(0)
954 }
71514351
JB
955 if (workerNode.usage.elu.utilization == null) {
956 expect(workerNode.usage.elu.utilization).toBeUndefined()
957 } else {
958 expect(workerNode.usage.elu.utilization).toBeGreaterThanOrEqual(0)
959 expect(workerNode.usage.elu.utilization).toBeLessThanOrEqual(1)
960 }
a1347286
JB
961 }
962 // We need to clean up the resources after our test
963 await pool.destroy()
964 })
965
966 it('Verify LEAST_ELU strategy can be run in a dynamic pool', async () => {
967 const pool = new DynamicThreadPool(
968 min,
969 max,
970 './tests/worker-files/thread/testWorker.js',
971 { workerChoiceStrategy: WorkerChoiceStrategies.LEAST_ELU }
972 )
973 // TODO: Create a better test to cover `LeastEluWorkerChoiceStrategy#choose`
dd38581f 974 const promises = new Set()
a1347286
JB
975 const maxMultiplier = 2
976 for (let i = 0; i < max * maxMultiplier; i++) {
dd38581f 977 promises.add(pool.execute())
a1347286 978 }
dd38581f 979 await Promise.all(promises)
a1347286 980 for (const workerNode of pool.workerNodes) {
619f403b 981 expect(workerNode.usage).toStrictEqual({
a1347286
JB
982 tasks: {
983 executed: expect.any(Number),
984 executing: 0,
985 queued: 0,
df593701 986 maxQueued: 0,
68cbdc84 987 stolen: 0,
a1347286
JB
988 failed: 0
989 },
990 runTime: {
619f403b 991 history: new CircularArray()
c5ad42cd
JB
992 },
993 waitTime: {
619f403b 994 history: new CircularArray()
5df69fab 995 },
619f403b
JB
996 elu: expect.objectContaining({
997 idle: expect.objectContaining({
5df69fab 998 history: expect.any(CircularArray)
619f403b
JB
999 }),
1000 active: expect.objectContaining({
5df69fab 1001 history: expect.any(CircularArray)
619f403b
JB
1002 })
1003 })
5df69fab 1004 })
465b2940
JB
1005 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
1006 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
c5ad42cd
JB
1007 max * maxMultiplier
1008 )
7db63069
JB
1009 if (workerNode.usage.elu.active.aggregate == null) {
1010 expect(workerNode.usage.elu.active.aggregate).toBeUndefined()
1011 } else {
1012 expect(workerNode.usage.elu.active.aggregate).toBeGreaterThan(0)
1013 }
1014 if (workerNode.usage.elu.idle.aggregate == null) {
1015 expect(workerNode.usage.elu.idle.aggregate).toBeUndefined()
1016 } else {
1017 expect(workerNode.usage.elu.idle.aggregate).toBeGreaterThanOrEqual(0)
1018 }
71514351
JB
1019 if (workerNode.usage.elu.utilization == null) {
1020 expect(workerNode.usage.elu.utilization).toBeUndefined()
1021 } else {
1022 expect(workerNode.usage.elu.utilization).toBeGreaterThanOrEqual(0)
1023 expect(workerNode.usage.elu.utilization).toBeLessThanOrEqual(1)
1024 }
c5ad42cd
JB
1025 }
1026 // We need to clean up the resources after our test
1027 await pool.destroy()
1028 })
1029
6c6afb84
JB
1030 it('Verify FAIR_SHARE strategy default policy', async () => {
1031 const workerChoiceStrategy = WorkerChoiceStrategies.FAIR_SHARE
1032 let pool = new FixedThreadPool(
1033 max,
1034 './tests/worker-files/thread/testWorker.js',
1035 { workerChoiceStrategy }
1036 )
1037 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
b1aae695
JB
1038 dynamicWorkerUsage: false,
1039 dynamicWorkerReady: true
6c6afb84
JB
1040 })
1041 await pool.destroy()
1042 pool = new DynamicThreadPool(
1043 min,
1044 max,
1045 './tests/worker-files/thread/testWorker.js',
1046 { workerChoiceStrategy }
1047 )
1048 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
b1aae695
JB
1049 dynamicWorkerUsage: false,
1050 dynamicWorkerReady: true
6c6afb84
JB
1051 })
1052 // We need to clean up the resources after our test
1053 await pool.destroy()
1054 })
1055
1056 it('Verify FAIR_SHARE strategy default tasks statistics requirements', async () => {
594bfb84 1057 const workerChoiceStrategy = WorkerChoiceStrategies.FAIR_SHARE
10fcfaf4
JB
1058 let pool = new FixedThreadPool(
1059 max,
d710242d 1060 './tests/worker-files/thread/testWorker.js',
594bfb84 1061 { workerChoiceStrategy }
10fcfaf4 1062 )
87de9ff5
JB
1063 expect(
1064 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
1065 ).toStrictEqual({
932fc8be
JB
1066 runTime: {
1067 aggregate: true,
1068 average: true,
1069 median: false
1070 },
1071 waitTime: {
1072 aggregate: false,
1073 average: false,
1074 median: false
1075 },
5df69fab 1076 elu: {
9adcefab
JB
1077 aggregate: true,
1078 average: true,
5df69fab
JB
1079 median: false
1080 }
86bf340d 1081 })
fd7ebd49 1082 await pool.destroy()
10fcfaf4
JB
1083 pool = new DynamicThreadPool(
1084 min,
1085 max,
d710242d 1086 './tests/worker-files/thread/testWorker.js',
594bfb84 1087 { workerChoiceStrategy }
10fcfaf4 1088 )
87de9ff5
JB
1089 expect(
1090 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
1091 ).toStrictEqual({
932fc8be
JB
1092 runTime: {
1093 aggregate: true,
1094 average: true,
1095 median: false
1096 },
1097 waitTime: {
1098 aggregate: false,
1099 average: false,
1100 median: false
1101 },
5df69fab 1102 elu: {
9adcefab
JB
1103 aggregate: true,
1104 average: true,
5df69fab
JB
1105 median: false
1106 }
86bf340d 1107 })
10fcfaf4
JB
1108 // We need to clean up the resources after our test
1109 await pool.destroy()
1110 })
1111
23ff945a 1112 it('Verify FAIR_SHARE strategy can be run in a fixed pool', async () => {
23ff945a
JB
1113 const pool = new FixedThreadPool(
1114 max,
1115 './tests/worker-files/thread/testWorker.js',
1116 { workerChoiceStrategy: WorkerChoiceStrategies.FAIR_SHARE }
1117 )
1118 // TODO: Create a better test to cover `FairShareChoiceStrategy#choose`
ee9f5295 1119 const promises = new Set()
a20f0ba5
JB
1120 const maxMultiplier = 2
1121 for (let i = 0; i < max * maxMultiplier; i++) {
ee9f5295 1122 promises.add(pool.execute())
23ff945a 1123 }
e211bc18 1124 await Promise.all(promises)
138d29a8 1125 for (const workerNode of pool.workerNodes) {
619f403b 1126 expect(workerNode.usage).toStrictEqual({
a4e07f72 1127 tasks: {
d33be430 1128 executed: expect.any(Number),
a4e07f72
JB
1129 executing: 0,
1130 queued: 0,
df593701 1131 maxQueued: 0,
68cbdc84 1132 stolen: 0,
a4e07f72
JB
1133 failed: 0
1134 },
619f403b 1135 runTime: expect.objectContaining({
a4e07f72 1136 history: expect.any(CircularArray)
619f403b 1137 }),
a4e07f72 1138 waitTime: {
619f403b 1139 history: new CircularArray()
a4e07f72 1140 },
619f403b
JB
1141 elu: expect.objectContaining({
1142 idle: expect.objectContaining({
5df69fab 1143 history: expect.any(CircularArray)
619f403b
JB
1144 }),
1145 active: expect.objectContaining({
5df69fab 1146 history: expect.any(CircularArray)
619f403b
JB
1147 })
1148 })
86bf340d 1149 })
465b2940
JB
1150 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
1151 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
d33be430
JB
1152 max * maxMultiplier
1153 )
71514351
JB
1154 if (workerNode.usage.runTime.aggregate == null) {
1155 expect(workerNode.usage.runTime.aggregate).toBeUndefined()
1156 } else {
1157 expect(workerNode.usage.runTime.aggregate).toBeGreaterThan(0)
1158 }
1159 if (workerNode.usage.runTime.average == null) {
1160 expect(workerNode.usage.runTime.average).toBeUndefined()
1161 } else {
1162 expect(workerNode.usage.runTime.average).toBeGreaterThan(0)
1163 }
7db63069
JB
1164 if (workerNode.usage.elu.active.aggregate == null) {
1165 expect(workerNode.usage.elu.active.aggregate).toBeUndefined()
1166 } else {
1167 expect(workerNode.usage.elu.active.aggregate).toBeGreaterThan(0)
1168 }
1169 if (workerNode.usage.elu.idle.aggregate == null) {
1170 expect(workerNode.usage.elu.idle.aggregate).toBeUndefined()
1171 } else {
1172 expect(workerNode.usage.elu.idle.aggregate).toBeGreaterThanOrEqual(0)
1173 }
71514351
JB
1174 if (workerNode.usage.elu.utilization == null) {
1175 expect(workerNode.usage.elu.utilization).toBeUndefined()
1176 } else {
1177 expect(workerNode.usage.elu.utilization).toBeGreaterThanOrEqual(0)
1178 expect(workerNode.usage.elu.utilization).toBeLessThanOrEqual(1)
1179 }
138d29a8 1180 }
97a2abc3 1181 expect(
95c83464 1182 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
d710242d 1183 pool.workerChoiceStrategyContext.workerChoiceStrategy
b0d6ed8f 1184 ).workersVirtualTaskEndTimestamp.length
f06e48d8 1185 ).toBe(pool.workerNodes.length)
23ff945a
JB
1186 // We need to clean up the resources after our test
1187 await pool.destroy()
1188 })
1189
1190 it('Verify FAIR_SHARE strategy can be run in a dynamic pool', async () => {
23ff945a
JB
1191 const pool = new DynamicThreadPool(
1192 min,
1193 max,
1194 './tests/worker-files/thread/testWorker.js',
1195 { workerChoiceStrategy: WorkerChoiceStrategies.FAIR_SHARE }
1196 )
1197 // TODO: Create a better test to cover `FairShareChoiceStrategy#choose`
ee9f5295 1198 const promises = new Set()
f7070eee 1199 const maxMultiplier = 2
804a889e 1200 for (let i = 0; i < max * maxMultiplier; i++) {
ee9f5295 1201 promises.add(pool.execute())
23ff945a 1202 }
e211bc18 1203 await Promise.all(promises)
138d29a8 1204 for (const workerNode of pool.workerNodes) {
619f403b 1205 expect(workerNode.usage).toStrictEqual({
a4e07f72 1206 tasks: {
6c6afb84 1207 executed: expect.any(Number),
a4e07f72
JB
1208 executing: 0,
1209 queued: 0,
df593701 1210 maxQueued: 0,
68cbdc84 1211 stolen: 0,
a4e07f72
JB
1212 failed: 0
1213 },
619f403b 1214 runTime: expect.objectContaining({
a4e07f72 1215 history: expect.any(CircularArray)
619f403b 1216 }),
a4e07f72 1217 waitTime: {
619f403b 1218 history: new CircularArray()
a4e07f72 1219 },
619f403b
JB
1220 elu: expect.objectContaining({
1221 idle: expect.objectContaining({
5df69fab 1222 history: expect.any(CircularArray)
619f403b
JB
1223 }),
1224 active: expect.objectContaining({
5df69fab 1225 history: expect.any(CircularArray)
619f403b
JB
1226 })
1227 })
86bf340d 1228 })
465b2940
JB
1229 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
1230 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
6c6afb84
JB
1231 max * maxMultiplier
1232 )
71514351
JB
1233 if (workerNode.usage.runTime.aggregate == null) {
1234 expect(workerNode.usage.runTime.aggregate).toBeUndefined()
1235 } else {
1236 expect(workerNode.usage.runTime.aggregate).toBeGreaterThan(0)
1237 }
1238 if (workerNode.usage.runTime.average == null) {
1239 expect(workerNode.usage.runTime.average).toBeUndefined()
1240 } else {
1241 expect(workerNode.usage.runTime.average).toBeGreaterThan(0)
1242 }
7db63069
JB
1243 if (workerNode.usage.elu.active.aggregate == null) {
1244 expect(workerNode.usage.elu.active.aggregate).toBeUndefined()
1245 } else {
1246 expect(workerNode.usage.elu.active.aggregate).toBeGreaterThan(0)
1247 }
1248 if (workerNode.usage.elu.idle.aggregate == null) {
1249 expect(workerNode.usage.elu.idle.aggregate).toBeUndefined()
1250 } else {
1251 expect(workerNode.usage.elu.idle.aggregate).toBeGreaterThanOrEqual(0)
1252 }
71514351
JB
1253 if (workerNode.usage.elu.utilization == null) {
1254 expect(workerNode.usage.elu.utilization).toBeUndefined()
1255 } else {
1256 expect(workerNode.usage.elu.utilization).toBeGreaterThanOrEqual(0)
1257 expect(workerNode.usage.elu.utilization).toBeLessThanOrEqual(1)
1258 }
138d29a8 1259 }
2b4fddb8
JB
1260 expect(
1261 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1262 pool.workerChoiceStrategyContext.workerChoiceStrategy
b0d6ed8f 1263 ).workersVirtualTaskEndTimestamp.length
2b4fddb8 1264 ).toBe(pool.workerNodes.length)
23ff945a
JB
1265 // We need to clean up the resources after our test
1266 await pool.destroy()
1267 })
1268
9e775f96 1269 it('Verify FAIR_SHARE strategy can be run in a dynamic pool with median runtime statistic', async () => {
010d7020
JB
1270 const pool = new DynamicThreadPool(
1271 min,
1272 max,
1273 './tests/worker-files/thread/testWorker.js',
1274 {
1275 workerChoiceStrategy: WorkerChoiceStrategies.FAIR_SHARE,
1276 workerChoiceStrategyOptions: {
932fc8be 1277 runTime: { median: true }
010d7020
JB
1278 }
1279 }
1280 )
1281 // TODO: Create a better test to cover `FairShareChoiceStrategy#choose`
ee9f5295 1282 const promises = new Set()
010d7020
JB
1283 const maxMultiplier = 2
1284 for (let i = 0; i < max * maxMultiplier; i++) {
ee9f5295 1285 promises.add(pool.execute())
010d7020 1286 }
e211bc18 1287 await Promise.all(promises)
010d7020 1288 for (const workerNode of pool.workerNodes) {
619f403b 1289 expect(workerNode.usage).toStrictEqual({
a4e07f72 1290 tasks: {
6c6afb84 1291 executed: expect.any(Number),
a4e07f72
JB
1292 executing: 0,
1293 queued: 0,
df593701 1294 maxQueued: 0,
68cbdc84 1295 stolen: 0,
a4e07f72
JB
1296 failed: 0
1297 },
619f403b 1298 runTime: expect.objectContaining({
a4e07f72 1299 history: expect.any(CircularArray)
619f403b 1300 }),
a4e07f72 1301 waitTime: {
619f403b 1302 history: new CircularArray()
a4e07f72 1303 },
619f403b
JB
1304 elu: expect.objectContaining({
1305 idle: expect.objectContaining({
5df69fab 1306 history: expect.any(CircularArray)
619f403b
JB
1307 }),
1308 active: expect.objectContaining({
5df69fab 1309 history: expect.any(CircularArray)
619f403b
JB
1310 })
1311 })
86bf340d 1312 })
465b2940
JB
1313 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
1314 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
6c6afb84
JB
1315 max * maxMultiplier
1316 )
71514351
JB
1317 if (workerNode.usage.runTime.aggregate == null) {
1318 expect(workerNode.usage.runTime.aggregate).toBeUndefined()
1319 } else {
1320 expect(workerNode.usage.runTime.aggregate).toBeGreaterThan(0)
1321 }
1322 if (workerNode.usage.runTime.median == null) {
1323 expect(workerNode.usage.runTime.median).toBeUndefined()
1324 } else {
1325 expect(workerNode.usage.runTime.median).toBeGreaterThan(0)
1326 }
7db63069
JB
1327 if (workerNode.usage.elu.active.aggregate == null) {
1328 expect(workerNode.usage.elu.active.aggregate).toBeUndefined()
1329 } else {
1330 expect(workerNode.usage.elu.active.aggregate).toBeGreaterThan(0)
1331 }
1332 if (workerNode.usage.elu.idle.aggregate == null) {
1333 expect(workerNode.usage.elu.idle.aggregate).toBeUndefined()
1334 } else {
1335 expect(workerNode.usage.elu.idle.aggregate).toBeGreaterThanOrEqual(0)
1336 }
71514351
JB
1337 if (workerNode.usage.elu.utilization == null) {
1338 expect(workerNode.usage.elu.utilization).toBeUndefined()
1339 } else {
1340 expect(workerNode.usage.elu.utilization).toBeGreaterThanOrEqual(0)
1341 expect(workerNode.usage.elu.utilization).toBeLessThanOrEqual(1)
1342 }
010d7020 1343 }
2b4fddb8
JB
1344 expect(
1345 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1346 pool.workerChoiceStrategyContext.workerChoiceStrategy
b0d6ed8f 1347 ).workersVirtualTaskEndTimestamp.length
2b4fddb8 1348 ).toBe(pool.workerNodes.length)
010d7020
JB
1349 // We need to clean up the resources after our test
1350 await pool.destroy()
1351 })
1352
a6f7f1b4 1353 it('Verify FAIR_SHARE strategy internals are resets after setting it', async () => {
594bfb84 1354 const workerChoiceStrategy = WorkerChoiceStrategies.FAIR_SHARE
f0829c53 1355 let pool = new FixedThreadPool(
caeb9817
JB
1356 max,
1357 './tests/worker-files/thread/testWorker.js'
1358 )
1359 expect(
95c83464 1360 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 1361 workerChoiceStrategy
b0d6ed8f 1362 ).workersVirtualTaskEndTimestamp
08f3f44c
JB
1363 ).toBeInstanceOf(Array)
1364 expect(
1365 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1366 workerChoiceStrategy
b0d6ed8f 1367 ).workersVirtualTaskEndTimestamp.length
08f3f44c 1368 ).toBe(0)
2b4fddb8
JB
1369 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1370 workerChoiceStrategy
b0d6ed8f 1371 ).workersVirtualTaskEndTimestamp[0] = performance.now()
2b4fddb8
JB
1372 expect(
1373 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1374 workerChoiceStrategy
b0d6ed8f 1375 ).workersVirtualTaskEndTimestamp.length
2b4fddb8 1376 ).toBe(1)
594bfb84 1377 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
08f3f44c
JB
1378 expect(
1379 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
086fd843 1380 pool.workerChoiceStrategyContext.workerChoiceStrategy
b0d6ed8f 1381 ).workersVirtualTaskEndTimestamp
08f3f44c 1382 ).toBeInstanceOf(Array)
08f3f44c
JB
1383 expect(
1384 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
086fd843 1385 pool.workerChoiceStrategyContext.workerChoiceStrategy
b0d6ed8f 1386 ).workersVirtualTaskEndTimestamp.length
2b4fddb8 1387 ).toBe(0)
f0829c53
JB
1388 await pool.destroy()
1389 pool = new DynamicThreadPool(
1390 min,
1391 max,
1392 './tests/worker-files/thread/testWorker.js'
1393 )
1394 expect(
95c83464 1395 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 1396 workerChoiceStrategy
b0d6ed8f 1397 ).workersVirtualTaskEndTimestamp
08f3f44c 1398 ).toBeInstanceOf(Array)
2b4fddb8
JB
1399 expect(
1400 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1401 workerChoiceStrategy
b0d6ed8f 1402 ).workersVirtualTaskEndTimestamp.length
2b4fddb8 1403 ).toBe(0)
08f3f44c
JB
1404 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1405 workerChoiceStrategy
b0d6ed8f 1406 ).workersVirtualTaskEndTimestamp[0] = performance.now()
08f3f44c
JB
1407 expect(
1408 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1409 workerChoiceStrategy
b0d6ed8f 1410 ).workersVirtualTaskEndTimestamp.length
08f3f44c 1411 ).toBe(1)
594bfb84 1412 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
08f3f44c
JB
1413 expect(
1414 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
086fd843 1415 pool.workerChoiceStrategyContext.workerChoiceStrategy
b0d6ed8f 1416 ).workersVirtualTaskEndTimestamp
08f3f44c
JB
1417 ).toBeInstanceOf(Array)
1418 expect(
1419 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
086fd843 1420 pool.workerChoiceStrategyContext.workerChoiceStrategy
b0d6ed8f 1421 ).workersVirtualTaskEndTimestamp.length
08f3f44c 1422 ).toBe(0)
caeb9817
JB
1423 // We need to clean up the resources after our test
1424 await pool.destroy()
1425 })
1426
6c6afb84
JB
1427 it('Verify WEIGHTED_ROUND_ROBIN strategy default policy', async () => {
1428 const workerChoiceStrategy = WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
1429 let pool = new FixedThreadPool(
1430 max,
1431 './tests/worker-files/thread/testWorker.js',
1432 { workerChoiceStrategy }
1433 )
1434 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
b1aae695
JB
1435 dynamicWorkerUsage: false,
1436 dynamicWorkerReady: true
6c6afb84
JB
1437 })
1438 await pool.destroy()
1439 pool = new DynamicThreadPool(
1440 min,
1441 max,
1442 './tests/worker-files/thread/testWorker.js',
1443 { workerChoiceStrategy }
1444 )
1445 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
b1aae695
JB
1446 dynamicWorkerUsage: false,
1447 dynamicWorkerReady: true
6c6afb84
JB
1448 })
1449 // We need to clean up the resources after our test
1450 await pool.destroy()
1451 })
1452
1453 it('Verify WEIGHTED_ROUND_ROBIN strategy default tasks statistics requirements', async () => {
594bfb84 1454 const workerChoiceStrategy = WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
10fcfaf4
JB
1455 let pool = new FixedThreadPool(
1456 max,
d710242d 1457 './tests/worker-files/thread/testWorker.js',
594bfb84 1458 { workerChoiceStrategy }
10fcfaf4 1459 )
87de9ff5
JB
1460 expect(
1461 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
1462 ).toStrictEqual({
932fc8be
JB
1463 runTime: {
1464 aggregate: true,
1465 average: true,
1466 median: false
1467 },
1468 waitTime: {
1469 aggregate: false,
1470 average: false,
1471 median: false
1472 },
5df69fab
JB
1473 elu: {
1474 aggregate: false,
1475 average: false,
1476 median: false
1477 }
86bf340d 1478 })
fd7ebd49 1479 await pool.destroy()
10fcfaf4
JB
1480 pool = new DynamicThreadPool(
1481 min,
1482 max,
d710242d 1483 './tests/worker-files/thread/testWorker.js',
594bfb84 1484 { workerChoiceStrategy }
10fcfaf4 1485 )
87de9ff5
JB
1486 expect(
1487 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
1488 ).toStrictEqual({
932fc8be
JB
1489 runTime: {
1490 aggregate: true,
1491 average: true,
1492 median: false
1493 },
1494 waitTime: {
1495 aggregate: false,
1496 average: false,
1497 median: false
1498 },
5df69fab
JB
1499 elu: {
1500 aggregate: false,
1501 average: false,
1502 median: false
1503 }
86bf340d 1504 })
10fcfaf4
JB
1505 // We need to clean up the resources after our test
1506 await pool.destroy()
1507 })
1508
b3432a63 1509 it('Verify WEIGHTED_ROUND_ROBIN strategy can be run in a fixed pool', async () => {
b3432a63
JB
1510 const pool = new FixedThreadPool(
1511 max,
1512 './tests/worker-files/thread/testWorker.js',
1513 { workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN }
1514 )
1515 // TODO: Create a better test to cover `WeightedRoundRobinWorkerChoiceStrategy#choose`
ee9f5295 1516 const promises = new Set()
a20f0ba5
JB
1517 const maxMultiplier = 2
1518 for (let i = 0; i < max * maxMultiplier; i++) {
ee9f5295 1519 promises.add(pool.execute())
b3432a63 1520 }
e211bc18 1521 await Promise.all(promises)
138d29a8 1522 for (const workerNode of pool.workerNodes) {
465b2940 1523 expect(workerNode.usage).toStrictEqual({
a4e07f72
JB
1524 tasks: {
1525 executed: expect.any(Number),
1526 executing: 0,
1527 queued: 0,
df593701 1528 maxQueued: 0,
68cbdc84 1529 stolen: 0,
a4e07f72
JB
1530 failed: 0
1531 },
71514351 1532 runTime: expect.objectContaining({
a4e07f72 1533 history: expect.any(CircularArray)
71514351 1534 }),
a4e07f72 1535 waitTime: {
619f403b 1536 history: new CircularArray()
a4e07f72 1537 },
5df69fab
JB
1538 elu: {
1539 idle: {
619f403b 1540 history: new CircularArray()
5df69fab
JB
1541 },
1542 active: {
619f403b 1543 history: new CircularArray()
71514351 1544 }
5df69fab 1545 }
86bf340d 1546 })
465b2940
JB
1547 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
1548 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
a4e07f72
JB
1549 max * maxMultiplier
1550 )
71514351
JB
1551 if (workerNode.usage.runTime.aggregate == null) {
1552 expect(workerNode.usage.runTime.aggregate).toBeUndefined()
1553 } else {
1554 expect(workerNode.usage.runTime.aggregate).toBeGreaterThan(0)
1555 }
1556 if (workerNode.usage.runTime.average == null) {
1557 expect(workerNode.usage.runTime.average).toBeUndefined()
1558 } else {
1559 expect(workerNode.usage.runTime.average).toBeGreaterThan(0)
1560 }
138d29a8 1561 }
97a2abc3 1562 expect(
95c83464 1563 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
d710242d 1564 pool.workerChoiceStrategyContext.workerChoiceStrategy
08f3f44c
JB
1565 ).defaultWorkerWeight
1566 ).toBeGreaterThan(0)
1567 expect(
1568 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1569 pool.workerChoiceStrategyContext.workerChoiceStrategy
1570 ).workerVirtualTaskRunTime
1571 ).toBeGreaterThanOrEqual(0)
b3432a63
JB
1572 // We need to clean up the resources after our test
1573 await pool.destroy()
1574 })
1575
1576 it('Verify WEIGHTED_ROUND_ROBIN strategy can be run in a dynamic pool', async () => {
b3432a63
JB
1577 const pool = new DynamicThreadPool(
1578 min,
1579 max,
1580 './tests/worker-files/thread/testWorker.js',
1581 { workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN }
1582 )
1583 // TODO: Create a better test to cover `WeightedRoundRobinWorkerChoiceStrategy#choose`
ee9f5295 1584 const promises = new Set()
138d29a8 1585 const maxMultiplier = 2
5502c07c 1586 for (let i = 0; i < max * maxMultiplier; i++) {
ee9f5295 1587 promises.add(pool.execute())
b3432a63 1588 }
e211bc18 1589 await Promise.all(promises)
138d29a8 1590 for (const workerNode of pool.workerNodes) {
465b2940 1591 expect(workerNode.usage).toStrictEqual({
a4e07f72
JB
1592 tasks: {
1593 executed: expect.any(Number),
1594 executing: 0,
1595 queued: 0,
df593701 1596 maxQueued: 0,
68cbdc84 1597 stolen: 0,
a4e07f72
JB
1598 failed: 0
1599 },
b1aae695 1600 runTime: expect.objectContaining({
a4e07f72 1601 history: expect.any(CircularArray)
b1aae695 1602 }),
a4e07f72 1603 waitTime: {
619f403b 1604 history: new CircularArray()
a4e07f72 1605 },
5df69fab
JB
1606 elu: {
1607 idle: {
619f403b 1608 history: new CircularArray()
5df69fab
JB
1609 },
1610 active: {
619f403b 1611 history: new CircularArray()
71514351 1612 }
5df69fab 1613 }
86bf340d 1614 })
465b2940
JB
1615 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
1616 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
a4e07f72
JB
1617 max * maxMultiplier
1618 )
b1aae695
JB
1619 if (workerNode.usage.runTime.aggregate == null) {
1620 expect(workerNode.usage.runTime.aggregate).toBeUndefined()
1621 } else {
1622 expect(workerNode.usage.runTime.aggregate).toBeGreaterThan(0)
1623 }
1624 if (workerNode.usage.runTime.average == null) {
1625 expect(workerNode.usage.runTime.average).toBeUndefined()
1626 } else {
1627 expect(workerNode.usage.runTime.average).toBeGreaterThan(0)
1628 }
138d29a8 1629 }
2b4fddb8
JB
1630 expect(
1631 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1632 pool.workerChoiceStrategyContext.workerChoiceStrategy
1633 ).defaultWorkerWeight
1634 ).toBeGreaterThan(0)
1635 expect(
1636 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1637 pool.workerChoiceStrategyContext.workerChoiceStrategy
1638 ).workerVirtualTaskRunTime
1639 ).toBeGreaterThanOrEqual(0)
b3432a63
JB
1640 // We need to clean up the resources after our test
1641 await pool.destroy()
1642 })
1643
9e775f96 1644 it('Verify WEIGHTED_ROUND_ROBIN strategy can be run in a dynamic pool with median runtime statistic', async () => {
010d7020
JB
1645 const pool = new DynamicThreadPool(
1646 min,
1647 max,
1648 './tests/worker-files/thread/testWorker.js',
1649 {
1650 workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN,
1651 workerChoiceStrategyOptions: {
932fc8be 1652 runTime: { median: true }
010d7020
JB
1653 }
1654 }
1655 )
1656 // TODO: Create a better test to cover `WeightedRoundRobinWorkerChoiceStrategy#choose`
ee9f5295 1657 const promises = new Set()
010d7020
JB
1658 const maxMultiplier = 2
1659 for (let i = 0; i < max * maxMultiplier; i++) {
ee9f5295 1660 promises.add(pool.execute())
010d7020 1661 }
e211bc18 1662 await Promise.all(promises)
010d7020 1663 for (const workerNode of pool.workerNodes) {
465b2940 1664 expect(workerNode.usage).toStrictEqual({
a4e07f72
JB
1665 tasks: {
1666 executed: expect.any(Number),
1667 executing: 0,
1668 queued: 0,
df593701 1669 maxQueued: 0,
68cbdc84 1670 stolen: 0,
a4e07f72
JB
1671 failed: 0
1672 },
b1aae695 1673 runTime: expect.objectContaining({
a4e07f72 1674 history: expect.any(CircularArray)
b1aae695 1675 }),
a4e07f72 1676 waitTime: {
619f403b 1677 history: new CircularArray()
a4e07f72 1678 },
5df69fab
JB
1679 elu: {
1680 idle: {
619f403b 1681 history: new CircularArray()
5df69fab
JB
1682 },
1683 active: {
619f403b 1684 history: new CircularArray()
71514351 1685 }
5df69fab 1686 }
86bf340d 1687 })
465b2940
JB
1688 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
1689 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
a4e07f72
JB
1690 max * maxMultiplier
1691 )
b1aae695
JB
1692 if (workerNode.usage.runTime.aggregate == null) {
1693 expect(workerNode.usage.runTime.aggregate).toBeUndefined()
1694 } else {
1695 expect(workerNode.usage.runTime.aggregate).toBeGreaterThan(0)
1696 }
1697 if (workerNode.usage.runTime.median == null) {
1698 expect(workerNode.usage.runTime.median).toBeUndefined()
1699 } else {
1700 expect(workerNode.usage.runTime.median).toBeGreaterThan(0)
1701 }
010d7020 1702 }
08f3f44c
JB
1703 expect(
1704 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1705 pool.workerChoiceStrategyContext.workerChoiceStrategy
1706 ).defaultWorkerWeight
1707 ).toBeGreaterThan(0)
1708 expect(
1709 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1710 pool.workerChoiceStrategyContext.workerChoiceStrategy
1711 ).workerVirtualTaskRunTime
1712 ).toBeGreaterThanOrEqual(0)
010d7020
JB
1713 // We need to clean up the resources after our test
1714 await pool.destroy()
1715 })
1716
a6f7f1b4 1717 it('Verify WEIGHTED_ROUND_ROBIN strategy internals are resets after setting it', async () => {
594bfb84 1718 const workerChoiceStrategy = WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
f0829c53 1719 let pool = new FixedThreadPool(
caeb9817
JB
1720 max,
1721 './tests/worker-files/thread/testWorker.js'
1722 )
38f6e859 1723 expect(
95c83464 1724 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 1725 workerChoiceStrategy
9b106837 1726 ).nextWorkerNodeKey
b529c323 1727 ).toBeDefined()
086fd843
JB
1728 expect(
1729 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1730 workerChoiceStrategy
1731 ).previousWorkerNodeKey
1732 ).toBeDefined()
38f6e859 1733 expect(
95c83464 1734 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 1735 workerChoiceStrategy
b529c323
JB
1736 ).defaultWorkerWeight
1737 ).toBeDefined()
caeb9817 1738 expect(
95c83464 1739 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 1740 workerChoiceStrategy
08f3f44c 1741 ).workerVirtualTaskRunTime
b529c323 1742 ).toBeDefined()
594bfb84 1743 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
a6f7f1b4 1744 expect(
95c83464 1745 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
d710242d 1746 pool.workerChoiceStrategyContext.workerChoiceStrategy
9b106837 1747 ).nextWorkerNodeKey
a6f7f1b4 1748 ).toBe(0)
086fd843
JB
1749 expect(
1750 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1751 pool.workerChoiceStrategyContext.workerChoiceStrategy
1752 ).previousWorkerNodeKey
1753 ).toBe(0)
a6f7f1b4 1754 expect(
95c83464 1755 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
d710242d 1756 pool.workerChoiceStrategyContext.workerChoiceStrategy
95c83464 1757 ).defaultWorkerWeight
a6f7f1b4 1758 ).toBeGreaterThan(0)
08f3f44c
JB
1759 expect(
1760 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
086fd843 1761 pool.workerChoiceStrategyContext.workerChoiceStrategy
08f3f44c
JB
1762 ).workerVirtualTaskRunTime
1763 ).toBe(0)
f0829c53
JB
1764 await pool.destroy()
1765 pool = new DynamicThreadPool(
1766 min,
1767 max,
1768 './tests/worker-files/thread/testWorker.js'
1769 )
38f6e859 1770 expect(
95c83464 1771 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 1772 workerChoiceStrategy
9b106837 1773 ).nextWorkerNodeKey
b529c323 1774 ).toBeDefined()
086fd843
JB
1775 expect(
1776 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1777 workerChoiceStrategy
1778 ).previousWorkerNodeKey
1779 ).toBeDefined()
38f6e859 1780 expect(
95c83464 1781 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 1782 workerChoiceStrategy
b529c323
JB
1783 ).defaultWorkerWeight
1784 ).toBeDefined()
f0829c53 1785 expect(
95c83464 1786 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 1787 workerChoiceStrategy
08f3f44c 1788 ).workerVirtualTaskRunTime
b529c323 1789 ).toBeDefined()
594bfb84 1790 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
a6f7f1b4 1791 expect(
95c83464 1792 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
d710242d 1793 pool.workerChoiceStrategyContext.workerChoiceStrategy
9b106837 1794 ).nextWorkerNodeKey
a6f7f1b4 1795 ).toBe(0)
086fd843
JB
1796 expect(
1797 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1798 pool.workerChoiceStrategyContext.workerChoiceStrategy
1799 ).previousWorkerNodeKey
1800 ).toBe(0)
a6f7f1b4 1801 expect(
95c83464 1802 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
d710242d 1803 pool.workerChoiceStrategyContext.workerChoiceStrategy
95c83464 1804 ).defaultWorkerWeight
a6f7f1b4 1805 ).toBeGreaterThan(0)
08f3f44c
JB
1806 expect(
1807 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
086fd843 1808 pool.workerChoiceStrategyContext.workerChoiceStrategy
08f3f44c
JB
1809 ).workerVirtualTaskRunTime
1810 ).toBe(0)
caeb9817
JB
1811 // We need to clean up the resources after our test
1812 await pool.destroy()
1813 })
1814
6c6afb84
JB
1815 it('Verify INTERLEAVED_WEIGHTED_ROUND_ROBIN strategy default policy', async () => {
1816 const workerChoiceStrategy =
1817 WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
1818 let pool = new FixedThreadPool(
1819 max,
1820 './tests/worker-files/thread/testWorker.js',
1821 { workerChoiceStrategy }
1822 )
1823 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
b1aae695
JB
1824 dynamicWorkerUsage: false,
1825 dynamicWorkerReady: true
6c6afb84
JB
1826 })
1827 await pool.destroy()
1828 pool = new DynamicThreadPool(
1829 min,
1830 max,
1831 './tests/worker-files/thread/testWorker.js',
1832 { workerChoiceStrategy }
1833 )
1834 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
b1aae695
JB
1835 dynamicWorkerUsage: false,
1836 dynamicWorkerReady: true
6c6afb84
JB
1837 })
1838 // We need to clean up the resources after our test
1839 await pool.destroy()
1840 })
1841
1842 it('Verify INTERLEAVED_WEIGHTED_ROUND_ROBIN strategy default tasks statistics requirements', async () => {
e52fb978
JB
1843 const workerChoiceStrategy =
1844 WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
1845 let pool = new FixedThreadPool(
1846 max,
1847 './tests/worker-files/thread/testWorker.js',
1848 { workerChoiceStrategy }
1849 )
87de9ff5
JB
1850 expect(
1851 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
1852 ).toStrictEqual({
932fc8be 1853 runTime: {
619f403b
JB
1854 aggregate: true,
1855 average: true,
932fc8be
JB
1856 median: false
1857 },
1858 waitTime: {
1859 aggregate: false,
1860 average: false,
1861 median: false
1862 },
5df69fab
JB
1863 elu: {
1864 aggregate: false,
1865 average: false,
1866 median: false
1867 }
e52fb978
JB
1868 })
1869 await pool.destroy()
1870 pool = new DynamicThreadPool(
1871 min,
1872 max,
1873 './tests/worker-files/thread/testWorker.js',
1874 { workerChoiceStrategy }
1875 )
87de9ff5
JB
1876 expect(
1877 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
1878 ).toStrictEqual({
932fc8be 1879 runTime: {
619f403b
JB
1880 aggregate: true,
1881 average: true,
932fc8be
JB
1882 median: false
1883 },
1884 waitTime: {
1885 aggregate: false,
1886 average: false,
1887 median: false
1888 },
5df69fab
JB
1889 elu: {
1890 aggregate: false,
1891 average: false,
1892 median: false
1893 }
e52fb978
JB
1894 })
1895 // We need to clean up the resources after our test
1896 await pool.destroy()
1897 })
1898
e62e7646
JB
1899 it('Verify INTERLEAVED_WEIGHTED_ROUND_ROBIN strategy can be run in a fixed pool', async () => {
1900 const pool = new FixedThreadPool(
1901 max,
1902 './tests/worker-files/thread/testWorker.js',
1903 {
1904 workerChoiceStrategy:
1905 WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
1906 }
1907 )
1908 // TODO: Create a better test to cover `InterleavedWeightedRoundRobinWorkerChoiceStrategy#choose`
1909 const promises = new Set()
1910 const maxMultiplier = 2
1911 for (let i = 0; i < max * maxMultiplier; i++) {
1912 promises.add(pool.execute())
1913 }
1914 await Promise.all(promises)
1915 for (const workerNode of pool.workerNodes) {
465b2940 1916 expect(workerNode.usage).toStrictEqual({
a4e07f72 1917 tasks: {
619f403b 1918 executed: expect.any(Number),
a4e07f72
JB
1919 executing: 0,
1920 queued: 0,
df593701 1921 maxQueued: 0,
68cbdc84 1922 stolen: 0,
a4e07f72
JB
1923 failed: 0
1924 },
619f403b
JB
1925 runTime: expect.objectContaining({
1926 history: expect.any(CircularArray)
1927 }),
a4e07f72 1928 waitTime: {
4ba4c7f9 1929 history: new CircularArray()
a4e07f72 1930 },
5df69fab
JB
1931 elu: {
1932 idle: {
4ba4c7f9 1933 history: new CircularArray()
5df69fab
JB
1934 },
1935 active: {
4ba4c7f9 1936 history: new CircularArray()
71514351 1937 }
5df69fab 1938 }
e62e7646 1939 })
619f403b
JB
1940 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
1941 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
1942 max * maxMultiplier
1943 )
e62e7646
JB
1944 }
1945 expect(
1946 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1947 pool.workerChoiceStrategyContext.workerChoiceStrategy
1948 ).defaultWorkerWeight
1949 ).toBeGreaterThan(0)
1950 expect(
1951 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1952 pool.workerChoiceStrategyContext.workerChoiceStrategy
d33be430 1953 ).roundId
e62e7646 1954 ).toBe(0)
619f403b
JB
1955 expect(
1956 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1957 pool.workerChoiceStrategyContext.workerChoiceStrategy
1958 ).workerNodeId
1959 ).toBe(0)
e62e7646
JB
1960 expect(
1961 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1962 pool.workerChoiceStrategyContext.workerChoiceStrategy
9b106837 1963 ).nextWorkerNodeKey
e62e7646 1964 ).toBe(0)
086fd843
JB
1965 expect(
1966 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1967 pool.workerChoiceStrategyContext.workerChoiceStrategy
1968 ).previousWorkerNodeKey
1969 ).toEqual(expect.any(Number))
e62e7646
JB
1970 expect(
1971 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1972 pool.workerChoiceStrategyContext.workerChoiceStrategy
1973 ).roundWeights
1974 ).toStrictEqual([
1975 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1976 pool.workerChoiceStrategyContext.workerChoiceStrategy
1977 ).defaultWorkerWeight
1978 ])
1979 // We need to clean up the resources after our test
1980 await pool.destroy()
1981 })
1982
1983 it('Verify INTERLEAVED_WEIGHTED_ROUND_ROBIN strategy can be run in a dynamic pool', async () => {
1984 const pool = new DynamicThreadPool(
1985 min,
1986 max,
1987 './tests/worker-files/thread/testWorker.js',
1988 {
1989 workerChoiceStrategy:
1990 WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
1991 }
1992 )
1993 // TODO: Create a better test to cover `InterleavedWeightedRoundRobinWorkerChoiceStrategy#choose`
1994 const promises = new Set()
1995 const maxMultiplier = 2
1996 for (let i = 0; i < max * maxMultiplier; i++) {
1997 promises.add(pool.execute())
1998 }
1999 await Promise.all(promises)
2000 for (const workerNode of pool.workerNodes) {
465b2940 2001 expect(workerNode.usage).toStrictEqual({
a4e07f72 2002 tasks: {
b1aae695 2003 executed: expect.any(Number),
a4e07f72
JB
2004 executing: 0,
2005 queued: 0,
df593701 2006 maxQueued: 0,
68cbdc84 2007 stolen: 0,
a4e07f72
JB
2008 failed: 0
2009 },
619f403b
JB
2010 runTime: expect.objectContaining({
2011 history: expect.any(CircularArray)
2012 }),
a4e07f72 2013 waitTime: {
4ba4c7f9 2014 history: new CircularArray()
a4e07f72 2015 },
5df69fab
JB
2016 elu: {
2017 idle: {
4ba4c7f9 2018 history: new CircularArray()
5df69fab
JB
2019 },
2020 active: {
4ba4c7f9 2021 history: new CircularArray()
71514351 2022 }
5df69fab 2023 }
e62e7646 2024 })
e43b8c2d
JB
2025 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
2026 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
2027 max * maxMultiplier
2028 )
e62e7646
JB
2029 }
2030 expect(
2031 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2032 pool.workerChoiceStrategyContext.workerChoiceStrategy
2033 ).defaultWorkerWeight
2034 ).toBeGreaterThan(0)
2035 expect(
2036 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2037 pool.workerChoiceStrategyContext.workerChoiceStrategy
d33be430 2038 ).roundId
e62e7646 2039 ).toBe(0)
619f403b
JB
2040 expect(
2041 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2042 pool.workerChoiceStrategyContext.workerChoiceStrategy
2043 ).workerNodeId
2044 ).toBe(0)
e62e7646
JB
2045 expect(
2046 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2047 pool.workerChoiceStrategyContext.workerChoiceStrategy
9b106837 2048 ).nextWorkerNodeKey
d2c73f82 2049 ).toBe(0)
086fd843
JB
2050 expect(
2051 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2052 pool.workerChoiceStrategyContext.workerChoiceStrategy
2053 ).previousWorkerNodeKey
2054 ).toEqual(expect.any(Number))
e62e7646
JB
2055 expect(
2056 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2057 pool.workerChoiceStrategyContext.workerChoiceStrategy
2058 ).roundWeights
2059 ).toStrictEqual([
2060 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2061 pool.workerChoiceStrategyContext.workerChoiceStrategy
2062 ).defaultWorkerWeight
2063 ])
2064 // We need to clean up the resources after our test
2065 await pool.destroy()
2066 })
2067
8c3ec188
JB
2068 it('Verify INTERLEAVED_WEIGHTED_ROUND_ROBIN strategy internals are resets after setting it', async () => {
2069 const workerChoiceStrategy =
2070 WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
2071 let pool = new FixedThreadPool(
2072 max,
2073 './tests/worker-files/thread/testWorker.js'
2074 )
2075 expect(
2076 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2077 workerChoiceStrategy
d33be430 2078 ).roundId
8c3ec188 2079 ).toBeDefined()
086fd843
JB
2080 expect(
2081 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2082 workerChoiceStrategy
2083 ).workerNodeId
2084 ).toBeDefined()
8c3ec188
JB
2085 expect(
2086 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2087 workerChoiceStrategy
9b106837 2088 ).nextWorkerNodeKey
8c3ec188 2089 ).toBeDefined()
086fd843
JB
2090 expect(
2091 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2092 workerChoiceStrategy
2093 ).previousWorkerNodeKey
2094 ).toBeDefined()
8c3ec188
JB
2095 expect(
2096 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2097 workerChoiceStrategy
2098 ).defaultWorkerWeight
2099 ).toBeDefined()
2100 expect(
2101 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2102 workerChoiceStrategy
2103 ).roundWeights
2104 ).toBeDefined()
2105 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
2106 expect(
2107 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
086fd843 2108 pool.workerChoiceStrategyContext.workerChoiceStrategy
d33be430 2109 ).roundId
8c3ec188 2110 ).toBe(0)
086fd843
JB
2111 expect(
2112 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2113 pool.workerChoiceStrategyContext.workerChoiceStrategy
2114 ).workerNodeId
2115 ).toBe(0)
8c3ec188
JB
2116 expect(
2117 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2118 pool.workerChoiceStrategyContext.workerChoiceStrategy
9b106837 2119 ).nextWorkerNodeKey
8c3ec188 2120 ).toBe(0)
086fd843
JB
2121 expect(
2122 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2123 pool.workerChoiceStrategyContext.workerChoiceStrategy
2124 ).previousWorkerNodeKey
2125 ).toBe(0)
8c3ec188
JB
2126 expect(
2127 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2128 pool.workerChoiceStrategyContext.workerChoiceStrategy
2129 ).defaultWorkerWeight
2130 ).toBeGreaterThan(0)
2131 expect(
2132 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
086fd843 2133 pool.workerChoiceStrategyContext.workerChoiceStrategy
8c3ec188
JB
2134 ).roundWeights
2135 ).toStrictEqual([
2136 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2137 pool.workerChoiceStrategyContext.workerChoiceStrategy
2138 ).defaultWorkerWeight
2139 ])
2140 await pool.destroy()
2141 pool = new DynamicThreadPool(
2142 min,
2143 max,
2144 './tests/worker-files/thread/testWorker.js'
2145 )
2146 expect(
2147 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2148 workerChoiceStrategy
d33be430 2149 ).roundId
8c3ec188 2150 ).toBeDefined()
086fd843
JB
2151 expect(
2152 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2153 workerChoiceStrategy
2154 ).workerNodeId
2155 ).toBeDefined()
8c3ec188
JB
2156 expect(
2157 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2158 workerChoiceStrategy
9b106837 2159 ).nextWorkerNodeKey
8c3ec188 2160 ).toBeDefined()
086fd843
JB
2161 expect(
2162 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2163 workerChoiceStrategy
2164 ).previousWorkerNodeKey
2165 ).toBeDefined()
8c3ec188
JB
2166 expect(
2167 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2168 workerChoiceStrategy
2169 ).defaultWorkerWeight
2170 ).toBeDefined()
2171 expect(
2172 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2173 workerChoiceStrategy
2174 ).roundWeights
2175 ).toBeDefined()
2176 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
086fd843
JB
2177 expect(
2178 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2179 pool.workerChoiceStrategyContext.workerChoiceStrategy
2180 ).roundId
2181 ).toBe(0)
2182 expect(
2183 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2184 pool.workerChoiceStrategyContext.workerChoiceStrategy
2185 ).workerNodeId
2186 ).toBe(0)
8c3ec188
JB
2187 expect(
2188 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2189 pool.workerChoiceStrategyContext.workerChoiceStrategy
9b106837 2190 ).nextWorkerNodeKey
8c3ec188 2191 ).toBe(0)
086fd843
JB
2192 expect(
2193 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2194 pool.workerChoiceStrategyContext.workerChoiceStrategy
2195 ).previousWorkerNodeKey
2196 ).toBe(0)
8c3ec188
JB
2197 expect(
2198 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2199 pool.workerChoiceStrategyContext.workerChoiceStrategy
2200 ).defaultWorkerWeight
2201 ).toBeGreaterThan(0)
2202 expect(
2203 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
086fd843 2204 pool.workerChoiceStrategyContext.workerChoiceStrategy
8c3ec188
JB
2205 ).roundWeights
2206 ).toStrictEqual([
2207 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2208 pool.workerChoiceStrategyContext.workerChoiceStrategy
2209 ).defaultWorkerWeight
2210 ])
2211 // We need to clean up the resources after our test
2212 await pool.destroy()
2213 })
2214
89b09b26 2215 it('Verify unknown strategy throw error', () => {
a35560ba
S
2216 expect(
2217 () =>
2218 new DynamicThreadPool(
2219 min,
2220 max,
2221 './tests/worker-files/thread/testWorker.js',
1927ee67 2222 { workerChoiceStrategy: 'UNKNOWN_STRATEGY' }
a35560ba 2223 )
d4aeae5a 2224 ).toThrowError("Invalid worker choice strategy 'UNKNOWN_STRATEGY'")
a35560ba
S
2225 })
2226})