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