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