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