Commit | Line | Data |
---|---|---|
a61a0724 | 1 | const { expect } = require('expect') |
a35560ba S |
2 | const { |
3 | WorkerChoiceStrategies, | |
4 | DynamicThreadPool, | |
2ced693a JB |
5 | FixedThreadPool, |
6 | FixedClusterPool | |
15d56315 | 7 | } = require('../../../lib/index') |
a35560ba S |
8 | |
9 | describe('Selection strategies test suite', () => { | |
e1ffb94f JB |
10 | const min = 0 |
11 | const max = 3 | |
12 | ||
a35560ba S |
13 | it('Verify that WorkerChoiceStrategies enumeration provides string values', () => { |
14 | expect(WorkerChoiceStrategies.ROUND_ROBIN).toBe('ROUND_ROBIN') | |
737c6d97 | 15 | expect(WorkerChoiceStrategies.LESS_USED).toBe('LESS_USED') |
168c526f | 16 | expect(WorkerChoiceStrategies.LESS_BUSY).toBe('LESS_BUSY') |
23ff945a | 17 | expect(WorkerChoiceStrategies.FAIR_SHARE).toBe('FAIR_SHARE') |
b3432a63 JB |
18 | expect(WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN).toBe( |
19 | 'WEIGHTED_ROUND_ROBIN' | |
20 | ) | |
a35560ba S |
21 | }) |
22 | ||
e843b904 | 23 | it('Verify ROUND_ROBIN strategy is the default at pool creation', async () => { |
e843b904 JB |
24 | const pool = new DynamicThreadPool( |
25 | min, | |
26 | max, | |
27 | './tests/worker-files/thread/testWorker.js' | |
28 | ) | |
29 | expect(pool.opts.workerChoiceStrategy).toBe( | |
30 | WorkerChoiceStrategies.ROUND_ROBIN | |
31 | ) | |
32 | // We need to clean up the resources after our test | |
33 | await pool.destroy() | |
34 | }) | |
35 | ||
594bfb84 JB |
36 | it('Verify available strategies are taken at pool creation', async () => { |
37 | for (const workerChoiceStrategy of Object.values(WorkerChoiceStrategies)) { | |
38 | const pool = new FixedThreadPool( | |
39 | max, | |
40 | './tests/worker-files/thread/testWorker.js', | |
41 | { workerChoiceStrategy } | |
42 | ) | |
43 | expect(pool.opts.workerChoiceStrategy).toBe(workerChoiceStrategy) | |
44 | expect(pool.workerChoiceStrategyContext.workerChoiceStrategy).toBe( | |
45 | workerChoiceStrategy | |
46 | ) | |
47 | await pool.destroy() | |
48 | } | |
d2f7b7a2 JB |
49 | }) |
50 | ||
594bfb84 JB |
51 | it('Verify available strategies can be set after pool creation', async () => { |
52 | for (const workerChoiceStrategy of Object.values(WorkerChoiceStrategies)) { | |
53 | const pool = new DynamicThreadPool( | |
54 | min, | |
55 | max, | |
ec82cfa1 | 56 | './tests/worker-files/thread/testWorker.js' |
594bfb84 JB |
57 | ) |
58 | pool.setWorkerChoiceStrategy(workerChoiceStrategy) | |
59 | expect(pool.opts.workerChoiceStrategy).toBe(workerChoiceStrategy) | |
60 | expect(pool.workerChoiceStrategyContext.workerChoiceStrategy).toBe( | |
61 | workerChoiceStrategy | |
62 | ) | |
63 | await pool.destroy() | |
64 | } | |
65 | }) | |
66 | ||
67 | it('Verify available strategies default internals at pool creation', async () => { | |
68 | const pool = new FixedThreadPool( | |
e843b904 JB |
69 | max, |
70 | './tests/worker-files/thread/testWorker.js' | |
71 | ) | |
594bfb84 JB |
72 | for (const workerChoiceStrategy of Object.values(WorkerChoiceStrategies)) { |
73 | if (workerChoiceStrategy === WorkerChoiceStrategies.ROUND_ROBIN) { | |
74 | expect( | |
75 | pool.workerChoiceStrategyContext.workerChoiceStrategies.get( | |
76 | workerChoiceStrategy | |
77 | ).nextWorkerNodeId | |
78 | ).toBe(0) | |
79 | } else if (workerChoiceStrategy === WorkerChoiceStrategies.FAIR_SHARE) { | |
80 | for (const workerNodeKey of pool.workerChoiceStrategyContext.workerChoiceStrategies | |
81 | .get(workerChoiceStrategy) | |
82 | .workerLastVirtualTaskTimestamp.keys()) { | |
83 | expect( | |
84 | pool.workerChoiceStrategyContext.workerChoiceStrategies | |
85 | .get(workerChoiceStrategy) | |
86 | .workerLastVirtualTaskTimestamp.get(workerNodeKey).start | |
87 | ).toBe(0) | |
88 | expect( | |
89 | pool.workerChoiceStrategyContext.workerChoiceStrategies | |
90 | .get(workerChoiceStrategy) | |
91 | .workerLastVirtualTaskTimestamp.get(workerNodeKey).end | |
92 | ).toBe(0) | |
93 | } | |
94 | } else if ( | |
95 | workerChoiceStrategy === WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN | |
96 | ) { | |
97 | expect( | |
98 | pool.workerChoiceStrategyContext.workerChoiceStrategies.get( | |
99 | workerChoiceStrategy | |
100 | ).currentWorkerNodeId | |
101 | ).toBe(0) | |
102 | expect( | |
103 | pool.workerChoiceStrategyContext.workerChoiceStrategies.get( | |
104 | workerChoiceStrategy | |
105 | ).defaultWorkerWeight | |
106 | ).toBeGreaterThan(0) | |
107 | for (const workerNodeKey of pool.workerChoiceStrategyContext.workerChoiceStrategies | |
108 | .get(workerChoiceStrategy) | |
109 | .workersTaskRunTime.keys()) { | |
110 | expect( | |
111 | pool.workerChoiceStrategyContext.workerChoiceStrategies | |
112 | .get(workerChoiceStrategy) | |
113 | .workersTaskRunTime.get(workerNodeKey).weight | |
114 | ).toBeGreaterThan(0) | |
115 | expect( | |
116 | pool.workerChoiceStrategyContext.workerChoiceStrategies | |
117 | .get(workerChoiceStrategy) | |
118 | .workersTaskRunTime.get(workerNodeKey).runTime | |
119 | ).toBe(0) | |
120 | } | |
121 | } | |
122 | } | |
e843b904 JB |
123 | await pool.destroy() |
124 | }) | |
125 | ||
10fcfaf4 | 126 | it('Verify ROUND_ROBIN strategy default tasks usage statistics requirements', async () => { |
594bfb84 | 127 | const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN |
10fcfaf4 JB |
128 | let pool = new FixedThreadPool( |
129 | max, | |
d710242d | 130 | './tests/worker-files/thread/testWorker.js', |
594bfb84 | 131 | { workerChoiceStrategy } |
10fcfaf4 | 132 | ) |
10fcfaf4 | 133 | expect( |
97a2abc3 | 134 | pool.workerChoiceStrategyContext.getRequiredStatistics().runTime |
10fcfaf4 | 135 | ).toBe(false) |
c6bd2650 JB |
136 | expect( |
137 | pool.workerChoiceStrategyContext.getRequiredStatistics().avgRunTime | |
138 | ).toBe(false) | |
78099a15 JB |
139 | expect( |
140 | pool.workerChoiceStrategyContext.getRequiredStatistics().medRunTime | |
141 | ).toBe(false) | |
fd7ebd49 | 142 | await pool.destroy() |
10fcfaf4 JB |
143 | pool = new DynamicThreadPool( |
144 | min, | |
145 | max, | |
d710242d | 146 | './tests/worker-files/thread/testWorker.js', |
594bfb84 | 147 | { workerChoiceStrategy } |
10fcfaf4 | 148 | ) |
10fcfaf4 | 149 | expect( |
97a2abc3 | 150 | pool.workerChoiceStrategyContext.getRequiredStatistics().runTime |
10fcfaf4 | 151 | ).toBe(false) |
c6bd2650 JB |
152 | expect( |
153 | pool.workerChoiceStrategyContext.getRequiredStatistics().avgRunTime | |
154 | ).toBe(false) | |
78099a15 JB |
155 | expect( |
156 | pool.workerChoiceStrategyContext.getRequiredStatistics().medRunTime | |
157 | ).toBe(false) | |
10fcfaf4 JB |
158 | // We need to clean up the resources after our test |
159 | await pool.destroy() | |
160 | }) | |
161 | ||
bdaf31cd | 162 | it('Verify ROUND_ROBIN strategy can be run in a fixed pool', async () => { |
bdaf31cd JB |
163 | const pool = new FixedThreadPool( |
164 | max, | |
165 | './tests/worker-files/thread/testWorker.js', | |
166 | { workerChoiceStrategy: WorkerChoiceStrategies.ROUND_ROBIN } | |
167 | ) | |
bdaf31cd JB |
168 | // TODO: Create a better test to cover `RoundRobinWorkerChoiceStrategy#choose` |
169 | const promises = [] | |
a20f0ba5 JB |
170 | const maxMultiplier = 2 |
171 | for (let i = 0; i < max * maxMultiplier; i++) { | |
6db75ad9 | 172 | promises.push(pool.execute()) |
bdaf31cd JB |
173 | } |
174 | await Promise.all(promises) | |
175 | // We need to clean up the resources after our test | |
176 | await pool.destroy() | |
177 | }) | |
178 | ||
179 | it('Verify ROUND_ROBIN strategy can be run in a dynamic pool', async () => { | |
bdaf31cd JB |
180 | const pool = new DynamicThreadPool( |
181 | min, | |
182 | max, | |
183 | './tests/worker-files/thread/testWorker.js', | |
184 | { workerChoiceStrategy: WorkerChoiceStrategies.ROUND_ROBIN } | |
185 | ) | |
bdaf31cd JB |
186 | // TODO: Create a better test to cover `RoundRobinWorkerChoiceStrategy#choose` |
187 | const promises = [] | |
a20f0ba5 JB |
188 | const maxMultiplier = 2 |
189 | for (let i = 0; i < max * maxMultiplier; i++) { | |
6db75ad9 | 190 | promises.push(pool.execute()) |
bdaf31cd JB |
191 | } |
192 | await Promise.all(promises) | |
193 | // We need to clean up the resources after our test | |
194 | await pool.destroy() | |
195 | }) | |
196 | ||
2ced693a | 197 | it('Verify ROUND_ROBIN strategy runtime behavior', async () => { |
594bfb84 | 198 | const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN |
2ced693a JB |
199 | let pool = new FixedClusterPool( |
200 | max, | |
594bfb84 JB |
201 | './tests/worker-files/cluster/testWorker.js', |
202 | { workerChoiceStrategy } | |
2ced693a JB |
203 | ) |
204 | let results = new Set() | |
205 | for (let i = 0; i < max; i++) { | |
adc3c320 | 206 | results.add(pool.chooseWorkerNode()[1].worker.id) |
2ced693a JB |
207 | } |
208 | expect(results.size).toBe(max) | |
209 | await pool.destroy() | |
594bfb84 JB |
210 | pool = new FixedThreadPool( |
211 | max, | |
212 | './tests/worker-files/thread/testWorker.js', | |
213 | { workerChoiceStrategy } | |
214 | ) | |
2ced693a JB |
215 | results = new Set() |
216 | for (let i = 0; i < max; i++) { | |
adc3c320 | 217 | results.add(pool.chooseWorkerNode()[1].worker.threadId) |
2ced693a JB |
218 | } |
219 | expect(results.size).toBe(max) | |
220 | await pool.destroy() | |
221 | }) | |
222 | ||
a6f7f1b4 | 223 | it('Verify ROUND_ROBIN strategy internals are resets after setting it', async () => { |
594bfb84 | 224 | const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN |
a6f7f1b4 JB |
225 | let pool = new FixedThreadPool( |
226 | max, | |
227 | './tests/worker-files/thread/testWorker.js', | |
228 | { workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN } | |
229 | ) | |
38f6e859 | 230 | expect( |
95c83464 | 231 | pool.workerChoiceStrategyContext.workerChoiceStrategies.get( |
594bfb84 | 232 | workerChoiceStrategy |
f06e48d8 | 233 | ).nextWorkerNodeId |
b529c323 | 234 | ).toBeDefined() |
594bfb84 | 235 | pool.setWorkerChoiceStrategy(workerChoiceStrategy) |
a6f7f1b4 | 236 | expect( |
95c83464 | 237 | pool.workerChoiceStrategyContext.workerChoiceStrategies.get( |
d710242d | 238 | pool.workerChoiceStrategyContext.workerChoiceStrategy |
f06e48d8 | 239 | ).nextWorkerNodeId |
a6f7f1b4 JB |
240 | ).toBe(0) |
241 | await pool.destroy() | |
242 | pool = new DynamicThreadPool( | |
243 | min, | |
244 | max, | |
245 | './tests/worker-files/thread/testWorker.js', | |
246 | { workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN } | |
247 | ) | |
38f6e859 | 248 | expect( |
95c83464 | 249 | pool.workerChoiceStrategyContext.workerChoiceStrategies.get( |
594bfb84 | 250 | workerChoiceStrategy |
f06e48d8 | 251 | ).nextWorkerNodeId |
b529c323 | 252 | ).toBeDefined() |
594bfb84 | 253 | pool.setWorkerChoiceStrategy(workerChoiceStrategy) |
a6f7f1b4 | 254 | expect( |
95c83464 | 255 | pool.workerChoiceStrategyContext.workerChoiceStrategies.get( |
d710242d | 256 | pool.workerChoiceStrategyContext.workerChoiceStrategy |
f06e48d8 | 257 | ).nextWorkerNodeId |
a6f7f1b4 JB |
258 | ).toBe(0) |
259 | // We need to clean up the resources after our test | |
260 | await pool.destroy() | |
261 | }) | |
262 | ||
737c6d97 | 263 | it('Verify LESS_USED strategy default tasks usage statistics requirements', async () => { |
594bfb84 | 264 | const workerChoiceStrategy = WorkerChoiceStrategies.LESS_USED |
10fcfaf4 JB |
265 | let pool = new FixedThreadPool( |
266 | max, | |
d710242d | 267 | './tests/worker-files/thread/testWorker.js', |
594bfb84 | 268 | { workerChoiceStrategy } |
10fcfaf4 | 269 | ) |
10fcfaf4 | 270 | expect( |
97a2abc3 | 271 | pool.workerChoiceStrategyContext.getRequiredStatistics().runTime |
10fcfaf4 | 272 | ).toBe(false) |
c6bd2650 JB |
273 | expect( |
274 | pool.workerChoiceStrategyContext.getRequiredStatistics().avgRunTime | |
275 | ).toBe(false) | |
78099a15 JB |
276 | expect( |
277 | pool.workerChoiceStrategyContext.getRequiredStatistics().medRunTime | |
278 | ).toBe(false) | |
fd7ebd49 | 279 | await pool.destroy() |
10fcfaf4 JB |
280 | pool = new DynamicThreadPool( |
281 | min, | |
282 | max, | |
d710242d | 283 | './tests/worker-files/thread/testWorker.js', |
594bfb84 | 284 | { workerChoiceStrategy } |
10fcfaf4 | 285 | ) |
10fcfaf4 | 286 | expect( |
97a2abc3 | 287 | pool.workerChoiceStrategyContext.getRequiredStatistics().runTime |
10fcfaf4 | 288 | ).toBe(false) |
c6bd2650 JB |
289 | expect( |
290 | pool.workerChoiceStrategyContext.getRequiredStatistics().avgRunTime | |
291 | ).toBe(false) | |
78099a15 JB |
292 | expect( |
293 | pool.workerChoiceStrategyContext.getRequiredStatistics().medRunTime | |
294 | ).toBe(false) | |
10fcfaf4 JB |
295 | // We need to clean up the resources after our test |
296 | await pool.destroy() | |
297 | }) | |
298 | ||
737c6d97 | 299 | it('Verify LESS_USED strategy can be run in a fixed pool', async () => { |
b98ec2e6 JB |
300 | const pool = new FixedThreadPool( |
301 | max, | |
302 | './tests/worker-files/thread/testWorker.js', | |
737c6d97 | 303 | { workerChoiceStrategy: WorkerChoiceStrategies.LESS_USED } |
b98ec2e6 | 304 | ) |
168c526f | 305 | // TODO: Create a better test to cover `LessUsedWorkerChoiceStrategy#choose` |
a35560ba | 306 | const promises = [] |
a20f0ba5 JB |
307 | const maxMultiplier = 2 |
308 | for (let i = 0; i < max * maxMultiplier; i++) { | |
6db75ad9 | 309 | promises.push(pool.execute()) |
a35560ba S |
310 | } |
311 | await Promise.all(promises) | |
a35560ba S |
312 | // We need to clean up the resources after our test |
313 | await pool.destroy() | |
314 | }) | |
315 | ||
737c6d97 | 316 | it('Verify LESS_USED strategy can be run in a dynamic pool', async () => { |
ff5e76e1 JB |
317 | const pool = new DynamicThreadPool( |
318 | min, | |
319 | max, | |
320 | './tests/worker-files/thread/testWorker.js', | |
737c6d97 | 321 | { workerChoiceStrategy: WorkerChoiceStrategies.LESS_USED } |
ff5e76e1 | 322 | ) |
168c526f JB |
323 | // TODO: Create a better test to cover `LessUsedWorkerChoiceStrategy#choose` |
324 | const promises = [] | |
a20f0ba5 JB |
325 | const maxMultiplier = 2 |
326 | for (let i = 0; i < max * maxMultiplier; i++) { | |
168c526f JB |
327 | promises.push(pool.execute()) |
328 | } | |
329 | await Promise.all(promises) | |
330 | // We need to clean up the resources after our test | |
331 | await pool.destroy() | |
332 | }) | |
333 | ||
168c526f | 334 | it('Verify LESS_BUSY strategy default tasks usage statistics requirements', async () => { |
594bfb84 | 335 | const workerChoiceStrategy = WorkerChoiceStrategies.LESS_BUSY |
168c526f JB |
336 | let pool = new FixedThreadPool( |
337 | max, | |
d710242d | 338 | './tests/worker-files/thread/testWorker.js', |
594bfb84 | 339 | { workerChoiceStrategy } |
168c526f | 340 | ) |
168c526f | 341 | expect( |
97a2abc3 | 342 | pool.workerChoiceStrategyContext.getRequiredStatistics().runTime |
168c526f | 343 | ).toBe(true) |
c6bd2650 JB |
344 | expect( |
345 | pool.workerChoiceStrategyContext.getRequiredStatistics().avgRunTime | |
346 | ).toBe(false) | |
78099a15 JB |
347 | expect( |
348 | pool.workerChoiceStrategyContext.getRequiredStatistics().medRunTime | |
349 | ).toBe(false) | |
168c526f JB |
350 | await pool.destroy() |
351 | pool = new DynamicThreadPool( | |
352 | min, | |
353 | max, | |
d710242d | 354 | './tests/worker-files/thread/testWorker.js', |
594bfb84 | 355 | { workerChoiceStrategy } |
168c526f | 356 | ) |
168c526f | 357 | expect( |
97a2abc3 | 358 | pool.workerChoiceStrategyContext.getRequiredStatistics().runTime |
168c526f | 359 | ).toBe(true) |
c6bd2650 JB |
360 | expect( |
361 | pool.workerChoiceStrategyContext.getRequiredStatistics().avgRunTime | |
362 | ).toBe(false) | |
78099a15 JB |
363 | expect( |
364 | pool.workerChoiceStrategyContext.getRequiredStatistics().medRunTime | |
365 | ).toBe(false) | |
168c526f JB |
366 | // We need to clean up the resources after our test |
367 | await pool.destroy() | |
368 | }) | |
369 | ||
370 | it('Verify LESS_BUSY strategy can be run in a fixed pool', async () => { | |
371 | const pool = new FixedThreadPool( | |
372 | max, | |
373 | './tests/worker-files/thread/testWorker.js', | |
374 | { workerChoiceStrategy: WorkerChoiceStrategies.LESS_BUSY } | |
375 | ) | |
376 | // TODO: Create a better test to cover `LessBusyWorkerChoiceStrategy#choose` | |
377 | const promises = [] | |
a20f0ba5 JB |
378 | const maxMultiplier = 2 |
379 | for (let i = 0; i < max * maxMultiplier; i++) { | |
168c526f JB |
380 | promises.push(pool.execute()) |
381 | } | |
382 | await Promise.all(promises) | |
383 | // We need to clean up the resources after our test | |
384 | await pool.destroy() | |
385 | }) | |
386 | ||
387 | it('Verify LESS_BUSY strategy can be run in a dynamic pool', async () => { | |
388 | const pool = new DynamicThreadPool( | |
389 | min, | |
390 | max, | |
391 | './tests/worker-files/thread/testWorker.js', | |
392 | { workerChoiceStrategy: WorkerChoiceStrategies.LESS_BUSY } | |
393 | ) | |
394 | // TODO: Create a better test to cover `LessBusyWorkerChoiceStrategy#choose` | |
ff5e76e1 | 395 | const promises = [] |
a20f0ba5 JB |
396 | const maxMultiplier = 2 |
397 | for (let i = 0; i < max * maxMultiplier; i++) { | |
6db75ad9 | 398 | promises.push(pool.execute()) |
ff5e76e1 JB |
399 | } |
400 | await Promise.all(promises) | |
ff5e76e1 JB |
401 | // We need to clean up the resources after our test |
402 | await pool.destroy() | |
403 | }) | |
404 | ||
10fcfaf4 | 405 | it('Verify FAIR_SHARE strategy default tasks usage statistics requirements', async () => { |
594bfb84 | 406 | const workerChoiceStrategy = WorkerChoiceStrategies.FAIR_SHARE |
10fcfaf4 JB |
407 | let pool = new FixedThreadPool( |
408 | max, | |
d710242d | 409 | './tests/worker-files/thread/testWorker.js', |
594bfb84 | 410 | { workerChoiceStrategy } |
10fcfaf4 | 411 | ) |
10fcfaf4 | 412 | expect( |
97a2abc3 | 413 | pool.workerChoiceStrategyContext.getRequiredStatistics().runTime |
10fcfaf4 | 414 | ).toBe(true) |
c6bd2650 JB |
415 | expect( |
416 | pool.workerChoiceStrategyContext.getRequiredStatistics().avgRunTime | |
417 | ).toBe(true) | |
78099a15 JB |
418 | expect( |
419 | pool.workerChoiceStrategyContext.getRequiredStatistics().medRunTime | |
420 | ).toBe(false) | |
fd7ebd49 | 421 | await pool.destroy() |
10fcfaf4 JB |
422 | pool = new DynamicThreadPool( |
423 | min, | |
424 | max, | |
d710242d | 425 | './tests/worker-files/thread/testWorker.js', |
594bfb84 | 426 | { workerChoiceStrategy } |
10fcfaf4 | 427 | ) |
10fcfaf4 | 428 | expect( |
97a2abc3 | 429 | pool.workerChoiceStrategyContext.getRequiredStatistics().runTime |
10fcfaf4 | 430 | ).toBe(true) |
c6bd2650 JB |
431 | expect( |
432 | pool.workerChoiceStrategyContext.getRequiredStatistics().avgRunTime | |
433 | ).toBe(true) | |
78099a15 JB |
434 | expect( |
435 | pool.workerChoiceStrategyContext.getRequiredStatistics().medRunTime | |
436 | ).toBe(false) | |
10fcfaf4 JB |
437 | // We need to clean up the resources after our test |
438 | await pool.destroy() | |
439 | }) | |
440 | ||
23ff945a | 441 | it('Verify FAIR_SHARE strategy can be run in a fixed pool', async () => { |
23ff945a JB |
442 | const pool = new FixedThreadPool( |
443 | max, | |
444 | './tests/worker-files/thread/testWorker.js', | |
445 | { workerChoiceStrategy: WorkerChoiceStrategies.FAIR_SHARE } | |
446 | ) | |
447 | // TODO: Create a better test to cover `FairShareChoiceStrategy#choose` | |
448 | const promises = [] | |
a20f0ba5 JB |
449 | const maxMultiplier = 2 |
450 | for (let i = 0; i < max * maxMultiplier; i++) { | |
6db75ad9 | 451 | promises.push(pool.execute()) |
23ff945a JB |
452 | } |
453 | await Promise.all(promises) | |
97a2abc3 | 454 | expect( |
95c83464 | 455 | pool.workerChoiceStrategyContext.workerChoiceStrategies.get( |
d710242d | 456 | pool.workerChoiceStrategyContext.workerChoiceStrategy |
95c83464 | 457 | ).workerLastVirtualTaskTimestamp.size |
f06e48d8 | 458 | ).toBe(pool.workerNodes.length) |
23ff945a JB |
459 | // We need to clean up the resources after our test |
460 | await pool.destroy() | |
461 | }) | |
462 | ||
463 | it('Verify FAIR_SHARE strategy can be run in a dynamic pool', async () => { | |
23ff945a JB |
464 | const pool = new DynamicThreadPool( |
465 | min, | |
466 | max, | |
467 | './tests/worker-files/thread/testWorker.js', | |
468 | { workerChoiceStrategy: WorkerChoiceStrategies.FAIR_SHARE } | |
469 | ) | |
470 | // TODO: Create a better test to cover `FairShareChoiceStrategy#choose` | |
471 | const promises = [] | |
f7070eee | 472 | const maxMultiplier = 2 |
804a889e | 473 | for (let i = 0; i < max * maxMultiplier; i++) { |
6db75ad9 | 474 | promises.push(pool.execute()) |
23ff945a JB |
475 | } |
476 | await Promise.all(promises) | |
f7070eee JB |
477 | // if (process.platform !== 'win32') { |
478 | // expect( | |
95c83464 | 479 | // pool.workerChoiceStrategyContext.workerChoiceStrategies.get( |
d710242d | 480 | // pool.workerChoiceStrategyContext.workerChoiceStrategy |
95c83464 | 481 | // ).workerLastVirtualTaskTimestamp.size |
f06e48d8 | 482 | // ).toBe(pool.workerNodes.length) |
f7070eee | 483 | // } |
23ff945a JB |
484 | // We need to clean up the resources after our test |
485 | await pool.destroy() | |
486 | }) | |
487 | ||
010d7020 JB |
488 | it('Verify FAIR_SHARE strategy can be run in a dynamic pool with median run time statistic', async () => { |
489 | const pool = new DynamicThreadPool( | |
490 | min, | |
491 | max, | |
492 | './tests/worker-files/thread/testWorker.js', | |
493 | { | |
494 | workerChoiceStrategy: WorkerChoiceStrategies.FAIR_SHARE, | |
495 | workerChoiceStrategyOptions: { | |
496 | medRunTime: true | |
497 | } | |
498 | } | |
499 | ) | |
500 | // TODO: Create a better test to cover `FairShareChoiceStrategy#choose` | |
501 | const promises = [] | |
502 | const maxMultiplier = 2 | |
503 | for (let i = 0; i < max * maxMultiplier; i++) { | |
504 | promises.push(pool.execute()) | |
505 | } | |
506 | await Promise.all(promises) | |
507 | for (const workerNode of pool.workerNodes) { | |
508 | expect(workerNode.tasksUsage.avgRunTime).toBeDefined() | |
509 | expect(workerNode.tasksUsage.avgRunTime).toBe(0) | |
510 | expect(workerNode.tasksUsage.medRunTime).toBeDefined() | |
511 | expect(workerNode.tasksUsage.medRunTime).toBeGreaterThan(0) | |
512 | } | |
513 | // if (process.platform !== 'win32') { | |
514 | // expect( | |
515 | // pool.workerChoiceStrategyContext.workerChoiceStrategies.get( | |
516 | // pool.workerChoiceStrategyContext.workerChoiceStrategy | |
517 | // ).workerLastVirtualTaskTimestamp.size | |
518 | // ).toBe(pool.workerNodes.length) | |
519 | // } | |
520 | // We need to clean up the resources after our test | |
521 | await pool.destroy() | |
522 | }) | |
523 | ||
a6f7f1b4 | 524 | it('Verify FAIR_SHARE strategy internals are resets after setting it', async () => { |
594bfb84 | 525 | const workerChoiceStrategy = WorkerChoiceStrategies.FAIR_SHARE |
f0829c53 | 526 | let pool = new FixedThreadPool( |
caeb9817 JB |
527 | max, |
528 | './tests/worker-files/thread/testWorker.js' | |
529 | ) | |
530 | expect( | |
95c83464 | 531 | pool.workerChoiceStrategyContext.workerChoiceStrategies.get( |
594bfb84 | 532 | workerChoiceStrategy |
b529c323 JB |
533 | ).workerLastVirtualTaskTimestamp |
534 | ).toBeDefined() | |
594bfb84 | 535 | pool.setWorkerChoiceStrategy(workerChoiceStrategy) |
f06e48d8 | 536 | for (const workerNodeKey of pool.workerChoiceStrategyContext.workerChoiceStrategies |
d710242d | 537 | .get(pool.workerChoiceStrategyContext.workerChoiceStrategy) |
95c83464 | 538 | .workerLastVirtualTaskTimestamp.keys()) { |
caeb9817 | 539 | expect( |
95c83464 | 540 | pool.workerChoiceStrategyContext.workerChoiceStrategies |
d710242d | 541 | .get(pool.workerChoiceStrategyContext.workerChoiceStrategy) |
f06e48d8 | 542 | .workerLastVirtualTaskTimestamp.get(workerNodeKey).start |
caeb9817 JB |
543 | ).toBe(0) |
544 | expect( | |
95c83464 | 545 | pool.workerChoiceStrategyContext.workerChoiceStrategies |
d710242d | 546 | .get(pool.workerChoiceStrategyContext.workerChoiceStrategy) |
f06e48d8 | 547 | .workerLastVirtualTaskTimestamp.get(workerNodeKey).end |
caeb9817 JB |
548 | ).toBe(0) |
549 | } | |
f0829c53 JB |
550 | await pool.destroy() |
551 | pool = new DynamicThreadPool( | |
552 | min, | |
553 | max, | |
554 | './tests/worker-files/thread/testWorker.js' | |
555 | ) | |
556 | expect( | |
95c83464 | 557 | pool.workerChoiceStrategyContext.workerChoiceStrategies.get( |
594bfb84 | 558 | workerChoiceStrategy |
b529c323 JB |
559 | ).workerLastVirtualTaskTimestamp |
560 | ).toBeDefined() | |
594bfb84 | 561 | pool.setWorkerChoiceStrategy(workerChoiceStrategy) |
f06e48d8 | 562 | for (const workerNodeKey of pool.workerChoiceStrategyContext.workerChoiceStrategies |
d710242d | 563 | .get(pool.workerChoiceStrategyContext.workerChoiceStrategy) |
95c83464 | 564 | .workerLastVirtualTaskTimestamp.keys()) { |
f0829c53 | 565 | expect( |
95c83464 | 566 | pool.workerChoiceStrategyContext.workerChoiceStrategies |
d710242d | 567 | .get(pool.workerChoiceStrategyContext.workerChoiceStrategy) |
f06e48d8 | 568 | .workerLastVirtualTaskTimestamp.get(workerNodeKey).start |
f0829c53 JB |
569 | ).toBe(0) |
570 | expect( | |
95c83464 | 571 | pool.workerChoiceStrategyContext.workerChoiceStrategies |
d710242d | 572 | .get(pool.workerChoiceStrategyContext.workerChoiceStrategy) |
f06e48d8 | 573 | .workerLastVirtualTaskTimestamp.get(workerNodeKey).end |
f0829c53 JB |
574 | ).toBe(0) |
575 | } | |
caeb9817 JB |
576 | // We need to clean up the resources after our test |
577 | await pool.destroy() | |
578 | }) | |
579 | ||
10fcfaf4 | 580 | it('Verify WEIGHTED_ROUND_ROBIN strategy default tasks usage statistics requirements', async () => { |
594bfb84 | 581 | const workerChoiceStrategy = WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN |
10fcfaf4 JB |
582 | let pool = new FixedThreadPool( |
583 | max, | |
d710242d | 584 | './tests/worker-files/thread/testWorker.js', |
594bfb84 | 585 | { workerChoiceStrategy } |
10fcfaf4 | 586 | ) |
10fcfaf4 | 587 | expect( |
97a2abc3 | 588 | pool.workerChoiceStrategyContext.getRequiredStatistics().runTime |
10fcfaf4 | 589 | ).toBe(true) |
c6bd2650 JB |
590 | expect( |
591 | pool.workerChoiceStrategyContext.getRequiredStatistics().avgRunTime | |
592 | ).toBe(true) | |
78099a15 JB |
593 | expect( |
594 | pool.workerChoiceStrategyContext.getRequiredStatistics().medRunTime | |
595 | ).toBe(false) | |
fd7ebd49 | 596 | await pool.destroy() |
10fcfaf4 JB |
597 | pool = new DynamicThreadPool( |
598 | min, | |
599 | max, | |
d710242d | 600 | './tests/worker-files/thread/testWorker.js', |
594bfb84 | 601 | { workerChoiceStrategy } |
10fcfaf4 | 602 | ) |
10fcfaf4 | 603 | expect( |
97a2abc3 | 604 | pool.workerChoiceStrategyContext.getRequiredStatistics().runTime |
10fcfaf4 | 605 | ).toBe(true) |
c6bd2650 JB |
606 | expect( |
607 | pool.workerChoiceStrategyContext.getRequiredStatistics().avgRunTime | |
608 | ).toBe(true) | |
78099a15 JB |
609 | expect( |
610 | pool.workerChoiceStrategyContext.getRequiredStatistics().medRunTime | |
611 | ).toBe(false) | |
10fcfaf4 JB |
612 | // We need to clean up the resources after our test |
613 | await pool.destroy() | |
614 | }) | |
615 | ||
b3432a63 | 616 | it('Verify WEIGHTED_ROUND_ROBIN strategy can be run in a fixed pool', async () => { |
b3432a63 JB |
617 | const pool = new FixedThreadPool( |
618 | max, | |
619 | './tests/worker-files/thread/testWorker.js', | |
620 | { workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN } | |
621 | ) | |
622 | // TODO: Create a better test to cover `WeightedRoundRobinWorkerChoiceStrategy#choose` | |
623 | const promises = [] | |
a20f0ba5 JB |
624 | const maxMultiplier = 2 |
625 | for (let i = 0; i < max * maxMultiplier; i++) { | |
6db75ad9 | 626 | promises.push(pool.execute()) |
b3432a63 JB |
627 | } |
628 | await Promise.all(promises) | |
97a2abc3 | 629 | expect( |
95c83464 | 630 | pool.workerChoiceStrategyContext.workerChoiceStrategies.get( |
d710242d | 631 | pool.workerChoiceStrategyContext.workerChoiceStrategy |
95c83464 | 632 | ).workersTaskRunTime.size |
f06e48d8 | 633 | ).toBe(pool.workerNodes.length) |
b3432a63 JB |
634 | // We need to clean up the resources after our test |
635 | await pool.destroy() | |
636 | }) | |
637 | ||
638 | it('Verify WEIGHTED_ROUND_ROBIN strategy can be run in a dynamic pool', async () => { | |
b3432a63 JB |
639 | const pool = new DynamicThreadPool( |
640 | min, | |
641 | max, | |
642 | './tests/worker-files/thread/testWorker.js', | |
643 | { workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN } | |
644 | ) | |
645 | // TODO: Create a better test to cover `WeightedRoundRobinWorkerChoiceStrategy#choose` | |
646 | const promises = [] | |
5502c07c | 647 | const maxMultiplier = |
95c83464 | 648 | pool.workerChoiceStrategyContext.workerChoiceStrategies.get( |
d710242d | 649 | pool.workerChoiceStrategyContext.workerChoiceStrategy |
8da9e84d | 650 | ).defaultWorkerWeight * 50 |
5502c07c | 651 | for (let i = 0; i < max * maxMultiplier; i++) { |
6db75ad9 | 652 | promises.push(pool.execute()) |
b3432a63 JB |
653 | } |
654 | await Promise.all(promises) | |
9f34a585 JB |
655 | if (process.platform !== 'win32') { |
656 | expect( | |
95c83464 | 657 | pool.workerChoiceStrategyContext.workerChoiceStrategies.get( |
d710242d | 658 | pool.workerChoiceStrategyContext.workerChoiceStrategy |
95c83464 | 659 | ).workersTaskRunTime.size |
f06e48d8 | 660 | ).toBe(pool.workerNodes.length) |
9f34a585 | 661 | } |
b3432a63 JB |
662 | // We need to clean up the resources after our test |
663 | await pool.destroy() | |
664 | }) | |
665 | ||
010d7020 JB |
666 | it('Verify WEIGHTED_ROUND_ROBIN strategy can be run in a dynamic pool with median run time statistic', async () => { |
667 | const pool = new DynamicThreadPool( | |
668 | min, | |
669 | max, | |
670 | './tests/worker-files/thread/testWorker.js', | |
671 | { | |
672 | workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN, | |
673 | workerChoiceStrategyOptions: { | |
674 | medRunTime: true | |
675 | } | |
676 | } | |
677 | ) | |
678 | // TODO: Create a better test to cover `WeightedRoundRobinWorkerChoiceStrategy#choose` | |
679 | const promises = [] | |
680 | const maxMultiplier = 2 | |
681 | for (let i = 0; i < max * maxMultiplier; i++) { | |
682 | promises.push(pool.execute()) | |
683 | } | |
684 | await Promise.all(promises) | |
685 | for (const workerNode of pool.workerNodes) { | |
686 | expect(workerNode.tasksUsage.avgRunTime).toBeDefined() | |
687 | expect(workerNode.tasksUsage.avgRunTime).toBe(0) | |
688 | expect(workerNode.tasksUsage.medRunTime).toBeDefined() | |
689 | expect(workerNode.tasksUsage.medRunTime).toBeGreaterThan(0) | |
690 | } | |
691 | // if (process.platform !== 'win32') { | |
692 | // expect( | |
693 | // pool.workerChoiceStrategyContext.workerChoiceStrategies.get( | |
694 | // pool.workerChoiceStrategyContext.workerChoiceStrategy | |
695 | // ).workersTaskRunTime.size | |
696 | // ).toBe(pool.workerNodes.length) | |
697 | // } | |
698 | // We need to clean up the resources after our test | |
699 | await pool.destroy() | |
700 | }) | |
701 | ||
a6f7f1b4 | 702 | it('Verify WEIGHTED_ROUND_ROBIN strategy internals are resets after setting it', async () => { |
594bfb84 | 703 | const workerChoiceStrategy = WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN |
f0829c53 | 704 | let pool = new FixedThreadPool( |
caeb9817 JB |
705 | max, |
706 | './tests/worker-files/thread/testWorker.js' | |
707 | ) | |
38f6e859 | 708 | expect( |
95c83464 | 709 | pool.workerChoiceStrategyContext.workerChoiceStrategies.get( |
594bfb84 | 710 | workerChoiceStrategy |
f06e48d8 | 711 | ).currentWorkerNodeId |
b529c323 | 712 | ).toBeDefined() |
38f6e859 | 713 | expect( |
95c83464 | 714 | pool.workerChoiceStrategyContext.workerChoiceStrategies.get( |
594bfb84 | 715 | workerChoiceStrategy |
b529c323 JB |
716 | ).defaultWorkerWeight |
717 | ).toBeDefined() | |
caeb9817 | 718 | expect( |
95c83464 | 719 | pool.workerChoiceStrategyContext.workerChoiceStrategies.get( |
594bfb84 | 720 | workerChoiceStrategy |
b529c323 JB |
721 | ).workersTaskRunTime |
722 | ).toBeDefined() | |
594bfb84 | 723 | pool.setWorkerChoiceStrategy(workerChoiceStrategy) |
a6f7f1b4 | 724 | expect( |
95c83464 | 725 | pool.workerChoiceStrategyContext.workerChoiceStrategies.get( |
d710242d | 726 | pool.workerChoiceStrategyContext.workerChoiceStrategy |
f06e48d8 | 727 | ).currentWorkerNodeId |
a6f7f1b4 JB |
728 | ).toBe(0) |
729 | expect( | |
95c83464 | 730 | pool.workerChoiceStrategyContext.workerChoiceStrategies.get( |
d710242d | 731 | pool.workerChoiceStrategyContext.workerChoiceStrategy |
95c83464 | 732 | ).defaultWorkerWeight |
a6f7f1b4 | 733 | ).toBeGreaterThan(0) |
f06e48d8 | 734 | for (const workerNodeKey of pool.workerChoiceStrategyContext.workerChoiceStrategies |
d710242d | 735 | .get(pool.workerChoiceStrategyContext.workerChoiceStrategy) |
95c83464 | 736 | .workersTaskRunTime.keys()) { |
caeb9817 | 737 | expect( |
95c83464 | 738 | pool.workerChoiceStrategyContext.workerChoiceStrategies |
d710242d | 739 | .get(pool.workerChoiceStrategyContext.workerChoiceStrategy) |
f06e48d8 | 740 | .workersTaskRunTime.get(workerNodeKey).runTime |
caeb9817 JB |
741 | ).toBe(0) |
742 | } | |
f0829c53 JB |
743 | await pool.destroy() |
744 | pool = new DynamicThreadPool( | |
745 | min, | |
746 | max, | |
747 | './tests/worker-files/thread/testWorker.js' | |
748 | ) | |
38f6e859 | 749 | expect( |
95c83464 | 750 | pool.workerChoiceStrategyContext.workerChoiceStrategies.get( |
594bfb84 | 751 | workerChoiceStrategy |
f06e48d8 | 752 | ).currentWorkerNodeId |
b529c323 | 753 | ).toBeDefined() |
38f6e859 | 754 | expect( |
95c83464 | 755 | pool.workerChoiceStrategyContext.workerChoiceStrategies.get( |
594bfb84 | 756 | workerChoiceStrategy |
b529c323 JB |
757 | ).defaultWorkerWeight |
758 | ).toBeDefined() | |
f0829c53 | 759 | expect( |
95c83464 | 760 | pool.workerChoiceStrategyContext.workerChoiceStrategies.get( |
594bfb84 | 761 | workerChoiceStrategy |
b529c323 JB |
762 | ).workersTaskRunTime |
763 | ).toBeDefined() | |
594bfb84 | 764 | pool.setWorkerChoiceStrategy(workerChoiceStrategy) |
a6f7f1b4 | 765 | expect( |
95c83464 | 766 | pool.workerChoiceStrategyContext.workerChoiceStrategies.get( |
d710242d | 767 | pool.workerChoiceStrategyContext.workerChoiceStrategy |
f06e48d8 | 768 | ).currentWorkerNodeId |
a6f7f1b4 JB |
769 | ).toBe(0) |
770 | expect( | |
95c83464 | 771 | pool.workerChoiceStrategyContext.workerChoiceStrategies.get( |
d710242d | 772 | pool.workerChoiceStrategyContext.workerChoiceStrategy |
95c83464 | 773 | ).defaultWorkerWeight |
a6f7f1b4 | 774 | ).toBeGreaterThan(0) |
f06e48d8 | 775 | for (const workerNodeKey of pool.workerChoiceStrategyContext.workerChoiceStrategies |
d710242d | 776 | .get(pool.workerChoiceStrategyContext.workerChoiceStrategy) |
95c83464 | 777 | .workersTaskRunTime.keys()) { |
f0829c53 | 778 | expect( |
95c83464 | 779 | pool.workerChoiceStrategyContext.workerChoiceStrategies |
d710242d | 780 | .get(pool.workerChoiceStrategyContext.workerChoiceStrategy) |
f06e48d8 | 781 | .workersTaskRunTime.get(workerNodeKey).runTime |
f0829c53 JB |
782 | ).toBe(0) |
783 | } | |
caeb9817 JB |
784 | // We need to clean up the resources after our test |
785 | await pool.destroy() | |
786 | }) | |
787 | ||
89b09b26 | 788 | it('Verify unknown strategy throw error', () => { |
a35560ba S |
789 | expect( |
790 | () => | |
791 | new DynamicThreadPool( | |
792 | min, | |
793 | max, | |
794 | './tests/worker-files/thread/testWorker.js', | |
1927ee67 | 795 | { workerChoiceStrategy: 'UNKNOWN_STRATEGY' } |
a35560ba | 796 | ) |
d4aeae5a | 797 | ).toThrowError("Invalid worker choice strategy 'UNKNOWN_STRATEGY'") |
a35560ba S |
798 | }) |
799 | }) |