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