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