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