fix: ensure worker choice is retried at least the pool max size
[poolifier.git] / tests / pools / selection-strategies / selection-strategies.test.mjs
CommitLineData
a074ffee
JB
1import { expect } from 'expect'
2import {
999ef664 3 DynamicClusterPool,
a35560ba 4 DynamicThreadPool,
3d6dd312 5 FixedClusterPool,
2ced693a 6 FixedThreadPool,
3d6dd312 7 WorkerChoiceStrategies
a074ffee
JB
8} from '../../../lib/index.js'
9import { CircularArray } from '../../../lib/circular-array.js'
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,
b2fd3f4a 33 './tests/worker-files/thread/testWorker.mjs'
e843b904
JB
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,
b2fd3f4a 46 './tests/worker-files/thread/testWorker.mjs',
594bfb84
JB
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,
b2fd3f4a 62 './tests/worker-files/thread/testWorker.mjs'
594bfb84
JB
63 )
64 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
65 expect(pool.opts.workerChoiceStrategy).toBe(workerChoiceStrategy)
66 expect(pool.workerChoiceStrategyContext.workerChoiceStrategy).toBe(
67 workerChoiceStrategy
68 )
26ce26ca 69 expect(pool.opts.workerChoiceStrategyOptions).toBeUndefined()
999ef664 70 expect(pool.workerChoiceStrategyContext.opts).toStrictEqual({
26ce26ca 71 retries: pool.info.maxSize,
999ef664
JB
72 runTime: { median: false },
73 waitTime: { median: false },
74 elu: { median: false }
75 })
76 await pool.destroy()
77 }
78 for (const workerChoiceStrategy of Object.values(WorkerChoiceStrategies)) {
79 const pool = new DynamicClusterPool(
80 min,
81 max,
82 './tests/worker-files/cluster/testWorker.js'
83 )
26ce26ca 84 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
999ef664
JB
85 expect(pool.opts.workerChoiceStrategy).toBe(workerChoiceStrategy)
86 expect(pool.workerChoiceStrategyContext.workerChoiceStrategy).toBe(
87 workerChoiceStrategy
88 )
26ce26ca 89 expect(pool.opts.workerChoiceStrategyOptions).toBeUndefined()
999ef664 90 expect(pool.workerChoiceStrategyContext.opts).toStrictEqual({
26ce26ca 91 retries: pool.info.maxSize,
999ef664
JB
92 runTime: { median: false },
93 waitTime: { median: false },
94 elu: { median: false }
95 })
594bfb84
JB
96 await pool.destroy()
97 }
98 })
99
100 it('Verify available strategies default internals at pool creation', async () => {
101 const pool = new FixedThreadPool(
e843b904 102 max,
b2fd3f4a 103 './tests/worker-files/thread/testWorker.mjs'
e843b904 104 )
594bfb84 105 for (const workerChoiceStrategy of Object.values(WorkerChoiceStrategies)) {
54f4e726
JB
106 expect(
107 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
108 workerChoiceStrategy
109 ).nextWorkerNodeKey
110 ).toBe(0)
111 expect(
112 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
113 workerChoiceStrategy
114 ).previousWorkerNodeKey
115 ).toBe(0)
f3a91bac 116 if (
594bfb84
JB
117 workerChoiceStrategy === WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
118 ) {
119 expect(
120 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
121 workerChoiceStrategy
54f4e726
JB
122 ).defaultWorkerWeight
123 ).toBeGreaterThan(0)
124 expect(
125 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
126 workerChoiceStrategy
f3a91bac 127 ).workerNodeVirtualTaskRunTime
594bfb84 128 ).toBe(0)
54f4e726
JB
129 } else if (
130 workerChoiceStrategy ===
131 WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
132 ) {
594bfb84
JB
133 expect(
134 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
135 workerChoiceStrategy
136 ).defaultWorkerWeight
137 ).toBeGreaterThan(0)
08f3f44c
JB
138 expect(
139 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
140 workerChoiceStrategy
f3a91bac 141 ).workerNodeVirtualTaskRunTime
08f3f44c 142 ).toBe(0)
54f4e726
JB
143 expect(
144 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
145 workerChoiceStrategy
146 ).roundId
147 ).toBe(0)
148 expect(
149 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
150 workerChoiceStrategy
151 ).workerNodeId
152 ).toBe(0)
153 expect(
154 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
155 workerChoiceStrategy
156 ).roundWeights
157 ).toStrictEqual([
158 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
159 workerChoiceStrategy
160 ).defaultWorkerWeight
161 ])
594bfb84
JB
162 }
163 }
e843b904
JB
164 await pool.destroy()
165 })
166
722d55a0
JB
167 it('Verify strategies wait for worker node readiness in dynamic pool', async () => {
168 const pool = new DynamicThreadPool(
169 min,
170 max,
171 './tests/worker-files/thread/testWorker.mjs'
172 )
722d55a0
JB
173 expect(pool.starting).toBe(false)
174 expect(pool.workerNodes.length).toBe(min)
175 const maxMultiplier = 10000
176 const promises = new Set()
177 for (let i = 0; i < max * maxMultiplier; i++) {
178 promises.add(pool.execute())
179 }
180 await Promise.all(promises)
181 expect(pool.workerNodes.length).toBe(max)
182 // We need to clean up the resources after our test
183 await pool.destroy()
184 })
185
6c6afb84
JB
186 it('Verify ROUND_ROBIN strategy default policy', async () => {
187 const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN
188 let pool = new FixedThreadPool(
189 max,
b2fd3f4a 190 './tests/worker-files/thread/testWorker.mjs',
6c6afb84
JB
191 { workerChoiceStrategy }
192 )
193 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
94407def 194 dynamicWorkerUsage: false,
b1aae695 195 dynamicWorkerReady: true
6c6afb84
JB
196 })
197 await pool.destroy()
198 pool = new DynamicThreadPool(
199 min,
200 max,
b2fd3f4a 201 './tests/worker-files/thread/testWorker.mjs',
6c6afb84
JB
202 { workerChoiceStrategy }
203 )
204 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
94407def 205 dynamicWorkerUsage: false,
b1aae695 206 dynamicWorkerReady: true
6c6afb84
JB
207 })
208 // We need to clean up the resources after our test
209 await pool.destroy()
210 })
211
212 it('Verify ROUND_ROBIN strategy default tasks statistics requirements', async () => {
594bfb84 213 const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN
10fcfaf4
JB
214 let pool = new FixedThreadPool(
215 max,
b2fd3f4a 216 './tests/worker-files/thread/testWorker.mjs',
594bfb84 217 { workerChoiceStrategy }
10fcfaf4 218 )
87de9ff5
JB
219 expect(
220 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
221 ).toStrictEqual({
932fc8be
JB
222 runTime: {
223 aggregate: false,
224 average: false,
225 median: false
226 },
227 waitTime: {
228 aggregate: false,
229 average: false,
230 median: false
231 },
5df69fab
JB
232 elu: {
233 aggregate: false,
234 average: false,
235 median: false
236 }
86bf340d 237 })
fd7ebd49 238 await pool.destroy()
10fcfaf4
JB
239 pool = new DynamicThreadPool(
240 min,
241 max,
b2fd3f4a 242 './tests/worker-files/thread/testWorker.mjs',
594bfb84 243 { workerChoiceStrategy }
10fcfaf4 244 )
87de9ff5
JB
245 expect(
246 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
247 ).toStrictEqual({
932fc8be
JB
248 runTime: {
249 aggregate: false,
250 average: false,
251 median: false
252 },
253 waitTime: {
254 aggregate: false,
255 average: false,
256 median: false
257 },
5df69fab
JB
258 elu: {
259 aggregate: false,
260 average: false,
261 median: false
262 }
86bf340d 263 })
10fcfaf4
JB
264 // We need to clean up the resources after our test
265 await pool.destroy()
266 })
267
bdaf31cd 268 it('Verify ROUND_ROBIN strategy can be run in a fixed pool', async () => {
516dcb0d 269 const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN
bdaf31cd
JB
270 const pool = new FixedThreadPool(
271 max,
b2fd3f4a 272 './tests/worker-files/thread/testWorker.mjs',
516dcb0d 273 { workerChoiceStrategy }
bdaf31cd 274 )
bdaf31cd 275 // TODO: Create a better test to cover `RoundRobinWorkerChoiceStrategy#choose`
ee9f5295 276 const promises = new Set()
a20f0ba5
JB
277 const maxMultiplier = 2
278 for (let i = 0; i < max * maxMultiplier; i++) {
ee9f5295 279 promises.add(pool.execute())
e211bc18
JB
280 }
281 await Promise.all(promises)
282 for (const workerNode of pool.workerNodes) {
465b2940 283 expect(workerNode.usage).toStrictEqual({
a4e07f72
JB
284 tasks: {
285 executed: maxMultiplier,
286 executing: 0,
287 queued: 0,
df593701 288 maxQueued: 0,
463226a4 289 sequentiallyStolen: 0,
5ad42e34 290 stolen: 0,
a4e07f72
JB
291 failed: 0
292 },
293 runTime: {
4ba4c7f9 294 history: new CircularArray()
a4e07f72
JB
295 },
296 waitTime: {
4ba4c7f9 297 history: new CircularArray()
a4e07f72 298 },
5df69fab
JB
299 elu: {
300 idle: {
4ba4c7f9 301 history: new CircularArray()
5df69fab
JB
302 },
303 active: {
4ba4c7f9 304 history: new CircularArray()
71514351 305 }
5df69fab 306 }
e211bc18 307 })
bdaf31cd 308 }
9458090a
JB
309 expect(
310 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
516dcb0d 311 pool.workerChoiceStrategyContext.workerChoiceStrategy
9b106837 312 ).nextWorkerNodeKey
9458090a 313 ).toBe(0)
086fd843
JB
314 expect(
315 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
516dcb0d 316 pool.workerChoiceStrategyContext.workerChoiceStrategy
086fd843
JB
317 ).previousWorkerNodeKey
318 ).toBe(pool.workerNodes.length - 1)
bdaf31cd
JB
319 // We need to clean up the resources after our test
320 await pool.destroy()
321 })
322
323 it('Verify ROUND_ROBIN strategy can be run in a dynamic pool', async () => {
516dcb0d 324 const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN
bdaf31cd
JB
325 const pool = new DynamicThreadPool(
326 min,
327 max,
b2fd3f4a 328 './tests/worker-files/thread/testWorker.mjs',
516dcb0d 329 { workerChoiceStrategy }
bdaf31cd 330 )
bdaf31cd 331 // TODO: Create a better test to cover `RoundRobinWorkerChoiceStrategy#choose`
ee9f5295 332 const promises = new Set()
a20f0ba5
JB
333 const maxMultiplier = 2
334 for (let i = 0; i < max * maxMultiplier; i++) {
ee9f5295 335 promises.add(pool.execute())
e211bc18
JB
336 }
337 await Promise.all(promises)
338 for (const workerNode of pool.workerNodes) {
465b2940 339 expect(workerNode.usage).toStrictEqual({
a4e07f72 340 tasks: {
94407def 341 executed: expect.any(Number),
a4e07f72
JB
342 executing: 0,
343 queued: 0,
df593701 344 maxQueued: 0,
463226a4 345 sequentiallyStolen: 0,
5ad42e34 346 stolen: 0,
a4e07f72
JB
347 failed: 0
348 },
349 runTime: {
4ba4c7f9 350 history: new CircularArray()
a4e07f72
JB
351 },
352 waitTime: {
4ba4c7f9 353 history: new CircularArray()
a4e07f72 354 },
5df69fab
JB
355 elu: {
356 idle: {
4ba4c7f9 357 history: new CircularArray()
5df69fab
JB
358 },
359 active: {
4ba4c7f9 360 history: new CircularArray()
71514351 361 }
5df69fab 362 }
e211bc18 363 })
94407def
JB
364 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
365 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
366 max * maxMultiplier
367 )
bdaf31cd 368 }
9458090a
JB
369 expect(
370 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
516dcb0d 371 pool.workerChoiceStrategyContext.workerChoiceStrategy
9b106837 372 ).nextWorkerNodeKey
9458090a 373 ).toBe(0)
086fd843
JB
374 expect(
375 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
516dcb0d 376 pool.workerChoiceStrategyContext.workerChoiceStrategy
086fd843
JB
377 ).previousWorkerNodeKey
378 ).toBe(pool.workerNodes.length - 1)
bdaf31cd
JB
379 // We need to clean up the resources after our test
380 await pool.destroy()
381 })
382
2ced693a 383 it('Verify ROUND_ROBIN strategy runtime behavior', async () => {
594bfb84 384 const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN
2ced693a
JB
385 let pool = new FixedClusterPool(
386 max,
594bfb84
JB
387 './tests/worker-files/cluster/testWorker.js',
388 { workerChoiceStrategy }
2ced693a
JB
389 )
390 let results = new Set()
391 for (let i = 0; i < max; i++) {
51a8af40 392 results.add(pool.workerNodes[pool.chooseWorkerNode()].info.id)
2ced693a
JB
393 }
394 expect(results.size).toBe(max)
395 await pool.destroy()
594bfb84
JB
396 pool = new FixedThreadPool(
397 max,
b2fd3f4a 398 './tests/worker-files/thread/testWorker.mjs',
594bfb84
JB
399 { workerChoiceStrategy }
400 )
2ced693a
JB
401 results = new Set()
402 for (let i = 0; i < max; i++) {
51a8af40 403 results.add(pool.workerNodes[pool.chooseWorkerNode()].info.id)
2ced693a
JB
404 }
405 expect(results.size).toBe(max)
406 await pool.destroy()
407 })
408
a6f7f1b4 409 it('Verify ROUND_ROBIN strategy internals are resets after setting it', async () => {
594bfb84 410 const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN
a6f7f1b4
JB
411 let pool = new FixedThreadPool(
412 max,
b2fd3f4a 413 './tests/worker-files/thread/testWorker.mjs',
a6f7f1b4
JB
414 { workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN }
415 )
86ed0598
JB
416 expect(
417 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
418 pool.workerChoiceStrategyContext.workerChoiceStrategy
419 ).nextWorkerNodeKey
420 ).toBeDefined()
421 expect(
422 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
423 pool.workerChoiceStrategyContext.workerChoiceStrategy
424 ).previousWorkerNodeKey
425 ).toBeDefined()
086fd843 426 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
38f6e859 427 expect(
95c83464 428 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
086fd843 429 pool.workerChoiceStrategyContext.workerChoiceStrategy
9b106837 430 ).nextWorkerNodeKey
086fd843 431 ).toBe(0)
a6f7f1b4 432 expect(
95c83464 433 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
d710242d 434 pool.workerChoiceStrategyContext.workerChoiceStrategy
086fd843 435 ).previousWorkerNodeKey
a6f7f1b4
JB
436 ).toBe(0)
437 await pool.destroy()
438 pool = new DynamicThreadPool(
439 min,
440 max,
b2fd3f4a 441 './tests/worker-files/thread/testWorker.mjs',
a6f7f1b4
JB
442 { workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN }
443 )
86ed0598
JB
444 expect(
445 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
446 pool.workerChoiceStrategyContext.workerChoiceStrategy
447 ).nextWorkerNodeKey
448 ).toBeDefined()
449 expect(
450 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
451 pool.workerChoiceStrategyContext.workerChoiceStrategy
452 ).previousWorkerNodeKey
453 ).toBeDefined()
086fd843 454 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
38f6e859 455 expect(
95c83464 456 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
086fd843 457 pool.workerChoiceStrategyContext.workerChoiceStrategy
9b106837 458 ).nextWorkerNodeKey
086fd843 459 ).toBe(0)
a6f7f1b4 460 expect(
95c83464 461 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
d710242d 462 pool.workerChoiceStrategyContext.workerChoiceStrategy
086fd843 463 ).previousWorkerNodeKey
a6f7f1b4
JB
464 ).toBe(0)
465 // We need to clean up the resources after our test
466 await pool.destroy()
467 })
468
6c6afb84
JB
469 it('Verify LEAST_USED strategy default policy', async () => {
470 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_USED
471 let pool = new FixedThreadPool(
472 max,
b2fd3f4a 473 './tests/worker-files/thread/testWorker.mjs',
6c6afb84
JB
474 { workerChoiceStrategy }
475 )
476 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
b1aae695
JB
477 dynamicWorkerUsage: false,
478 dynamicWorkerReady: true
6c6afb84
JB
479 })
480 await pool.destroy()
481 pool = new DynamicThreadPool(
482 min,
483 max,
b2fd3f4a 484 './tests/worker-files/thread/testWorker.mjs',
6c6afb84
JB
485 { workerChoiceStrategy }
486 )
487 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
b1aae695
JB
488 dynamicWorkerUsage: false,
489 dynamicWorkerReady: true
6c6afb84
JB
490 })
491 // We need to clean up the resources after our test
492 await pool.destroy()
493 })
494
495 it('Verify LEAST_USED strategy default tasks statistics requirements', async () => {
e4543b14 496 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_USED
10fcfaf4
JB
497 let pool = new FixedThreadPool(
498 max,
b2fd3f4a 499 './tests/worker-files/thread/testWorker.mjs',
594bfb84 500 { workerChoiceStrategy }
10fcfaf4 501 )
87de9ff5
JB
502 expect(
503 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
504 ).toStrictEqual({
932fc8be
JB
505 runTime: {
506 aggregate: false,
507 average: false,
508 median: false
509 },
510 waitTime: {
511 aggregate: false,
512 average: false,
513 median: false
514 },
5df69fab
JB
515 elu: {
516 aggregate: false,
517 average: false,
518 median: false
519 }
86bf340d 520 })
fd7ebd49 521 await pool.destroy()
10fcfaf4
JB
522 pool = new DynamicThreadPool(
523 min,
524 max,
b2fd3f4a 525 './tests/worker-files/thread/testWorker.mjs',
594bfb84 526 { workerChoiceStrategy }
10fcfaf4 527 )
87de9ff5
JB
528 expect(
529 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
530 ).toStrictEqual({
932fc8be
JB
531 runTime: {
532 aggregate: false,
533 average: false,
534 median: false
535 },
536 waitTime: {
537 aggregate: false,
538 average: false,
539 median: false
540 },
5df69fab
JB
541 elu: {
542 aggregate: false,
543 average: false,
544 median: false
545 }
86bf340d 546 })
10fcfaf4
JB
547 // We need to clean up the resources after our test
548 await pool.destroy()
549 })
550
e4543b14 551 it('Verify LEAST_USED strategy can be run in a fixed pool', async () => {
b98ec2e6
JB
552 const pool = new FixedThreadPool(
553 max,
b2fd3f4a 554 './tests/worker-files/thread/testWorker.mjs',
e4543b14 555 { workerChoiceStrategy: WorkerChoiceStrategies.LEAST_USED }
b98ec2e6 556 )
e4543b14 557 // TODO: Create a better test to cover `LeastUsedWorkerChoiceStrategy#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) {
465b2940 565 expect(workerNode.usage).toStrictEqual({
a4e07f72 566 tasks: {
76407b8e 567 executed: expect.any(Number),
a4e07f72
JB
568 executing: 0,
569 queued: 0,
df593701 570 maxQueued: 0,
463226a4 571 sequentiallyStolen: 0,
5ad42e34 572 stolen: 0,
a4e07f72
JB
573 failed: 0
574 },
575 runTime: {
4ba4c7f9 576 history: new CircularArray()
a4e07f72
JB
577 },
578 waitTime: {
4ba4c7f9 579 history: new CircularArray()
a4e07f72 580 },
5df69fab
JB
581 elu: {
582 idle: {
4ba4c7f9 583 history: new CircularArray()
5df69fab
JB
584 },
585 active: {
4ba4c7f9 586 history: new CircularArray()
71514351 587 }
5df69fab 588 }
e211bc18 589 })
465b2940
JB
590 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
591 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
76407b8e
JB
592 max * maxMultiplier
593 )
a35560ba 594 }
e5c68e12
JB
595 expect(
596 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
597 pool.workerChoiceStrategyContext.workerChoiceStrategy
598 ).nextWorkerNodeKey
599 ).toEqual(expect.any(Number))
600 expect(
601 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
602 pool.workerChoiceStrategyContext.workerChoiceStrategy
603 ).previousWorkerNodeKey
604 ).toEqual(expect.any(Number))
a35560ba
S
605 // We need to clean up the resources after our test
606 await pool.destroy()
607 })
608
e4543b14 609 it('Verify LEAST_USED strategy can be run in a dynamic pool', async () => {
ff5e76e1
JB
610 const pool = new DynamicThreadPool(
611 min,
612 max,
b2fd3f4a 613 './tests/worker-files/thread/testWorker.mjs',
e4543b14 614 { workerChoiceStrategy: WorkerChoiceStrategies.LEAST_USED }
ff5e76e1 615 )
e4543b14 616 // TODO: Create a better test to cover `LeastUsedWorkerChoiceStrategy#choose`
ee9f5295 617 const promises = new Set()
a20f0ba5
JB
618 const maxMultiplier = 2
619 for (let i = 0; i < max * maxMultiplier; i++) {
ee9f5295 620 promises.add(pool.execute())
e211bc18
JB
621 }
622 await Promise.all(promises)
623 for (const workerNode of pool.workerNodes) {
465b2940 624 expect(workerNode.usage).toStrictEqual({
a4e07f72 625 tasks: {
76407b8e 626 executed: expect.any(Number),
a4e07f72
JB
627 executing: 0,
628 queued: 0,
df593701 629 maxQueued: 0,
463226a4 630 sequentiallyStolen: 0,
5ad42e34 631 stolen: 0,
a4e07f72
JB
632 failed: 0
633 },
634 runTime: {
4ba4c7f9 635 history: new CircularArray()
a4e07f72
JB
636 },
637 waitTime: {
4ba4c7f9 638 history: new CircularArray()
a4e07f72 639 },
5df69fab
JB
640 elu: {
641 idle: {
4ba4c7f9 642 history: new CircularArray()
5df69fab
JB
643 },
644 active: {
4ba4c7f9 645 history: new CircularArray()
71514351 646 }
5df69fab 647 }
e211bc18 648 })
465b2940
JB
649 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
650 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
76407b8e
JB
651 max * maxMultiplier
652 )
168c526f 653 }
e5c68e12
JB
654 expect(
655 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
656 pool.workerChoiceStrategyContext.workerChoiceStrategy
657 ).nextWorkerNodeKey
658 ).toEqual(expect.any(Number))
659 expect(
660 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
661 pool.workerChoiceStrategyContext.workerChoiceStrategy
662 ).previousWorkerNodeKey
663 ).toEqual(expect.any(Number))
168c526f
JB
664 // We need to clean up the resources after our test
665 await pool.destroy()
666 })
667
6c6afb84
JB
668 it('Verify LEAST_BUSY strategy default policy', async () => {
669 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_BUSY
670 let pool = new FixedThreadPool(
671 max,
b2fd3f4a 672 './tests/worker-files/thread/testWorker.mjs',
6c6afb84
JB
673 { workerChoiceStrategy }
674 )
675 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
b1aae695
JB
676 dynamicWorkerUsage: false,
677 dynamicWorkerReady: true
6c6afb84
JB
678 })
679 await pool.destroy()
680 pool = new DynamicThreadPool(
681 min,
682 max,
b2fd3f4a 683 './tests/worker-files/thread/testWorker.mjs',
6c6afb84
JB
684 { workerChoiceStrategy }
685 )
686 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
b1aae695
JB
687 dynamicWorkerUsage: false,
688 dynamicWorkerReady: true
6c6afb84
JB
689 })
690 // We need to clean up the resources after our test
691 await pool.destroy()
692 })
693
694 it('Verify LEAST_BUSY strategy default tasks statistics requirements', async () => {
e4543b14 695 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_BUSY
168c526f
JB
696 let pool = new FixedThreadPool(
697 max,
b2fd3f4a 698 './tests/worker-files/thread/testWorker.mjs',
594bfb84 699 { workerChoiceStrategy }
168c526f 700 )
87de9ff5
JB
701 expect(
702 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
703 ).toStrictEqual({
932fc8be
JB
704 runTime: {
705 aggregate: true,
706 average: false,
707 median: false
708 },
709 waitTime: {
710 aggregate: true,
711 average: false,
712 median: false
713 },
5df69fab
JB
714 elu: {
715 aggregate: false,
716 average: false,
717 median: false
718 }
86bf340d 719 })
168c526f
JB
720 await pool.destroy()
721 pool = new DynamicThreadPool(
722 min,
723 max,
b2fd3f4a 724 './tests/worker-files/thread/testWorker.mjs',
594bfb84 725 { workerChoiceStrategy }
168c526f 726 )
87de9ff5
JB
727 expect(
728 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
729 ).toStrictEqual({
932fc8be
JB
730 runTime: {
731 aggregate: true,
732 average: false,
733 median: false
734 },
735 waitTime: {
736 aggregate: true,
737 average: false,
738 median: false
739 },
5df69fab
JB
740 elu: {
741 aggregate: false,
742 average: false,
743 median: false
744 }
86bf340d 745 })
168c526f
JB
746 // We need to clean up the resources after our test
747 await pool.destroy()
748 })
749
e4543b14 750 it('Verify LEAST_BUSY strategy can be run in a fixed pool', async () => {
168c526f
JB
751 const pool = new FixedThreadPool(
752 max,
b2fd3f4a 753 './tests/worker-files/thread/testWorker.mjs',
e4543b14 754 { workerChoiceStrategy: WorkerChoiceStrategies.LEAST_BUSY }
168c526f 755 )
e4543b14 756 // TODO: Create a better test to cover `LeastBusyWorkerChoiceStrategy#choose`
ee9f5295 757 const promises = new Set()
a20f0ba5
JB
758 const maxMultiplier = 2
759 for (let i = 0; i < max * maxMultiplier; i++) {
ee9f5295 760 promises.add(pool.execute())
e211bc18
JB
761 }
762 await Promise.all(promises)
763 for (const workerNode of pool.workerNodes) {
619f403b 764 expect(workerNode.usage).toStrictEqual({
a4e07f72
JB
765 tasks: {
766 executed: expect.any(Number),
767 executing: 0,
768 queued: 0,
df593701 769 maxQueued: 0,
463226a4 770 sequentiallyStolen: 0,
5ad42e34 771 stolen: 0,
a4e07f72
JB
772 failed: 0
773 },
619f403b 774 runTime: expect.objectContaining({
a4e07f72 775 history: expect.any(CircularArray)
619f403b
JB
776 }),
777 waitTime: expect.objectContaining({
a4e07f72 778 history: expect.any(CircularArray)
619f403b 779 }),
5df69fab
JB
780 elu: {
781 idle: {
619f403b 782 history: new CircularArray()
5df69fab
JB
783 },
784 active: {
619f403b 785 history: new CircularArray()
71514351 786 }
5df69fab 787 }
e211bc18 788 })
465b2940
JB
789 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
790 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
a4e07f72
JB
791 max * maxMultiplier
792 )
19dbc45b
JB
793 if (workerNode.usage.runTime.aggregate == null) {
794 expect(workerNode.usage.runTime.aggregate).toBeUndefined()
795 } else {
796 expect(workerNode.usage.runTime.aggregate).toBeGreaterThan(0)
797 }
798 if (workerNode.usage.waitTime.aggregate == null) {
799 expect(workerNode.usage.waitTime.aggregate).toBeUndefined()
800 } else {
801 expect(workerNode.usage.waitTime.aggregate).toBeGreaterThan(0)
802 }
168c526f 803 }
e5c68e12
JB
804 expect(
805 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
806 pool.workerChoiceStrategyContext.workerChoiceStrategy
807 ).nextWorkerNodeKey
808 ).toEqual(expect.any(Number))
809 expect(
810 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
811 pool.workerChoiceStrategyContext.workerChoiceStrategy
812 ).previousWorkerNodeKey
813 ).toEqual(expect.any(Number))
168c526f
JB
814 // We need to clean up the resources after our test
815 await pool.destroy()
816 })
817
e4543b14 818 it('Verify LEAST_BUSY strategy can be run in a dynamic pool', async () => {
168c526f
JB
819 const pool = new DynamicThreadPool(
820 min,
821 max,
b2fd3f4a 822 './tests/worker-files/thread/testWorker.mjs',
e4543b14 823 { workerChoiceStrategy: WorkerChoiceStrategies.LEAST_BUSY }
168c526f 824 )
e4543b14 825 // TODO: Create a better test to cover `LeastBusyWorkerChoiceStrategy#choose`
ee9f5295 826 const promises = new Set()
a20f0ba5
JB
827 const maxMultiplier = 2
828 for (let i = 0; i < max * maxMultiplier; i++) {
ee9f5295 829 promises.add(pool.execute())
e211bc18
JB
830 }
831 await Promise.all(promises)
832 for (const workerNode of pool.workerNodes) {
619f403b 833 expect(workerNode.usage).toStrictEqual({
a4e07f72
JB
834 tasks: {
835 executed: expect.any(Number),
836 executing: 0,
837 queued: 0,
df593701 838 maxQueued: 0,
463226a4 839 sequentiallyStolen: 0,
5ad42e34 840 stolen: 0,
a4e07f72
JB
841 failed: 0
842 },
619f403b 843 runTime: expect.objectContaining({
a4e07f72 844 history: expect.any(CircularArray)
619f403b
JB
845 }),
846 waitTime: expect.objectContaining({
a4e07f72 847 history: expect.any(CircularArray)
619f403b 848 }),
5df69fab
JB
849 elu: {
850 idle: {
619f403b 851 history: new CircularArray()
5df69fab
JB
852 },
853 active: {
619f403b 854 history: new CircularArray()
71514351 855 }
5df69fab 856 }
e211bc18 857 })
465b2940
JB
858 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
859 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
a4e07f72
JB
860 max * maxMultiplier
861 )
19dbc45b
JB
862 if (workerNode.usage.runTime.aggregate == null) {
863 expect(workerNode.usage.runTime.aggregate).toBeUndefined()
864 } else {
865 expect(workerNode.usage.runTime.aggregate).toBeGreaterThan(0)
866 }
867 if (workerNode.usage.waitTime.aggregate == null) {
868 expect(workerNode.usage.waitTime.aggregate).toBeUndefined()
869 } else {
870 expect(workerNode.usage.waitTime.aggregate).toBeGreaterThan(0)
871 }
ff5e76e1 872 }
e5c68e12
JB
873 expect(
874 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
875 pool.workerChoiceStrategyContext.workerChoiceStrategy
876 ).nextWorkerNodeKey
877 ).toEqual(expect.any(Number))
878 expect(
879 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
880 pool.workerChoiceStrategyContext.workerChoiceStrategy
881 ).previousWorkerNodeKey
882 ).toEqual(expect.any(Number))
ff5e76e1
JB
883 // We need to clean up the resources after our test
884 await pool.destroy()
885 })
886
6c6afb84
JB
887 it('Verify LEAST_ELU strategy default policy', async () => {
888 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_ELU
889 let pool = new FixedThreadPool(
890 max,
b2fd3f4a 891 './tests/worker-files/thread/testWorker.mjs',
6c6afb84
JB
892 { workerChoiceStrategy }
893 )
894 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
b1aae695
JB
895 dynamicWorkerUsage: false,
896 dynamicWorkerReady: true
6c6afb84
JB
897 })
898 await pool.destroy()
899 pool = new DynamicThreadPool(
900 min,
901 max,
b2fd3f4a 902 './tests/worker-files/thread/testWorker.mjs',
6c6afb84
JB
903 { workerChoiceStrategy }
904 )
905 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
b1aae695
JB
906 dynamicWorkerUsage: false,
907 dynamicWorkerReady: true
6c6afb84
JB
908 })
909 // We need to clean up the resources after our test
910 await pool.destroy()
911 })
912
913 it('Verify LEAST_ELU strategy default tasks statistics requirements', async () => {
a7bbf44a
JB
914 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_ELU
915 let pool = new FixedThreadPool(
916 max,
b2fd3f4a 917 './tests/worker-files/thread/testWorker.mjs',
a7bbf44a
JB
918 { workerChoiceStrategy }
919 )
05302647
JB
920 expect(
921 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
922 ).toStrictEqual({
e460940e
JB
923 runTime: {
924 aggregate: false,
925 average: false,
926 median: false
927 },
928 waitTime: {
929 aggregate: false,
930 average: false,
931 median: false
932 },
5df69fab
JB
933 elu: {
934 aggregate: true,
935 average: false,
936 median: false
937 }
a7bbf44a
JB
938 })
939 await pool.destroy()
940 pool = new DynamicThreadPool(
941 min,
942 max,
b2fd3f4a 943 './tests/worker-files/thread/testWorker.mjs',
a7bbf44a
JB
944 { workerChoiceStrategy }
945 )
05302647
JB
946 expect(
947 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
948 ).toStrictEqual({
e460940e
JB
949 runTime: {
950 aggregate: false,
951 average: false,
952 median: false
953 },
954 waitTime: {
955 aggregate: false,
956 average: false,
957 median: false
958 },
5df69fab
JB
959 elu: {
960 aggregate: true,
961 average: false,
962 median: false
963 }
a7bbf44a
JB
964 })
965 // We need to clean up the resources after our test
966 await pool.destroy()
967 })
968
ae9cf3c8 969 it('Verify LEAST_ELU strategy can be run in a fixed pool', async () => {
c5ad42cd
JB
970 const pool = new FixedThreadPool(
971 max,
b2fd3f4a 972 './tests/worker-files/thread/testWorker.mjs',
c5ad42cd
JB
973 { workerChoiceStrategy: WorkerChoiceStrategies.LEAST_ELU }
974 )
975 // TODO: Create a better test to cover `LeastEluWorkerChoiceStrategy#choose`
dd38581f 976 const promises = new Set()
c5ad42cd
JB
977 const maxMultiplier = 2
978 for (let i = 0; i < max * maxMultiplier; i++) {
dd38581f 979 promises.add(pool.execute())
c5ad42cd 980 }
dd38581f 981 await Promise.all(promises)
c5ad42cd 982 for (const workerNode of pool.workerNodes) {
619f403b 983 expect(workerNode.usage).toStrictEqual({
c5ad42cd
JB
984 tasks: {
985 executed: expect.any(Number),
986 executing: 0,
987 queued: 0,
df593701 988 maxQueued: 0,
463226a4 989 sequentiallyStolen: 0,
5ad42e34 990 stolen: 0,
c5ad42cd
JB
991 failed: 0
992 },
993 runTime: {
619f403b 994 history: new CircularArray()
a1347286
JB
995 },
996 waitTime: {
619f403b 997 history: new CircularArray()
5df69fab 998 },
619f403b
JB
999 elu: expect.objectContaining({
1000 idle: expect.objectContaining({
5df69fab 1001 history: expect.any(CircularArray)
619f403b
JB
1002 }),
1003 active: expect.objectContaining({
5df69fab 1004 history: expect.any(CircularArray)
619f403b
JB
1005 })
1006 })
5df69fab 1007 })
465b2940
JB
1008 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
1009 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
a1347286
JB
1010 max * maxMultiplier
1011 )
7db63069
JB
1012 if (workerNode.usage.elu.active.aggregate == null) {
1013 expect(workerNode.usage.elu.active.aggregate).toBeUndefined()
1014 } else {
1015 expect(workerNode.usage.elu.active.aggregate).toBeGreaterThan(0)
1016 }
1017 if (workerNode.usage.elu.idle.aggregate == null) {
1018 expect(workerNode.usage.elu.idle.aggregate).toBeUndefined()
1019 } else {
1020 expect(workerNode.usage.elu.idle.aggregate).toBeGreaterThanOrEqual(0)
1021 }
71514351
JB
1022 if (workerNode.usage.elu.utilization == null) {
1023 expect(workerNode.usage.elu.utilization).toBeUndefined()
1024 } else {
1025 expect(workerNode.usage.elu.utilization).toBeGreaterThanOrEqual(0)
1026 expect(workerNode.usage.elu.utilization).toBeLessThanOrEqual(1)
1027 }
a1347286 1028 }
e5c68e12
JB
1029 expect(
1030 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1031 pool.workerChoiceStrategyContext.workerChoiceStrategy
1032 ).nextWorkerNodeKey
1033 ).toEqual(expect.any(Number))
1034 expect(
1035 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1036 pool.workerChoiceStrategyContext.workerChoiceStrategy
1037 ).previousWorkerNodeKey
1038 ).toEqual(expect.any(Number))
a1347286
JB
1039 // We need to clean up the resources after our test
1040 await pool.destroy()
1041 })
1042
1043 it('Verify LEAST_ELU strategy can be run in a dynamic pool', async () => {
1044 const pool = new DynamicThreadPool(
1045 min,
1046 max,
b2fd3f4a 1047 './tests/worker-files/thread/testWorker.mjs',
a1347286
JB
1048 { workerChoiceStrategy: WorkerChoiceStrategies.LEAST_ELU }
1049 )
1050 // TODO: Create a better test to cover `LeastEluWorkerChoiceStrategy#choose`
dd38581f 1051 const promises = new Set()
a1347286
JB
1052 const maxMultiplier = 2
1053 for (let i = 0; i < max * maxMultiplier; i++) {
dd38581f 1054 promises.add(pool.execute())
a1347286 1055 }
dd38581f 1056 await Promise.all(promises)
a1347286 1057 for (const workerNode of pool.workerNodes) {
619f403b 1058 expect(workerNode.usage).toStrictEqual({
a1347286
JB
1059 tasks: {
1060 executed: expect.any(Number),
1061 executing: 0,
1062 queued: 0,
df593701 1063 maxQueued: 0,
463226a4 1064 sequentiallyStolen: 0,
5ad42e34 1065 stolen: 0,
a1347286
JB
1066 failed: 0
1067 },
1068 runTime: {
619f403b 1069 history: new CircularArray()
c5ad42cd
JB
1070 },
1071 waitTime: {
619f403b 1072 history: new CircularArray()
5df69fab 1073 },
619f403b
JB
1074 elu: expect.objectContaining({
1075 idle: expect.objectContaining({
5df69fab 1076 history: expect.any(CircularArray)
619f403b
JB
1077 }),
1078 active: expect.objectContaining({
5df69fab 1079 history: expect.any(CircularArray)
619f403b
JB
1080 })
1081 })
5df69fab 1082 })
465b2940
JB
1083 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
1084 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
c5ad42cd
JB
1085 max * maxMultiplier
1086 )
7db63069
JB
1087 if (workerNode.usage.elu.active.aggregate == null) {
1088 expect(workerNode.usage.elu.active.aggregate).toBeUndefined()
1089 } else {
1090 expect(workerNode.usage.elu.active.aggregate).toBeGreaterThan(0)
1091 }
1092 if (workerNode.usage.elu.idle.aggregate == null) {
1093 expect(workerNode.usage.elu.idle.aggregate).toBeUndefined()
1094 } else {
1095 expect(workerNode.usage.elu.idle.aggregate).toBeGreaterThanOrEqual(0)
1096 }
71514351
JB
1097 if (workerNode.usage.elu.utilization == null) {
1098 expect(workerNode.usage.elu.utilization).toBeUndefined()
1099 } else {
1100 expect(workerNode.usage.elu.utilization).toBeGreaterThanOrEqual(0)
1101 expect(workerNode.usage.elu.utilization).toBeLessThanOrEqual(1)
1102 }
c5ad42cd 1103 }
e5c68e12
JB
1104 expect(
1105 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1106 pool.workerChoiceStrategyContext.workerChoiceStrategy
1107 ).nextWorkerNodeKey
1108 ).toEqual(expect.any(Number))
1109 expect(
1110 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1111 pool.workerChoiceStrategyContext.workerChoiceStrategy
1112 ).previousWorkerNodeKey
1113 ).toEqual(expect.any(Number))
c5ad42cd
JB
1114 // We need to clean up the resources after our test
1115 await pool.destroy()
1116 })
1117
6c6afb84
JB
1118 it('Verify FAIR_SHARE strategy default policy', async () => {
1119 const workerChoiceStrategy = WorkerChoiceStrategies.FAIR_SHARE
1120 let pool = new FixedThreadPool(
1121 max,
b2fd3f4a 1122 './tests/worker-files/thread/testWorker.mjs',
6c6afb84
JB
1123 { workerChoiceStrategy }
1124 )
1125 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
b1aae695
JB
1126 dynamicWorkerUsage: false,
1127 dynamicWorkerReady: true
6c6afb84
JB
1128 })
1129 await pool.destroy()
1130 pool = new DynamicThreadPool(
1131 min,
1132 max,
b2fd3f4a 1133 './tests/worker-files/thread/testWorker.mjs',
6c6afb84
JB
1134 { workerChoiceStrategy }
1135 )
1136 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
b1aae695
JB
1137 dynamicWorkerUsage: false,
1138 dynamicWorkerReady: true
6c6afb84
JB
1139 })
1140 // We need to clean up the resources after our test
1141 await pool.destroy()
1142 })
1143
1144 it('Verify FAIR_SHARE strategy default tasks statistics requirements', async () => {
594bfb84 1145 const workerChoiceStrategy = WorkerChoiceStrategies.FAIR_SHARE
10fcfaf4
JB
1146 let pool = new FixedThreadPool(
1147 max,
b2fd3f4a 1148 './tests/worker-files/thread/testWorker.mjs',
594bfb84 1149 { workerChoiceStrategy }
10fcfaf4 1150 )
87de9ff5
JB
1151 expect(
1152 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
1153 ).toStrictEqual({
932fc8be
JB
1154 runTime: {
1155 aggregate: true,
1156 average: true,
1157 median: false
1158 },
1159 waitTime: {
1160 aggregate: false,
1161 average: false,
1162 median: false
1163 },
5df69fab 1164 elu: {
9adcefab
JB
1165 aggregate: true,
1166 average: true,
5df69fab
JB
1167 median: false
1168 }
86bf340d 1169 })
fd7ebd49 1170 await pool.destroy()
10fcfaf4
JB
1171 pool = new DynamicThreadPool(
1172 min,
1173 max,
b2fd3f4a 1174 './tests/worker-files/thread/testWorker.mjs',
594bfb84 1175 { workerChoiceStrategy }
10fcfaf4 1176 )
87de9ff5
JB
1177 expect(
1178 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
1179 ).toStrictEqual({
932fc8be
JB
1180 runTime: {
1181 aggregate: true,
1182 average: true,
1183 median: false
1184 },
1185 waitTime: {
1186 aggregate: false,
1187 average: false,
1188 median: false
1189 },
5df69fab 1190 elu: {
9adcefab
JB
1191 aggregate: true,
1192 average: true,
5df69fab
JB
1193 median: false
1194 }
86bf340d 1195 })
10fcfaf4
JB
1196 // We need to clean up the resources after our test
1197 await pool.destroy()
1198 })
1199
23ff945a 1200 it('Verify FAIR_SHARE strategy can be run in a fixed pool', async () => {
23ff945a
JB
1201 const pool = new FixedThreadPool(
1202 max,
b2fd3f4a 1203 './tests/worker-files/thread/testWorker.mjs',
23ff945a
JB
1204 { workerChoiceStrategy: WorkerChoiceStrategies.FAIR_SHARE }
1205 )
1206 // TODO: Create a better test to cover `FairShareChoiceStrategy#choose`
ee9f5295 1207 const promises = new Set()
a20f0ba5
JB
1208 const maxMultiplier = 2
1209 for (let i = 0; i < max * maxMultiplier; i++) {
ee9f5295 1210 promises.add(pool.execute())
23ff945a 1211 }
e211bc18 1212 await Promise.all(promises)
138d29a8 1213 for (const workerNode of pool.workerNodes) {
619f403b 1214 expect(workerNode.usage).toStrictEqual({
a4e07f72 1215 tasks: {
d33be430 1216 executed: expect.any(Number),
a4e07f72
JB
1217 executing: 0,
1218 queued: 0,
df593701 1219 maxQueued: 0,
463226a4 1220 sequentiallyStolen: 0,
5ad42e34 1221 stolen: 0,
a4e07f72
JB
1222 failed: 0
1223 },
619f403b 1224 runTime: expect.objectContaining({
a4e07f72 1225 history: expect.any(CircularArray)
619f403b 1226 }),
a4e07f72 1227 waitTime: {
619f403b 1228 history: new CircularArray()
a4e07f72 1229 },
619f403b
JB
1230 elu: expect.objectContaining({
1231 idle: expect.objectContaining({
5df69fab 1232 history: expect.any(CircularArray)
619f403b
JB
1233 }),
1234 active: expect.objectContaining({
5df69fab 1235 history: expect.any(CircularArray)
619f403b
JB
1236 })
1237 })
86bf340d 1238 })
465b2940
JB
1239 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
1240 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
d33be430
JB
1241 max * maxMultiplier
1242 )
71514351
JB
1243 if (workerNode.usage.runTime.aggregate == null) {
1244 expect(workerNode.usage.runTime.aggregate).toBeUndefined()
1245 } else {
1246 expect(workerNode.usage.runTime.aggregate).toBeGreaterThan(0)
1247 }
1248 if (workerNode.usage.runTime.average == null) {
1249 expect(workerNode.usage.runTime.average).toBeUndefined()
1250 } else {
1251 expect(workerNode.usage.runTime.average).toBeGreaterThan(0)
1252 }
7db63069
JB
1253 if (workerNode.usage.elu.active.aggregate == null) {
1254 expect(workerNode.usage.elu.active.aggregate).toBeUndefined()
1255 } else {
1256 expect(workerNode.usage.elu.active.aggregate).toBeGreaterThan(0)
1257 }
1258 if (workerNode.usage.elu.idle.aggregate == null) {
1259 expect(workerNode.usage.elu.idle.aggregate).toBeUndefined()
1260 } else {
1261 expect(workerNode.usage.elu.idle.aggregate).toBeGreaterThanOrEqual(0)
1262 }
71514351
JB
1263 if (workerNode.usage.elu.utilization == null) {
1264 expect(workerNode.usage.elu.utilization).toBeUndefined()
1265 } else {
1266 expect(workerNode.usage.elu.utilization).toBeGreaterThanOrEqual(0)
1267 expect(workerNode.usage.elu.utilization).toBeLessThanOrEqual(1)
1268 }
946b809b 1269 expect(workerNode.strategyData.virtualTaskEndTimestamp).toBeGreaterThan(0)
138d29a8 1270 }
e5c68e12
JB
1271 expect(
1272 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1273 pool.workerChoiceStrategyContext.workerChoiceStrategy
1274 ).nextWorkerNodeKey
1275 ).toEqual(expect.any(Number))
1276 expect(
1277 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1278 pool.workerChoiceStrategyContext.workerChoiceStrategy
1279 ).previousWorkerNodeKey
1280 ).toEqual(expect.any(Number))
23ff945a
JB
1281 // We need to clean up the resources after our test
1282 await pool.destroy()
1283 })
1284
1285 it('Verify FAIR_SHARE strategy can be run in a dynamic pool', async () => {
23ff945a
JB
1286 const pool = new DynamicThreadPool(
1287 min,
1288 max,
b2fd3f4a 1289 './tests/worker-files/thread/testWorker.mjs',
23ff945a
JB
1290 { workerChoiceStrategy: WorkerChoiceStrategies.FAIR_SHARE }
1291 )
1292 // TODO: Create a better test to cover `FairShareChoiceStrategy#choose`
ee9f5295 1293 const promises = new Set()
f7070eee 1294 const maxMultiplier = 2
804a889e 1295 for (let i = 0; i < max * maxMultiplier; i++) {
ee9f5295 1296 promises.add(pool.execute())
23ff945a 1297 }
e211bc18 1298 await Promise.all(promises)
138d29a8 1299 for (const workerNode of pool.workerNodes) {
619f403b 1300 expect(workerNode.usage).toStrictEqual({
a4e07f72 1301 tasks: {
6c6afb84 1302 executed: expect.any(Number),
a4e07f72
JB
1303 executing: 0,
1304 queued: 0,
df593701 1305 maxQueued: 0,
463226a4 1306 sequentiallyStolen: 0,
5ad42e34 1307 stolen: 0,
a4e07f72
JB
1308 failed: 0
1309 },
619f403b 1310 runTime: expect.objectContaining({
a4e07f72 1311 history: expect.any(CircularArray)
619f403b 1312 }),
a4e07f72 1313 waitTime: {
619f403b 1314 history: new CircularArray()
a4e07f72 1315 },
619f403b
JB
1316 elu: expect.objectContaining({
1317 idle: expect.objectContaining({
5df69fab 1318 history: expect.any(CircularArray)
619f403b
JB
1319 }),
1320 active: expect.objectContaining({
5df69fab 1321 history: expect.any(CircularArray)
619f403b
JB
1322 })
1323 })
86bf340d 1324 })
465b2940
JB
1325 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
1326 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
6c6afb84
JB
1327 max * maxMultiplier
1328 )
71514351
JB
1329 if (workerNode.usage.runTime.aggregate == null) {
1330 expect(workerNode.usage.runTime.aggregate).toBeUndefined()
1331 } else {
1332 expect(workerNode.usage.runTime.aggregate).toBeGreaterThan(0)
1333 }
1334 if (workerNode.usage.runTime.average == null) {
1335 expect(workerNode.usage.runTime.average).toBeUndefined()
1336 } else {
1337 expect(workerNode.usage.runTime.average).toBeGreaterThan(0)
1338 }
7db63069
JB
1339 if (workerNode.usage.elu.active.aggregate == null) {
1340 expect(workerNode.usage.elu.active.aggregate).toBeUndefined()
1341 } else {
1342 expect(workerNode.usage.elu.active.aggregate).toBeGreaterThan(0)
1343 }
1344 if (workerNode.usage.elu.idle.aggregate == null) {
1345 expect(workerNode.usage.elu.idle.aggregate).toBeUndefined()
1346 } else {
1347 expect(workerNode.usage.elu.idle.aggregate).toBeGreaterThanOrEqual(0)
1348 }
71514351
JB
1349 if (workerNode.usage.elu.utilization == null) {
1350 expect(workerNode.usage.elu.utilization).toBeUndefined()
1351 } else {
1352 expect(workerNode.usage.elu.utilization).toBeGreaterThanOrEqual(0)
1353 expect(workerNode.usage.elu.utilization).toBeLessThanOrEqual(1)
1354 }
946b809b 1355 expect(workerNode.strategyData.virtualTaskEndTimestamp).toBeGreaterThan(0)
138d29a8 1356 }
e5c68e12
JB
1357 expect(
1358 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1359 pool.workerChoiceStrategyContext.workerChoiceStrategy
1360 ).nextWorkerNodeKey
1361 ).toEqual(expect.any(Number))
1362 expect(
1363 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1364 pool.workerChoiceStrategyContext.workerChoiceStrategy
1365 ).previousWorkerNodeKey
1366 ).toEqual(expect.any(Number))
23ff945a
JB
1367 // We need to clean up the resources after our test
1368 await pool.destroy()
1369 })
1370
9e775f96 1371 it('Verify FAIR_SHARE strategy can be run in a dynamic pool with median runtime statistic', async () => {
010d7020
JB
1372 const pool = new DynamicThreadPool(
1373 min,
1374 max,
b2fd3f4a 1375 './tests/worker-files/thread/testWorker.mjs',
010d7020
JB
1376 {
1377 workerChoiceStrategy: WorkerChoiceStrategies.FAIR_SHARE,
1378 workerChoiceStrategyOptions: {
932fc8be 1379 runTime: { median: true }
010d7020
JB
1380 }
1381 }
1382 )
1383 // TODO: Create a better test to cover `FairShareChoiceStrategy#choose`
ee9f5295 1384 const promises = new Set()
010d7020
JB
1385 const maxMultiplier = 2
1386 for (let i = 0; i < max * maxMultiplier; i++) {
ee9f5295 1387 promises.add(pool.execute())
010d7020 1388 }
e211bc18 1389 await Promise.all(promises)
010d7020 1390 for (const workerNode of pool.workerNodes) {
619f403b 1391 expect(workerNode.usage).toStrictEqual({
a4e07f72 1392 tasks: {
6c6afb84 1393 executed: expect.any(Number),
a4e07f72
JB
1394 executing: 0,
1395 queued: 0,
df593701 1396 maxQueued: 0,
463226a4 1397 sequentiallyStolen: 0,
5ad42e34 1398 stolen: 0,
a4e07f72
JB
1399 failed: 0
1400 },
619f403b 1401 runTime: expect.objectContaining({
a4e07f72 1402 history: expect.any(CircularArray)
619f403b 1403 }),
a4e07f72 1404 waitTime: {
619f403b 1405 history: new CircularArray()
a4e07f72 1406 },
619f403b
JB
1407 elu: expect.objectContaining({
1408 idle: expect.objectContaining({
5df69fab 1409 history: expect.any(CircularArray)
619f403b
JB
1410 }),
1411 active: expect.objectContaining({
5df69fab 1412 history: expect.any(CircularArray)
619f403b
JB
1413 })
1414 })
86bf340d 1415 })
465b2940
JB
1416 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
1417 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
6c6afb84
JB
1418 max * maxMultiplier
1419 )
71514351
JB
1420 if (workerNode.usage.runTime.aggregate == null) {
1421 expect(workerNode.usage.runTime.aggregate).toBeUndefined()
1422 } else {
1423 expect(workerNode.usage.runTime.aggregate).toBeGreaterThan(0)
1424 }
1425 if (workerNode.usage.runTime.median == null) {
1426 expect(workerNode.usage.runTime.median).toBeUndefined()
1427 } else {
1428 expect(workerNode.usage.runTime.median).toBeGreaterThan(0)
1429 }
7db63069
JB
1430 if (workerNode.usage.elu.active.aggregate == null) {
1431 expect(workerNode.usage.elu.active.aggregate).toBeUndefined()
1432 } else {
1433 expect(workerNode.usage.elu.active.aggregate).toBeGreaterThan(0)
1434 }
1435 if (workerNode.usage.elu.idle.aggregate == null) {
1436 expect(workerNode.usage.elu.idle.aggregate).toBeUndefined()
1437 } else {
1438 expect(workerNode.usage.elu.idle.aggregate).toBeGreaterThanOrEqual(0)
1439 }
71514351
JB
1440 if (workerNode.usage.elu.utilization == null) {
1441 expect(workerNode.usage.elu.utilization).toBeUndefined()
1442 } else {
1443 expect(workerNode.usage.elu.utilization).toBeGreaterThanOrEqual(0)
1444 expect(workerNode.usage.elu.utilization).toBeLessThanOrEqual(1)
1445 }
946b809b 1446 expect(workerNode.strategyData.virtualTaskEndTimestamp).toBeGreaterThan(0)
010d7020 1447 }
2b4fddb8
JB
1448 expect(
1449 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1450 pool.workerChoiceStrategyContext.workerChoiceStrategy
e5c68e12
JB
1451 ).nextWorkerNodeKey
1452 ).toEqual(expect.any(Number))
1453 expect(
1454 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1455 pool.workerChoiceStrategyContext.workerChoiceStrategy
1456 ).previousWorkerNodeKey
1457 ).toEqual(expect.any(Number))
010d7020
JB
1458 // We need to clean up the resources after our test
1459 await pool.destroy()
1460 })
1461
a6f7f1b4 1462 it('Verify FAIR_SHARE strategy internals are resets after setting it', async () => {
594bfb84 1463 const workerChoiceStrategy = WorkerChoiceStrategies.FAIR_SHARE
f0829c53 1464 let pool = new FixedThreadPool(
caeb9817 1465 max,
b2fd3f4a 1466 './tests/worker-files/thread/testWorker.mjs'
caeb9817 1467 )
f3a91bac
JB
1468 for (const workerNode of pool.workerNodes) {
1469 workerNode.strategyData = {
1470 virtualTaskEndTimestamp: performance.now()
1471 }
1472 }
594bfb84 1473 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
f3a91bac
JB
1474 for (const workerNode of pool.workerNodes) {
1475 expect(workerNode.strategyData.virtualTaskEndTimestamp).toBeUndefined()
1476 }
f0829c53
JB
1477 await pool.destroy()
1478 pool = new DynamicThreadPool(
1479 min,
1480 max,
b2fd3f4a 1481 './tests/worker-files/thread/testWorker.mjs'
f0829c53 1482 )
f3a91bac
JB
1483 for (const workerNode of pool.workerNodes) {
1484 workerNode.strategyData = {
1485 virtualTaskEndTimestamp: performance.now()
1486 }
1487 }
594bfb84 1488 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
f3a91bac
JB
1489 for (const workerNode of pool.workerNodes) {
1490 expect(workerNode.strategyData.virtualTaskEndTimestamp).toBeUndefined()
1491 }
caeb9817
JB
1492 // We need to clean up the resources after our test
1493 await pool.destroy()
1494 })
1495
6c6afb84
JB
1496 it('Verify WEIGHTED_ROUND_ROBIN strategy default policy', async () => {
1497 const workerChoiceStrategy = WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
1498 let pool = new FixedThreadPool(
1499 max,
b2fd3f4a 1500 './tests/worker-files/thread/testWorker.mjs',
6c6afb84
JB
1501 { workerChoiceStrategy }
1502 )
1503 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
b1aae695
JB
1504 dynamicWorkerUsage: false,
1505 dynamicWorkerReady: true
6c6afb84
JB
1506 })
1507 await pool.destroy()
1508 pool = new DynamicThreadPool(
1509 min,
1510 max,
b2fd3f4a 1511 './tests/worker-files/thread/testWorker.mjs',
6c6afb84
JB
1512 { workerChoiceStrategy }
1513 )
1514 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
b1aae695
JB
1515 dynamicWorkerUsage: false,
1516 dynamicWorkerReady: true
6c6afb84
JB
1517 })
1518 // We need to clean up the resources after our test
1519 await pool.destroy()
1520 })
1521
1522 it('Verify WEIGHTED_ROUND_ROBIN strategy default tasks statistics requirements', async () => {
594bfb84 1523 const workerChoiceStrategy = WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
10fcfaf4
JB
1524 let pool = new FixedThreadPool(
1525 max,
b2fd3f4a 1526 './tests/worker-files/thread/testWorker.mjs',
594bfb84 1527 { workerChoiceStrategy }
10fcfaf4 1528 )
87de9ff5
JB
1529 expect(
1530 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
1531 ).toStrictEqual({
932fc8be
JB
1532 runTime: {
1533 aggregate: true,
1534 average: true,
1535 median: false
1536 },
1537 waitTime: {
1538 aggregate: false,
1539 average: false,
1540 median: false
1541 },
5df69fab
JB
1542 elu: {
1543 aggregate: false,
1544 average: false,
1545 median: false
1546 }
86bf340d 1547 })
fd7ebd49 1548 await pool.destroy()
10fcfaf4
JB
1549 pool = new DynamicThreadPool(
1550 min,
1551 max,
b2fd3f4a 1552 './tests/worker-files/thread/testWorker.mjs',
594bfb84 1553 { workerChoiceStrategy }
10fcfaf4 1554 )
87de9ff5
JB
1555 expect(
1556 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
1557 ).toStrictEqual({
932fc8be
JB
1558 runTime: {
1559 aggregate: true,
1560 average: true,
1561 median: false
1562 },
1563 waitTime: {
1564 aggregate: false,
1565 average: false,
1566 median: false
1567 },
5df69fab
JB
1568 elu: {
1569 aggregate: false,
1570 average: false,
1571 median: false
1572 }
86bf340d 1573 })
10fcfaf4
JB
1574 // We need to clean up the resources after our test
1575 await pool.destroy()
1576 })
1577
b3432a63 1578 it('Verify WEIGHTED_ROUND_ROBIN strategy can be run in a fixed pool', async () => {
b3432a63
JB
1579 const pool = new FixedThreadPool(
1580 max,
b2fd3f4a 1581 './tests/worker-files/thread/testWorker.mjs',
b3432a63
JB
1582 { workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN }
1583 )
1584 // TODO: Create a better test to cover `WeightedRoundRobinWorkerChoiceStrategy#choose`
ee9f5295 1585 const promises = new Set()
a20f0ba5
JB
1586 const maxMultiplier = 2
1587 for (let i = 0; i < max * maxMultiplier; i++) {
ee9f5295 1588 promises.add(pool.execute())
b3432a63 1589 }
e211bc18 1590 await Promise.all(promises)
138d29a8 1591 for (const workerNode of pool.workerNodes) {
465b2940 1592 expect(workerNode.usage).toStrictEqual({
a4e07f72
JB
1593 tasks: {
1594 executed: expect.any(Number),
1595 executing: 0,
1596 queued: 0,
df593701 1597 maxQueued: 0,
463226a4 1598 sequentiallyStolen: 0,
5ad42e34 1599 stolen: 0,
a4e07f72
JB
1600 failed: 0
1601 },
71514351 1602 runTime: expect.objectContaining({
a4e07f72 1603 history: expect.any(CircularArray)
71514351 1604 }),
a4e07f72 1605 waitTime: {
619f403b 1606 history: new CircularArray()
a4e07f72 1607 },
5df69fab
JB
1608 elu: {
1609 idle: {
619f403b 1610 history: new CircularArray()
5df69fab
JB
1611 },
1612 active: {
619f403b 1613 history: new CircularArray()
71514351 1614 }
5df69fab 1615 }
86bf340d 1616 })
465b2940
JB
1617 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
1618 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
a4e07f72
JB
1619 max * maxMultiplier
1620 )
71514351
JB
1621 if (workerNode.usage.runTime.aggregate == null) {
1622 expect(workerNode.usage.runTime.aggregate).toBeUndefined()
1623 } else {
1624 expect(workerNode.usage.runTime.aggregate).toBeGreaterThan(0)
1625 }
1626 if (workerNode.usage.runTime.average == null) {
1627 expect(workerNode.usage.runTime.average).toBeUndefined()
1628 } else {
1629 expect(workerNode.usage.runTime.average).toBeGreaterThan(0)
1630 }
138d29a8 1631 }
516dcb0d
JB
1632 expect(
1633 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1634 pool.workerChoiceStrategyContext.workerChoiceStrategy
1635 ).nextWorkerNodeKey
1636 ).toBe(0)
1637 expect(
1638 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1639 pool.workerChoiceStrategyContext.workerChoiceStrategy
1640 ).previousWorkerNodeKey
1641 ).toBe(0)
97a2abc3 1642 expect(
95c83464 1643 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
d710242d 1644 pool.workerChoiceStrategyContext.workerChoiceStrategy
08f3f44c
JB
1645 ).defaultWorkerWeight
1646 ).toBeGreaterThan(0)
1647 expect(
1648 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1649 pool.workerChoiceStrategyContext.workerChoiceStrategy
f3a91bac 1650 ).workerNodeVirtualTaskRunTime
08f3f44c 1651 ).toBeGreaterThanOrEqual(0)
b3432a63
JB
1652 // We need to clean up the resources after our test
1653 await pool.destroy()
1654 })
1655
1656 it('Verify WEIGHTED_ROUND_ROBIN strategy can be run in a dynamic pool', async () => {
b3432a63
JB
1657 const pool = new DynamicThreadPool(
1658 min,
1659 max,
b2fd3f4a 1660 './tests/worker-files/thread/testWorker.mjs',
b3432a63
JB
1661 { workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN }
1662 )
1663 // TODO: Create a better test to cover `WeightedRoundRobinWorkerChoiceStrategy#choose`
ee9f5295 1664 const promises = new Set()
138d29a8 1665 const maxMultiplier = 2
5502c07c 1666 for (let i = 0; i < max * maxMultiplier; i++) {
ee9f5295 1667 promises.add(pool.execute())
b3432a63 1668 }
e211bc18 1669 await Promise.all(promises)
138d29a8 1670 for (const workerNode of pool.workerNodes) {
465b2940 1671 expect(workerNode.usage).toStrictEqual({
a4e07f72
JB
1672 tasks: {
1673 executed: expect.any(Number),
1674 executing: 0,
1675 queued: 0,
df593701 1676 maxQueued: 0,
463226a4 1677 sequentiallyStolen: 0,
5ad42e34 1678 stolen: 0,
a4e07f72
JB
1679 failed: 0
1680 },
b1aae695 1681 runTime: expect.objectContaining({
a4e07f72 1682 history: expect.any(CircularArray)
b1aae695 1683 }),
a4e07f72 1684 waitTime: {
619f403b 1685 history: new CircularArray()
a4e07f72 1686 },
5df69fab
JB
1687 elu: {
1688 idle: {
619f403b 1689 history: new CircularArray()
5df69fab
JB
1690 },
1691 active: {
619f403b 1692 history: new CircularArray()
71514351 1693 }
5df69fab 1694 }
86bf340d 1695 })
465b2940
JB
1696 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
1697 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
a4e07f72
JB
1698 max * maxMultiplier
1699 )
b1aae695
JB
1700 if (workerNode.usage.runTime.aggregate == null) {
1701 expect(workerNode.usage.runTime.aggregate).toBeUndefined()
1702 } else {
1703 expect(workerNode.usage.runTime.aggregate).toBeGreaterThan(0)
1704 }
1705 if (workerNode.usage.runTime.average == null) {
1706 expect(workerNode.usage.runTime.average).toBeUndefined()
1707 } else {
1708 expect(workerNode.usage.runTime.average).toBeGreaterThan(0)
1709 }
138d29a8 1710 }
516dcb0d
JB
1711 expect(
1712 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1713 pool.workerChoiceStrategyContext.workerChoiceStrategy
1714 ).nextWorkerNodeKey
1715 ).toBe(0)
1716 expect(
1717 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1718 pool.workerChoiceStrategyContext.workerChoiceStrategy
1719 ).previousWorkerNodeKey
1720 ).toBe(0)
2b4fddb8
JB
1721 expect(
1722 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1723 pool.workerChoiceStrategyContext.workerChoiceStrategy
1724 ).defaultWorkerWeight
1725 ).toBeGreaterThan(0)
1726 expect(
1727 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1728 pool.workerChoiceStrategyContext.workerChoiceStrategy
f3a91bac 1729 ).workerNodeVirtualTaskRunTime
2b4fddb8 1730 ).toBeGreaterThanOrEqual(0)
b3432a63
JB
1731 // We need to clean up the resources after our test
1732 await pool.destroy()
1733 })
1734
9e775f96 1735 it('Verify WEIGHTED_ROUND_ROBIN strategy can be run in a dynamic pool with median runtime statistic', async () => {
010d7020
JB
1736 const pool = new DynamicThreadPool(
1737 min,
1738 max,
b2fd3f4a 1739 './tests/worker-files/thread/testWorker.mjs',
010d7020
JB
1740 {
1741 workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN,
1742 workerChoiceStrategyOptions: {
932fc8be 1743 runTime: { median: true }
010d7020
JB
1744 }
1745 }
1746 )
1747 // TODO: Create a better test to cover `WeightedRoundRobinWorkerChoiceStrategy#choose`
ee9f5295 1748 const promises = new Set()
010d7020
JB
1749 const maxMultiplier = 2
1750 for (let i = 0; i < max * maxMultiplier; i++) {
ee9f5295 1751 promises.add(pool.execute())
010d7020 1752 }
e211bc18 1753 await Promise.all(promises)
010d7020 1754 for (const workerNode of pool.workerNodes) {
465b2940 1755 expect(workerNode.usage).toStrictEqual({
a4e07f72
JB
1756 tasks: {
1757 executed: expect.any(Number),
1758 executing: 0,
1759 queued: 0,
df593701 1760 maxQueued: 0,
463226a4 1761 sequentiallyStolen: 0,
5ad42e34 1762 stolen: 0,
a4e07f72
JB
1763 failed: 0
1764 },
b1aae695 1765 runTime: expect.objectContaining({
a4e07f72 1766 history: expect.any(CircularArray)
b1aae695 1767 }),
a4e07f72 1768 waitTime: {
619f403b 1769 history: new CircularArray()
a4e07f72 1770 },
5df69fab
JB
1771 elu: {
1772 idle: {
619f403b 1773 history: new CircularArray()
5df69fab
JB
1774 },
1775 active: {
619f403b 1776 history: new CircularArray()
71514351 1777 }
5df69fab 1778 }
86bf340d 1779 })
465b2940
JB
1780 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
1781 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
a4e07f72
JB
1782 max * maxMultiplier
1783 )
b1aae695
JB
1784 if (workerNode.usage.runTime.aggregate == null) {
1785 expect(workerNode.usage.runTime.aggregate).toBeUndefined()
1786 } else {
1787 expect(workerNode.usage.runTime.aggregate).toBeGreaterThan(0)
1788 }
1789 if (workerNode.usage.runTime.median == null) {
1790 expect(workerNode.usage.runTime.median).toBeUndefined()
1791 } else {
1792 expect(workerNode.usage.runTime.median).toBeGreaterThan(0)
1793 }
010d7020 1794 }
516dcb0d
JB
1795 expect(
1796 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1797 pool.workerChoiceStrategyContext.workerChoiceStrategy
1798 ).nextWorkerNodeKey
1799 ).toBe(0)
1800 expect(
1801 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1802 pool.workerChoiceStrategyContext.workerChoiceStrategy
1803 ).previousWorkerNodeKey
1804 ).toBe(0)
08f3f44c
JB
1805 expect(
1806 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1807 pool.workerChoiceStrategyContext.workerChoiceStrategy
1808 ).defaultWorkerWeight
1809 ).toBeGreaterThan(0)
1810 expect(
1811 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1812 pool.workerChoiceStrategyContext.workerChoiceStrategy
f3a91bac 1813 ).workerNodeVirtualTaskRunTime
08f3f44c 1814 ).toBeGreaterThanOrEqual(0)
010d7020
JB
1815 // We need to clean up the resources after our test
1816 await pool.destroy()
1817 })
1818
a6f7f1b4 1819 it('Verify WEIGHTED_ROUND_ROBIN strategy internals are resets after setting it', async () => {
594bfb84 1820 const workerChoiceStrategy = WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
f0829c53 1821 let pool = new FixedThreadPool(
caeb9817 1822 max,
b2fd3f4a 1823 './tests/worker-files/thread/testWorker.mjs'
caeb9817 1824 )
38f6e859 1825 expect(
95c83464 1826 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 1827 workerChoiceStrategy
9b106837 1828 ).nextWorkerNodeKey
b529c323 1829 ).toBeDefined()
086fd843
JB
1830 expect(
1831 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1832 workerChoiceStrategy
1833 ).previousWorkerNodeKey
1834 ).toBeDefined()
38f6e859 1835 expect(
95c83464 1836 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 1837 workerChoiceStrategy
b529c323
JB
1838 ).defaultWorkerWeight
1839 ).toBeDefined()
caeb9817 1840 expect(
95c83464 1841 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 1842 workerChoiceStrategy
f3a91bac 1843 ).workerNodeVirtualTaskRunTime
b529c323 1844 ).toBeDefined()
594bfb84 1845 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
a6f7f1b4 1846 expect(
95c83464 1847 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
d710242d 1848 pool.workerChoiceStrategyContext.workerChoiceStrategy
9b106837 1849 ).nextWorkerNodeKey
a6f7f1b4 1850 ).toBe(0)
086fd843
JB
1851 expect(
1852 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1853 pool.workerChoiceStrategyContext.workerChoiceStrategy
1854 ).previousWorkerNodeKey
1855 ).toBe(0)
a6f7f1b4 1856 expect(
95c83464 1857 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
d710242d 1858 pool.workerChoiceStrategyContext.workerChoiceStrategy
95c83464 1859 ).defaultWorkerWeight
a6f7f1b4 1860 ).toBeGreaterThan(0)
08f3f44c
JB
1861 expect(
1862 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
086fd843 1863 pool.workerChoiceStrategyContext.workerChoiceStrategy
f3a91bac 1864 ).workerNodeVirtualTaskRunTime
08f3f44c 1865 ).toBe(0)
f0829c53
JB
1866 await pool.destroy()
1867 pool = new DynamicThreadPool(
1868 min,
1869 max,
b2fd3f4a 1870 './tests/worker-files/thread/testWorker.mjs'
f0829c53 1871 )
38f6e859 1872 expect(
95c83464 1873 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 1874 workerChoiceStrategy
9b106837 1875 ).nextWorkerNodeKey
b529c323 1876 ).toBeDefined()
086fd843
JB
1877 expect(
1878 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1879 workerChoiceStrategy
1880 ).previousWorkerNodeKey
1881 ).toBeDefined()
38f6e859 1882 expect(
95c83464 1883 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 1884 workerChoiceStrategy
b529c323
JB
1885 ).defaultWorkerWeight
1886 ).toBeDefined()
f0829c53 1887 expect(
95c83464 1888 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 1889 workerChoiceStrategy
f3a91bac 1890 ).workerNodeVirtualTaskRunTime
b529c323 1891 ).toBeDefined()
594bfb84 1892 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
a6f7f1b4 1893 expect(
95c83464 1894 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
d710242d 1895 pool.workerChoiceStrategyContext.workerChoiceStrategy
9b106837 1896 ).nextWorkerNodeKey
a6f7f1b4 1897 ).toBe(0)
086fd843
JB
1898 expect(
1899 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
1900 pool.workerChoiceStrategyContext.workerChoiceStrategy
1901 ).previousWorkerNodeKey
1902 ).toBe(0)
a6f7f1b4 1903 expect(
95c83464 1904 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
d710242d 1905 pool.workerChoiceStrategyContext.workerChoiceStrategy
95c83464 1906 ).defaultWorkerWeight
a6f7f1b4 1907 ).toBeGreaterThan(0)
08f3f44c
JB
1908 expect(
1909 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
086fd843 1910 pool.workerChoiceStrategyContext.workerChoiceStrategy
f3a91bac 1911 ).workerNodeVirtualTaskRunTime
08f3f44c 1912 ).toBe(0)
caeb9817
JB
1913 // We need to clean up the resources after our test
1914 await pool.destroy()
1915 })
1916
6c6afb84
JB
1917 it('Verify INTERLEAVED_WEIGHTED_ROUND_ROBIN strategy default policy', async () => {
1918 const workerChoiceStrategy =
1919 WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
1920 let pool = new FixedThreadPool(
1921 max,
b2fd3f4a 1922 './tests/worker-files/thread/testWorker.mjs',
6c6afb84
JB
1923 { workerChoiceStrategy }
1924 )
1925 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
b1aae695
JB
1926 dynamicWorkerUsage: false,
1927 dynamicWorkerReady: true
6c6afb84
JB
1928 })
1929 await pool.destroy()
1930 pool = new DynamicThreadPool(
1931 min,
1932 max,
b2fd3f4a 1933 './tests/worker-files/thread/testWorker.mjs',
6c6afb84
JB
1934 { workerChoiceStrategy }
1935 )
1936 expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({
b1aae695
JB
1937 dynamicWorkerUsage: false,
1938 dynamicWorkerReady: true
6c6afb84
JB
1939 })
1940 // We need to clean up the resources after our test
1941 await pool.destroy()
1942 })
1943
1944 it('Verify INTERLEAVED_WEIGHTED_ROUND_ROBIN strategy default tasks statistics requirements', async () => {
e52fb978
JB
1945 const workerChoiceStrategy =
1946 WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
1947 let pool = new FixedThreadPool(
1948 max,
b2fd3f4a 1949 './tests/worker-files/thread/testWorker.mjs',
e52fb978
JB
1950 { workerChoiceStrategy }
1951 )
87de9ff5
JB
1952 expect(
1953 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
1954 ).toStrictEqual({
932fc8be 1955 runTime: {
619f403b
JB
1956 aggregate: true,
1957 average: true,
932fc8be
JB
1958 median: false
1959 },
1960 waitTime: {
1961 aggregate: false,
1962 average: false,
1963 median: false
1964 },
5df69fab
JB
1965 elu: {
1966 aggregate: false,
1967 average: false,
1968 median: false
1969 }
e52fb978
JB
1970 })
1971 await pool.destroy()
1972 pool = new DynamicThreadPool(
1973 min,
1974 max,
b2fd3f4a 1975 './tests/worker-files/thread/testWorker.mjs',
e52fb978
JB
1976 { workerChoiceStrategy }
1977 )
87de9ff5
JB
1978 expect(
1979 pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
1980 ).toStrictEqual({
932fc8be 1981 runTime: {
619f403b
JB
1982 aggregate: true,
1983 average: true,
932fc8be
JB
1984 median: false
1985 },
1986 waitTime: {
1987 aggregate: false,
1988 average: false,
1989 median: false
1990 },
5df69fab
JB
1991 elu: {
1992 aggregate: false,
1993 average: false,
1994 median: false
1995 }
e52fb978
JB
1996 })
1997 // We need to clean up the resources after our test
1998 await pool.destroy()
1999 })
2000
e62e7646
JB
2001 it('Verify INTERLEAVED_WEIGHTED_ROUND_ROBIN strategy can be run in a fixed pool', async () => {
2002 const pool = new FixedThreadPool(
2003 max,
b2fd3f4a 2004 './tests/worker-files/thread/testWorker.mjs',
e62e7646
JB
2005 {
2006 workerChoiceStrategy:
2007 WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
2008 }
2009 )
2010 // TODO: Create a better test to cover `InterleavedWeightedRoundRobinWorkerChoiceStrategy#choose`
2011 const promises = new Set()
2012 const maxMultiplier = 2
2013 for (let i = 0; i < max * maxMultiplier; i++) {
2014 promises.add(pool.execute())
2015 }
2016 await Promise.all(promises)
2017 for (const workerNode of pool.workerNodes) {
465b2940 2018 expect(workerNode.usage).toStrictEqual({
a4e07f72 2019 tasks: {
619f403b 2020 executed: expect.any(Number),
a4e07f72
JB
2021 executing: 0,
2022 queued: 0,
df593701 2023 maxQueued: 0,
463226a4 2024 sequentiallyStolen: 0,
5ad42e34 2025 stolen: 0,
a4e07f72
JB
2026 failed: 0
2027 },
619f403b
JB
2028 runTime: expect.objectContaining({
2029 history: expect.any(CircularArray)
2030 }),
a4e07f72 2031 waitTime: {
4ba4c7f9 2032 history: new CircularArray()
a4e07f72 2033 },
5df69fab
JB
2034 elu: {
2035 idle: {
4ba4c7f9 2036 history: new CircularArray()
5df69fab
JB
2037 },
2038 active: {
4ba4c7f9 2039 history: new CircularArray()
71514351 2040 }
5df69fab 2041 }
e62e7646 2042 })
619f403b
JB
2043 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
2044 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
2045 max * maxMultiplier
2046 )
e62e7646
JB
2047 }
2048 expect(
2049 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2050 pool.workerChoiceStrategyContext.workerChoiceStrategy
2051 ).defaultWorkerWeight
2052 ).toBeGreaterThan(0)
2053 expect(
2054 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2055 pool.workerChoiceStrategyContext.workerChoiceStrategy
d33be430 2056 ).roundId
e62e7646 2057 ).toBe(0)
619f403b
JB
2058 expect(
2059 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2060 pool.workerChoiceStrategyContext.workerChoiceStrategy
2061 ).workerNodeId
2062 ).toBe(0)
e62e7646
JB
2063 expect(
2064 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2065 pool.workerChoiceStrategyContext.workerChoiceStrategy
9b106837 2066 ).nextWorkerNodeKey
e62e7646 2067 ).toBe(0)
086fd843
JB
2068 expect(
2069 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2070 pool.workerChoiceStrategyContext.workerChoiceStrategy
2071 ).previousWorkerNodeKey
2072 ).toEqual(expect.any(Number))
e62e7646
JB
2073 expect(
2074 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2075 pool.workerChoiceStrategyContext.workerChoiceStrategy
2076 ).roundWeights
2077 ).toStrictEqual([
2078 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2079 pool.workerChoiceStrategyContext.workerChoiceStrategy
2080 ).defaultWorkerWeight
2081 ])
2082 // We need to clean up the resources after our test
2083 await pool.destroy()
2084 })
2085
2086 it('Verify INTERLEAVED_WEIGHTED_ROUND_ROBIN strategy can be run in a dynamic pool', async () => {
2087 const pool = new DynamicThreadPool(
2088 min,
2089 max,
b2fd3f4a 2090 './tests/worker-files/thread/testWorker.mjs',
e62e7646
JB
2091 {
2092 workerChoiceStrategy:
2093 WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
2094 }
2095 )
2096 // TODO: Create a better test to cover `InterleavedWeightedRoundRobinWorkerChoiceStrategy#choose`
2097 const promises = new Set()
2098 const maxMultiplier = 2
2099 for (let i = 0; i < max * maxMultiplier; i++) {
2100 promises.add(pool.execute())
2101 }
2102 await Promise.all(promises)
2103 for (const workerNode of pool.workerNodes) {
465b2940 2104 expect(workerNode.usage).toStrictEqual({
a4e07f72 2105 tasks: {
b1aae695 2106 executed: expect.any(Number),
a4e07f72
JB
2107 executing: 0,
2108 queued: 0,
df593701 2109 maxQueued: 0,
463226a4 2110 sequentiallyStolen: 0,
5ad42e34 2111 stolen: 0,
a4e07f72
JB
2112 failed: 0
2113 },
619f403b
JB
2114 runTime: expect.objectContaining({
2115 history: expect.any(CircularArray)
2116 }),
a4e07f72 2117 waitTime: {
4ba4c7f9 2118 history: new CircularArray()
a4e07f72 2119 },
5df69fab
JB
2120 elu: {
2121 idle: {
4ba4c7f9 2122 history: new CircularArray()
5df69fab
JB
2123 },
2124 active: {
4ba4c7f9 2125 history: new CircularArray()
71514351 2126 }
5df69fab 2127 }
e62e7646 2128 })
e43b8c2d
JB
2129 expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
2130 expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
2131 max * maxMultiplier
2132 )
e62e7646
JB
2133 }
2134 expect(
2135 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2136 pool.workerChoiceStrategyContext.workerChoiceStrategy
2137 ).defaultWorkerWeight
2138 ).toBeGreaterThan(0)
2139 expect(
2140 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2141 pool.workerChoiceStrategyContext.workerChoiceStrategy
d33be430 2142 ).roundId
e62e7646 2143 ).toBe(0)
619f403b
JB
2144 expect(
2145 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2146 pool.workerChoiceStrategyContext.workerChoiceStrategy
2147 ).workerNodeId
2148 ).toBe(0)
e62e7646
JB
2149 expect(
2150 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2151 pool.workerChoiceStrategyContext.workerChoiceStrategy
9b106837 2152 ).nextWorkerNodeKey
d2c73f82 2153 ).toBe(0)
086fd843
JB
2154 expect(
2155 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2156 pool.workerChoiceStrategyContext.workerChoiceStrategy
2157 ).previousWorkerNodeKey
2158 ).toEqual(expect.any(Number))
e62e7646
JB
2159 expect(
2160 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2161 pool.workerChoiceStrategyContext.workerChoiceStrategy
2162 ).roundWeights
2163 ).toStrictEqual([
2164 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2165 pool.workerChoiceStrategyContext.workerChoiceStrategy
2166 ).defaultWorkerWeight
2167 ])
2168 // We need to clean up the resources after our test
2169 await pool.destroy()
2170 })
2171
8c3ec188
JB
2172 it('Verify INTERLEAVED_WEIGHTED_ROUND_ROBIN strategy internals are resets after setting it', async () => {
2173 const workerChoiceStrategy =
2174 WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
2175 let pool = new FixedThreadPool(
2176 max,
b2fd3f4a 2177 './tests/worker-files/thread/testWorker.mjs'
8c3ec188
JB
2178 )
2179 expect(
2180 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2181 workerChoiceStrategy
d33be430 2182 ).roundId
8c3ec188 2183 ).toBeDefined()
086fd843
JB
2184 expect(
2185 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2186 workerChoiceStrategy
2187 ).workerNodeId
2188 ).toBeDefined()
8c3ec188
JB
2189 expect(
2190 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2191 workerChoiceStrategy
9b106837 2192 ).nextWorkerNodeKey
8c3ec188 2193 ).toBeDefined()
086fd843
JB
2194 expect(
2195 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2196 workerChoiceStrategy
2197 ).previousWorkerNodeKey
2198 ).toBeDefined()
8c3ec188
JB
2199 expect(
2200 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2201 workerChoiceStrategy
2202 ).defaultWorkerWeight
2203 ).toBeDefined()
2204 expect(
2205 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2206 workerChoiceStrategy
2207 ).roundWeights
2208 ).toBeDefined()
2209 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
2210 expect(
2211 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
086fd843 2212 pool.workerChoiceStrategyContext.workerChoiceStrategy
d33be430 2213 ).roundId
8c3ec188 2214 ).toBe(0)
086fd843
JB
2215 expect(
2216 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2217 pool.workerChoiceStrategyContext.workerChoiceStrategy
2218 ).workerNodeId
2219 ).toBe(0)
8c3ec188
JB
2220 expect(
2221 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2222 pool.workerChoiceStrategyContext.workerChoiceStrategy
9b106837 2223 ).nextWorkerNodeKey
8c3ec188 2224 ).toBe(0)
086fd843
JB
2225 expect(
2226 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2227 pool.workerChoiceStrategyContext.workerChoiceStrategy
2228 ).previousWorkerNodeKey
2229 ).toBe(0)
8c3ec188
JB
2230 expect(
2231 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2232 pool.workerChoiceStrategyContext.workerChoiceStrategy
2233 ).defaultWorkerWeight
2234 ).toBeGreaterThan(0)
2235 expect(
2236 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
086fd843 2237 pool.workerChoiceStrategyContext.workerChoiceStrategy
8c3ec188
JB
2238 ).roundWeights
2239 ).toStrictEqual([
2240 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2241 pool.workerChoiceStrategyContext.workerChoiceStrategy
2242 ).defaultWorkerWeight
2243 ])
2244 await pool.destroy()
2245 pool = new DynamicThreadPool(
2246 min,
2247 max,
b2fd3f4a 2248 './tests/worker-files/thread/testWorker.mjs'
8c3ec188
JB
2249 )
2250 expect(
2251 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2252 workerChoiceStrategy
d33be430 2253 ).roundId
8c3ec188 2254 ).toBeDefined()
086fd843
JB
2255 expect(
2256 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2257 workerChoiceStrategy
2258 ).workerNodeId
2259 ).toBeDefined()
8c3ec188
JB
2260 expect(
2261 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2262 workerChoiceStrategy
9b106837 2263 ).nextWorkerNodeKey
8c3ec188 2264 ).toBeDefined()
086fd843
JB
2265 expect(
2266 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2267 workerChoiceStrategy
2268 ).previousWorkerNodeKey
2269 ).toBeDefined()
8c3ec188
JB
2270 expect(
2271 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2272 workerChoiceStrategy
2273 ).defaultWorkerWeight
2274 ).toBeDefined()
2275 expect(
2276 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2277 workerChoiceStrategy
2278 ).roundWeights
2279 ).toBeDefined()
2280 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
086fd843
JB
2281 expect(
2282 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2283 pool.workerChoiceStrategyContext.workerChoiceStrategy
2284 ).roundId
2285 ).toBe(0)
2286 expect(
2287 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2288 pool.workerChoiceStrategyContext.workerChoiceStrategy
2289 ).workerNodeId
2290 ).toBe(0)
8c3ec188
JB
2291 expect(
2292 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2293 pool.workerChoiceStrategyContext.workerChoiceStrategy
9b106837 2294 ).nextWorkerNodeKey
8c3ec188 2295 ).toBe(0)
086fd843
JB
2296 expect(
2297 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2298 pool.workerChoiceStrategyContext.workerChoiceStrategy
2299 ).previousWorkerNodeKey
2300 ).toBe(0)
8c3ec188
JB
2301 expect(
2302 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2303 pool.workerChoiceStrategyContext.workerChoiceStrategy
2304 ).defaultWorkerWeight
2305 ).toBeGreaterThan(0)
2306 expect(
2307 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
086fd843 2308 pool.workerChoiceStrategyContext.workerChoiceStrategy
8c3ec188
JB
2309 ).roundWeights
2310 ).toStrictEqual([
2311 pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
2312 pool.workerChoiceStrategyContext.workerChoiceStrategy
2313 ).defaultWorkerWeight
2314 ])
2315 // We need to clean up the resources after our test
2316 await pool.destroy()
2317 })
2318
89b09b26 2319 it('Verify unknown strategy throw error', () => {
a35560ba
S
2320 expect(
2321 () =>
2322 new DynamicThreadPool(
2323 min,
2324 max,
b2fd3f4a 2325 './tests/worker-files/thread/testWorker.mjs',
1927ee67 2326 { workerChoiceStrategy: 'UNKNOWN_STRATEGY' }
a35560ba 2327 )
948faff7 2328 ).toThrow("Invalid worker choice strategy 'UNKNOWN_STRATEGY'")
a35560ba
S
2329 })
2330})