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