test: add least ELU tests
[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({
86bf340d
JB
129 runTime: false,
130 avgRunTime: false,
131 medRunTime: false,
132 waitTime: false,
133 avgWaitTime: false,
d44d5953
JB
134 medWaitTime: false,
135 elu: false
86bf340d 136 })
fd7ebd49 137 await pool.destroy()
10fcfaf4
JB
138 pool = new DynamicThreadPool(
139 min,
140 max,
d710242d 141 './tests/worker-files/thread/testWorker.js',
594bfb84 142 { workerChoiceStrategy }
10fcfaf4 143 )
87de9ff5
JB
144 expect(
145 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
146 ).toStrictEqual({
86bf340d
JB
147 runTime: false,
148 avgRunTime: false,
149 medRunTime: false,
150 waitTime: false,
151 avgWaitTime: false,
d44d5953
JB
152 medWaitTime: false,
153 elu: false
86bf340d 154 })
10fcfaf4
JB
155 // We need to clean up the resources after our test
156 await pool.destroy()
157 })
158
bdaf31cd 159 it('Verify ROUND_ROBIN strategy can be run in a fixed pool', async () => {
bdaf31cd
JB
160 const pool = new FixedThreadPool(
161 max,
162 './tests/worker-files/thread/testWorker.js',
163 { workerChoiceStrategy: WorkerChoiceStrategies.ROUND_ROBIN }
164 )
bdaf31cd 165 // TODO: Create a better test to cover `RoundRobinWorkerChoiceStrategy#choose`
ee9f5295 166 const promises = new Set()
a20f0ba5
JB
167 const maxMultiplier = 2
168 for (let i = 0; i < max * maxMultiplier; i++) {
ee9f5295 169 promises.add(pool.execute())
e211bc18
JB
170 }
171 await Promise.all(promises)
172 for (const workerNode of pool.workerNodes) {
a4e07f72
JB
173 expect(workerNode.workerUsage).toStrictEqual({
174 tasks: {
175 executed: maxMultiplier,
176 executing: 0,
177 queued: 0,
178 failed: 0
179 },
180 runTime: {
181 aggregation: 0,
182 average: 0,
183 median: 0,
184 history: expect.any(CircularArray)
185 },
186 waitTime: {
187 aggregation: 0,
188 average: 0,
189 median: 0,
190 history: expect.any(CircularArray)
191 },
d44d5953 192 elu: undefined
e211bc18 193 })
bdaf31cd 194 }
9458090a
JB
195 expect(
196 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
197 WorkerChoiceStrategies.ROUND_ROBIN
198 ).nextWorkerNodeId
199 ).toBe(0)
bdaf31cd
JB
200 // We need to clean up the resources after our test
201 await pool.destroy()
202 })
203
204 it('Verify ROUND_ROBIN strategy can be run in a dynamic pool', async () => {
bdaf31cd
JB
205 const pool = new DynamicThreadPool(
206 min,
207 max,
208 './tests/worker-files/thread/testWorker.js',
209 { workerChoiceStrategy: WorkerChoiceStrategies.ROUND_ROBIN }
210 )
bdaf31cd 211 // TODO: Create a better test to cover `RoundRobinWorkerChoiceStrategy#choose`
ee9f5295 212 const promises = new Set()
a20f0ba5
JB
213 const maxMultiplier = 2
214 for (let i = 0; i < max * maxMultiplier; i++) {
ee9f5295 215 promises.add(pool.execute())
e211bc18
JB
216 }
217 await Promise.all(promises)
218 for (const workerNode of pool.workerNodes) {
a4e07f72
JB
219 expect(workerNode.workerUsage).toStrictEqual({
220 tasks: {
221 executed: maxMultiplier,
222 executing: 0,
223 queued: 0,
224 failed: 0
225 },
226 runTime: {
227 aggregation: 0,
228 average: 0,
229 median: 0,
230 history: expect.any(CircularArray)
231 },
232 waitTime: {
233 aggregation: 0,
234 average: 0,
235 median: 0,
236 history: expect.any(CircularArray)
237 },
d44d5953 238 elu: undefined
e211bc18 239 })
bdaf31cd 240 }
9458090a
JB
241 expect(
242 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
243 WorkerChoiceStrategies.ROUND_ROBIN
244 ).nextWorkerNodeId
245 ).toBe(0)
bdaf31cd
JB
246 // We need to clean up the resources after our test
247 await pool.destroy()
248 })
249
2ced693a 250 it('Verify ROUND_ROBIN strategy runtime behavior', async () => {
594bfb84 251 const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN
2ced693a
JB
252 let pool = new FixedClusterPool(
253 max,
594bfb84
JB
254 './tests/worker-files/cluster/testWorker.js',
255 { workerChoiceStrategy }
2ced693a
JB
256 )
257 let results = new Set()
258 for (let i = 0; i < max; i++) {
20dcad1a 259 results.add(pool.workerNodes[pool.chooseWorkerNode()].worker.id)
2ced693a
JB
260 }
261 expect(results.size).toBe(max)
262 await pool.destroy()
594bfb84
JB
263 pool = new FixedThreadPool(
264 max,
265 './tests/worker-files/thread/testWorker.js',
266 { workerChoiceStrategy }
267 )
2ced693a
JB
268 results = new Set()
269 for (let i = 0; i < max; i++) {
20dcad1a 270 results.add(pool.workerNodes[pool.chooseWorkerNode()].worker.threadId)
2ced693a
JB
271 }
272 expect(results.size).toBe(max)
273 await pool.destroy()
274 })
275
a6f7f1b4 276 it('Verify ROUND_ROBIN strategy internals are resets after setting it', async () => {
594bfb84 277 const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN
a6f7f1b4
JB
278 let pool = new FixedThreadPool(
279 max,
280 './tests/worker-files/thread/testWorker.js',
281 { workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN }
282 )
38f6e859 283 expect(
95c83464 284 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 285 workerChoiceStrategy
f06e48d8 286 ).nextWorkerNodeId
b529c323 287 ).toBeDefined()
594bfb84 288 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
a6f7f1b4 289 expect(
95c83464 290 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
d710242d 291 pool.workerChoiceStrategyContext.workerChoiceStrategy
f06e48d8 292 ).nextWorkerNodeId
a6f7f1b4
JB
293 ).toBe(0)
294 await pool.destroy()
295 pool = new DynamicThreadPool(
296 min,
297 max,
298 './tests/worker-files/thread/testWorker.js',
299 { workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN }
300 )
38f6e859 301 expect(
95c83464 302 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 303 workerChoiceStrategy
f06e48d8 304 ).nextWorkerNodeId
b529c323 305 ).toBeDefined()
594bfb84 306 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
a6f7f1b4 307 expect(
95c83464 308 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
d710242d 309 pool.workerChoiceStrategyContext.workerChoiceStrategy
f06e48d8 310 ).nextWorkerNodeId
a6f7f1b4
JB
311 ).toBe(0)
312 // We need to clean up the resources after our test
313 await pool.destroy()
314 })
315
e4543b14
JB
316 it('Verify LEAST_USED strategy default tasks usage statistics requirements', async () => {
317 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_USED
10fcfaf4
JB
318 let pool = new FixedThreadPool(
319 max,
d710242d 320 './tests/worker-files/thread/testWorker.js',
594bfb84 321 { workerChoiceStrategy }
10fcfaf4 322 )
87de9ff5
JB
323 expect(
324 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
325 ).toStrictEqual({
86bf340d
JB
326 runTime: false,
327 avgRunTime: false,
328 medRunTime: false,
329 waitTime: false,
330 avgWaitTime: false,
d44d5953
JB
331 medWaitTime: false,
332 elu: false
86bf340d 333 })
fd7ebd49 334 await pool.destroy()
10fcfaf4
JB
335 pool = new DynamicThreadPool(
336 min,
337 max,
d710242d 338 './tests/worker-files/thread/testWorker.js',
594bfb84 339 { workerChoiceStrategy }
10fcfaf4 340 )
87de9ff5
JB
341 expect(
342 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
343 ).toStrictEqual({
86bf340d
JB
344 runTime: false,
345 avgRunTime: false,
346 medRunTime: false,
347 waitTime: false,
348 avgWaitTime: false,
d44d5953
JB
349 medWaitTime: false,
350 elu: false
86bf340d 351 })
10fcfaf4
JB
352 // We need to clean up the resources after our test
353 await pool.destroy()
354 })
355
e4543b14 356 it('Verify LEAST_USED strategy can be run in a fixed pool', async () => {
b98ec2e6
JB
357 const pool = new FixedThreadPool(
358 max,
359 './tests/worker-files/thread/testWorker.js',
e4543b14 360 { workerChoiceStrategy: WorkerChoiceStrategies.LEAST_USED }
b98ec2e6 361 )
e4543b14 362 // TODO: Create a better test to cover `LeastUsedWorkerChoiceStrategy#choose`
ee9f5295 363 const promises = new Set()
a20f0ba5
JB
364 const maxMultiplier = 2
365 for (let i = 0; i < max * maxMultiplier; i++) {
ee9f5295 366 promises.add(pool.execute())
e211bc18
JB
367 }
368 await Promise.all(promises)
369 for (const workerNode of pool.workerNodes) {
a4e07f72
JB
370 expect(workerNode.workerUsage).toStrictEqual({
371 tasks: {
372 executed: maxMultiplier,
373 executing: 0,
374 queued: 0,
375 failed: 0
376 },
377 runTime: {
378 aggregation: 0,
379 average: 0,
380 median: 0,
381 history: expect.any(CircularArray)
382 },
383 waitTime: {
384 aggregation: 0,
385 average: 0,
386 median: 0,
387 history: expect.any(CircularArray)
388 },
d44d5953 389 elu: undefined
e211bc18 390 })
a35560ba 391 }
a35560ba
S
392 // We need to clean up the resources after our test
393 await pool.destroy()
394 })
395
e4543b14 396 it('Verify LEAST_USED strategy can be run in a dynamic pool', async () => {
ff5e76e1
JB
397 const pool = new DynamicThreadPool(
398 min,
399 max,
400 './tests/worker-files/thread/testWorker.js',
e4543b14 401 { workerChoiceStrategy: WorkerChoiceStrategies.LEAST_USED }
ff5e76e1 402 )
e4543b14 403 // TODO: Create a better test to cover `LeastUsedWorkerChoiceStrategy#choose`
ee9f5295 404 const promises = new Set()
a20f0ba5
JB
405 const maxMultiplier = 2
406 for (let i = 0; i < max * maxMultiplier; i++) {
ee9f5295 407 promises.add(pool.execute())
e211bc18
JB
408 }
409 await Promise.all(promises)
410 for (const workerNode of pool.workerNodes) {
a4e07f72
JB
411 expect(workerNode.workerUsage).toStrictEqual({
412 tasks: {
413 executed: maxMultiplier,
414 executing: 0,
415 queued: 0,
416 failed: 0
417 },
418 runTime: {
419 aggregation: 0,
420 average: 0,
421 median: 0,
422 history: expect.any(CircularArray)
423 },
424 waitTime: {
425 aggregation: 0,
426 average: 0,
427 median: 0,
428 history: expect.any(CircularArray)
429 },
430
d44d5953 431 elu: undefined
e211bc18 432 })
168c526f 433 }
168c526f
JB
434 // We need to clean up the resources after our test
435 await pool.destroy()
436 })
437
e4543b14
JB
438 it('Verify LEAST_BUSY strategy default tasks usage statistics requirements', async () => {
439 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_BUSY
168c526f
JB
440 let pool = new FixedThreadPool(
441 max,
d710242d 442 './tests/worker-files/thread/testWorker.js',
594bfb84 443 { workerChoiceStrategy }
168c526f 444 )
87de9ff5
JB
445 expect(
446 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
447 ).toStrictEqual({
86bf340d
JB
448 runTime: true,
449 avgRunTime: false,
450 medRunTime: false,
1c6fe997 451 waitTime: true,
86bf340d 452 avgWaitTime: false,
d44d5953
JB
453 medWaitTime: false,
454 elu: false
86bf340d 455 })
168c526f
JB
456 await pool.destroy()
457 pool = new DynamicThreadPool(
458 min,
459 max,
d710242d 460 './tests/worker-files/thread/testWorker.js',
594bfb84 461 { workerChoiceStrategy }
168c526f 462 )
87de9ff5
JB
463 expect(
464 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
465 ).toStrictEqual({
86bf340d
JB
466 runTime: true,
467 avgRunTime: false,
468 medRunTime: false,
1c6fe997 469 waitTime: true,
86bf340d 470 avgWaitTime: false,
d44d5953
JB
471 medWaitTime: false,
472 elu: false
86bf340d 473 })
168c526f
JB
474 // We need to clean up the resources after our test
475 await pool.destroy()
476 })
477
e4543b14 478 it('Verify LEAST_BUSY strategy can be run in a fixed pool', async () => {
168c526f
JB
479 const pool = new FixedThreadPool(
480 max,
481 './tests/worker-files/thread/testWorker.js',
e4543b14 482 { workerChoiceStrategy: WorkerChoiceStrategies.LEAST_BUSY }
168c526f 483 )
e4543b14 484 // TODO: Create a better test to cover `LeastBusyWorkerChoiceStrategy#choose`
ee9f5295 485 const promises = new Set()
a20f0ba5
JB
486 const maxMultiplier = 2
487 for (let i = 0; i < max * maxMultiplier; i++) {
ee9f5295 488 promises.add(pool.execute())
e211bc18
JB
489 }
490 await Promise.all(promises)
491 for (const workerNode of pool.workerNodes) {
a4e07f72
JB
492 expect(workerNode.workerUsage).toStrictEqual({
493 tasks: {
494 executed: expect.any(Number),
495 executing: 0,
496 queued: 0,
497 failed: 0
498 },
499 runTime: {
500 aggregation: expect.any(Number),
501 average: 0,
502 median: 0,
503 history: expect.any(CircularArray)
504 },
505 waitTime: {
1c6fe997 506 aggregation: expect.any(Number),
a4e07f72
JB
507 average: 0,
508 median: 0,
509 history: expect.any(CircularArray)
510 },
d44d5953 511 elu: undefined
e211bc18 512 })
a4e07f72
JB
513 expect(workerNode.workerUsage.tasks.executed).toBeGreaterThanOrEqual(0)
514 expect(workerNode.workerUsage.tasks.executed).toBeLessThanOrEqual(
515 max * maxMultiplier
516 )
517 expect(workerNode.workerUsage.runTime.aggregation).toBeGreaterThanOrEqual(
518 0
519 )
1c6fe997
JB
520 expect(
521 workerNode.workerUsage.waitTime.aggregation
522 ).toBeGreaterThanOrEqual(0)
168c526f 523 }
168c526f
JB
524 // We need to clean up the resources after our test
525 await pool.destroy()
526 })
527
e4543b14 528 it('Verify LEAST_BUSY strategy can be run in a dynamic pool', async () => {
168c526f
JB
529 const pool = new DynamicThreadPool(
530 min,
531 max,
532 './tests/worker-files/thread/testWorker.js',
e4543b14 533 { workerChoiceStrategy: WorkerChoiceStrategies.LEAST_BUSY }
168c526f 534 )
e4543b14 535 // TODO: Create a better test to cover `LeastBusyWorkerChoiceStrategy#choose`
ee9f5295 536 const promises = new Set()
a20f0ba5
JB
537 const maxMultiplier = 2
538 for (let i = 0; i < max * maxMultiplier; i++) {
ee9f5295 539 promises.add(pool.execute())
e211bc18
JB
540 }
541 await Promise.all(promises)
542 for (const workerNode of pool.workerNodes) {
a4e07f72
JB
543 expect(workerNode.workerUsage).toStrictEqual({
544 tasks: {
545 executed: expect.any(Number),
546 executing: 0,
547 queued: 0,
548 failed: 0
549 },
550 runTime: {
551 aggregation: expect.any(Number),
552 average: 0,
553 median: 0,
554 history: expect.any(CircularArray)
555 },
556 waitTime: {
1c6fe997 557 aggregation: expect.any(Number),
a4e07f72
JB
558 average: 0,
559 median: 0,
560 history: expect.any(CircularArray)
561 },
d44d5953 562 elu: undefined
e211bc18 563 })
a4e07f72
JB
564 expect(workerNode.workerUsage.tasks.executed).toBeGreaterThan(0)
565 expect(workerNode.workerUsage.tasks.executed).toBeLessThanOrEqual(
566 max * maxMultiplier
567 )
568 expect(workerNode.workerUsage.runTime.aggregation).toBeGreaterThan(0)
1c6fe997 569 expect(workerNode.workerUsage.waitTime.aggregation).toBeGreaterThan(0)
ff5e76e1 570 }
ff5e76e1
JB
571 // We need to clean up the resources after our test
572 await pool.destroy()
573 })
574
a7bbf44a
JB
575 it('Verify LEAST_ELU strategy default tasks usage statistics requirements', async () => {
576 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_ELU
577 let pool = new FixedThreadPool(
578 max,
579 './tests/worker-files/thread/testWorker.js',
580 { workerChoiceStrategy }
581 )
05302647
JB
582 expect(
583 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
584 ).toStrictEqual({
a7bbf44a
JB
585 runTime: false,
586 avgRunTime: false,
587 medRunTime: false,
588 waitTime: false,
589 avgWaitTime: false,
590 medWaitTime: false,
591 elu: true
592 })
593 await pool.destroy()
594 pool = new DynamicThreadPool(
595 min,
596 max,
597 './tests/worker-files/thread/testWorker.js',
598 { workerChoiceStrategy }
599 )
05302647
JB
600 expect(
601 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
602 ).toStrictEqual({
a7bbf44a
JB
603 runTime: false,
604 avgRunTime: false,
605 medRunTime: false,
606 waitTime: false,
607 avgWaitTime: false,
608 medWaitTime: false,
609 elu: true
610 })
611 // We need to clean up the resources after our test
612 await pool.destroy()
613 })
614
ae9cf3c8 615 it('Verify LEAST_ELU strategy can be run in a fixed pool', async () => {
c5ad42cd
JB
616 const pool = new FixedThreadPool(
617 max,
618 './tests/worker-files/thread/testWorker.js',
619 { workerChoiceStrategy: WorkerChoiceStrategies.LEAST_ELU }
620 )
621 // TODO: Create a better test to cover `LeastEluWorkerChoiceStrategy#choose`
c5ad42cd
JB
622 const maxMultiplier = 2
623 for (let i = 0; i < max * maxMultiplier; i++) {
a1c82d5d
JB
624 await pool.execute()
625 if (i !== max * maxMultiplier - 1) await TestUtils.sleep(500)
c5ad42cd 626 }
c5ad42cd
JB
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})