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