Merge branch 'master' of github.com:poolifier/poolifier
[poolifier.git] / tests / pools / selection-strategies / worker-choice-strategy-context.test.mjs
CommitLineData
a074ffee
JB
1import { expect } from 'expect'
2import { createStubInstance, restore, stub } from 'sinon'
3import {
40ad1d27 4 DynamicThreadPool,
a074ffee 5 FixedThreadPool,
40ad1d27 6 WorkerChoiceStrategies
a074ffee
JB
7} from '../../../lib/index.js'
8import { WorkerChoiceStrategyContext } from '../../../lib/pools/selection-strategies/worker-choice-strategy-context.js'
9import { RoundRobinWorkerChoiceStrategy } from '../../../lib/pools/selection-strategies/round-robin-worker-choice-strategy.js'
10import { LeastUsedWorkerChoiceStrategy } from '../../../lib/pools/selection-strategies/least-used-worker-choice-strategy.js'
11import { LeastBusyWorkerChoiceStrategy } from '../../../lib/pools/selection-strategies/least-busy-worker-choice-strategy.js'
12import { LeastEluWorkerChoiceStrategy } from '../../../lib/pools/selection-strategies/least-elu-worker-choice-strategy.js'
13import { FairShareWorkerChoiceStrategy } from '../../../lib/pools/selection-strategies/fair-share-worker-choice-strategy.js'
14import { WeightedRoundRobinWorkerChoiceStrategy } from '../../../lib/pools/selection-strategies/weighted-round-robin-worker-choice-strategy.js'
15import { InterleavedWeightedRoundRobinWorkerChoiceStrategy } from '../../../lib/pools/selection-strategies/interleaved-weighted-round-robin-worker-choice-strategy.js'
40ad1d27
JB
16
17describe('Worker choice strategy context test suite', () => {
c15273f2
JB
18 const min = 1
19 const max = 3
40ad1d27 20 let fixedPool, dynamicPool
c15273f2
JB
21
22 before(() => {
23 fixedPool = new FixedThreadPool(
24 max,
b2fd3f4a 25 './tests/worker-files/thread/testWorker.mjs'
c15273f2
JB
26 )
27 dynamicPool = new DynamicThreadPool(
28 min,
29 max,
b2fd3f4a 30 './tests/worker-files/thread/testWorker.mjs'
c15273f2 31 )
40ad1d27
JB
32 })
33
34 afterEach(() => {
a074ffee 35 restore()
40ad1d27
JB
36 })
37
fd7ebd49
JB
38 after(async () => {
39 await fixedPool.destroy()
40 await dynamicPool.destroy()
c15273f2
JB
41 })
42
2285a040
JB
43 it('Verify that constructor() initializes the context with all the available worker choice strategies', () => {
44 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
45 fixedPool
46 )
47 expect(workerChoiceStrategyContext.workerChoiceStrategies.size).toBe(
48 Object.keys(WorkerChoiceStrategies).length
49 )
50 })
51
40ad1d27
JB
52 it('Verify that execute() return the worker chosen by the strategy with fixed pool', () => {
53 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
54 fixedPool
55 )
33d2304b 56 const workerChoiceStrategyStub = createStubInstance(
40ad1d27
JB
57 RoundRobinWorkerChoiceStrategy,
58 {
a074ffee 59 choose: stub().returns(0)
40ad1d27
JB
60 }
61 )
d710242d 62 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
95c83464
JB
63 WorkerChoiceStrategies.ROUND_ROBIN
64 )
65 workerChoiceStrategyContext.workerChoiceStrategies.set(
d710242d 66 workerChoiceStrategyContext.workerChoiceStrategy,
33d2304b 67 workerChoiceStrategyStub
95c83464 68 )
c923ce56 69 const chosenWorkerKey = workerChoiceStrategyContext.execute()
40ad1d27 70 expect(
95c83464 71 workerChoiceStrategyContext.workerChoiceStrategies.get(
d710242d 72 workerChoiceStrategyContext.workerChoiceStrategy
95c83464 73 ).choose.calledOnce
40ad1d27 74 ).toBe(true)
c923ce56 75 expect(chosenWorkerKey).toBe(0)
40ad1d27
JB
76 })
77
4ba8492f 78 it('Verify that execute() throws error if null or undefined is returned after retries', () => {
527e715f
JB
79 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
80 fixedPool
81 )
33d2304b 82 const workerChoiceStrategyUndefinedStub = createStubInstance(
527e715f
JB
83 RoundRobinWorkerChoiceStrategy,
84 {
a074ffee 85 choose: stub().returns(undefined)
527e715f
JB
86 }
87 )
33d2304b 88 const workerChoiceStrategyNullStub = createStubInstance(
fa418e12
JB
89 RoundRobinWorkerChoiceStrategy,
90 {
a074ffee 91 choose: stub().returns(null)
fa418e12
JB
92 }
93 )
527e715f
JB
94 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
95 WorkerChoiceStrategies.ROUND_ROBIN
96 )
97 workerChoiceStrategyContext.workerChoiceStrategies.set(
98 workerChoiceStrategyContext.workerChoiceStrategy,
33d2304b 99 workerChoiceStrategyUndefinedStub
fa418e12
JB
100 )
101 expect(() => workerChoiceStrategyContext.execute()).toThrowError(
e695d66f 102 new Error('Worker node key chosen is null or undefined after 6 retries')
fa418e12
JB
103 )
104 workerChoiceStrategyContext.workerChoiceStrategies.set(
105 workerChoiceStrategyContext.workerChoiceStrategy,
33d2304b 106 workerChoiceStrategyNullStub
527e715f
JB
107 )
108 expect(() => workerChoiceStrategyContext.execute()).toThrowError(
e695d66f 109 new Error('Worker node key chosen is null or undefined after 6 retries')
527e715f
JB
110 )
111 })
112
40ad1d27
JB
113 it('Verify that execute() return the worker chosen by the strategy with dynamic pool', () => {
114 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
115 dynamicPool
116 )
33d2304b 117 const workerChoiceStrategyStub = createStubInstance(
40ad1d27
JB
118 RoundRobinWorkerChoiceStrategy,
119 {
a074ffee 120 choose: stub().returns(0)
40ad1d27
JB
121 }
122 )
d710242d 123 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
95c83464
JB
124 WorkerChoiceStrategies.ROUND_ROBIN
125 )
126 workerChoiceStrategyContext.workerChoiceStrategies.set(
d710242d 127 workerChoiceStrategyContext.workerChoiceStrategy,
33d2304b 128 workerChoiceStrategyStub
95c83464 129 )
c923ce56 130 const chosenWorkerKey = workerChoiceStrategyContext.execute()
40ad1d27 131 expect(
95c83464 132 workerChoiceStrategyContext.workerChoiceStrategies.get(
d710242d 133 workerChoiceStrategyContext.workerChoiceStrategy
95c83464 134 ).choose.calledOnce
40ad1d27 135 ).toBe(true)
c923ce56 136 expect(chosenWorkerKey).toBe(0)
40ad1d27
JB
137 })
138
139 it('Verify that setWorkerChoiceStrategy() works with ROUND_ROBIN and fixed pool', () => {
594bfb84 140 const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN
40ad1d27
JB
141 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
142 fixedPool
143 )
95c83464
JB
144 expect(
145 workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 146 workerChoiceStrategy
95c83464
JB
147 )
148 ).toBeInstanceOf(RoundRobinWorkerChoiceStrategy)
d710242d 149 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
594bfb84 150 workerChoiceStrategy
40ad1d27 151 )
594bfb84 152 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
95c83464
JB
153 expect(
154 workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 155 workerChoiceStrategy
95c83464
JB
156 )
157 ).toBeInstanceOf(RoundRobinWorkerChoiceStrategy)
d710242d 158 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
594bfb84 159 workerChoiceStrategy
b2b1d84e 160 )
40ad1d27
JB
161 })
162
23ff945a 163 it('Verify that setWorkerChoiceStrategy() works with ROUND_ROBIN and dynamic pool', () => {
594bfb84 164 const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN
40ad1d27
JB
165 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
166 dynamicPool
167 )
95c83464
JB
168 expect(
169 workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 170 workerChoiceStrategy
95c83464
JB
171 )
172 ).toBeInstanceOf(RoundRobinWorkerChoiceStrategy)
d710242d 173 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
594bfb84 174 workerChoiceStrategy
40ad1d27 175 )
594bfb84 176 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
95c83464
JB
177 expect(
178 workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 179 workerChoiceStrategy
95c83464
JB
180 )
181 ).toBeInstanceOf(RoundRobinWorkerChoiceStrategy)
d710242d 182 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
594bfb84 183 workerChoiceStrategy
b2b1d84e 184 )
40ad1d27
JB
185 })
186
e4543b14
JB
187 it('Verify that setWorkerChoiceStrategy() works with LEAST_USED and fixed pool', () => {
188 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_USED
40ad1d27
JB
189 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
190 fixedPool
191 )
594bfb84 192 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
95c83464
JB
193 expect(
194 workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 195 workerChoiceStrategy
95c83464 196 )
e4543b14 197 ).toBeInstanceOf(LeastUsedWorkerChoiceStrategy)
d710242d 198 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
594bfb84 199 workerChoiceStrategy
b2b1d84e 200 )
40ad1d27
JB
201 })
202
e4543b14
JB
203 it('Verify that setWorkerChoiceStrategy() works with LEAST_USED and dynamic pool', () => {
204 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_USED
40ad1d27
JB
205 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
206 dynamicPool
207 )
594bfb84 208 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
95c83464
JB
209 expect(
210 workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 211 workerChoiceStrategy
95c83464 212 )
e4543b14 213 ).toBeInstanceOf(LeastUsedWorkerChoiceStrategy)
d710242d 214 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
594bfb84 215 workerChoiceStrategy
b2b1d84e 216 )
168c526f
JB
217 })
218
e4543b14
JB
219 it('Verify that setWorkerChoiceStrategy() works with LEAST_BUSY and fixed pool', () => {
220 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_BUSY
168c526f
JB
221 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
222 fixedPool
223 )
594bfb84 224 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
95c83464
JB
225 expect(
226 workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 227 workerChoiceStrategy
95c83464 228 )
e4543b14 229 ).toBeInstanceOf(LeastBusyWorkerChoiceStrategy)
d710242d 230 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
594bfb84 231 workerChoiceStrategy
b2b1d84e 232 )
168c526f
JB
233 })
234
e4543b14
JB
235 it('Verify that setWorkerChoiceStrategy() works with LEAST_BUSY and dynamic pool', () => {
236 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_BUSY
168c526f
JB
237 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
238 dynamicPool
239 )
594bfb84 240 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
95c83464
JB
241 expect(
242 workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 243 workerChoiceStrategy
95c83464 244 )
e4543b14 245 ).toBeInstanceOf(LeastBusyWorkerChoiceStrategy)
d710242d 246 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
594bfb84 247 workerChoiceStrategy
b2b1d84e 248 )
40ad1d27 249 })
23ff945a 250
a1c82d5d
JB
251 it('Verify that setWorkerChoiceStrategy() works with LEAST_ELU and fixed pool', () => {
252 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_ELU
253 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
254 fixedPool
255 )
256 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
257 expect(
258 workerChoiceStrategyContext.workerChoiceStrategies.get(
259 workerChoiceStrategy
260 )
261 ).toBeInstanceOf(LeastEluWorkerChoiceStrategy)
262 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
263 workerChoiceStrategy
264 )
265 })
266
267 it('Verify that setWorkerChoiceStrategy() works with LEAST_ELU and dynamic pool', () => {
268 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_ELU
269 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
270 dynamicPool
271 )
272 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
273 expect(
274 workerChoiceStrategyContext.workerChoiceStrategies.get(
275 workerChoiceStrategy
276 )
277 ).toBeInstanceOf(LeastEluWorkerChoiceStrategy)
278 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
279 workerChoiceStrategy
280 )
281 })
282
23ff945a 283 it('Verify that setWorkerChoiceStrategy() works with FAIR_SHARE and fixed pool', () => {
594bfb84 284 const workerChoiceStrategy = WorkerChoiceStrategies.FAIR_SHARE
23ff945a
JB
285 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
286 fixedPool
287 )
594bfb84 288 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
95c83464
JB
289 expect(
290 workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 291 workerChoiceStrategy
95c83464
JB
292 )
293 ).toBeInstanceOf(FairShareWorkerChoiceStrategy)
d710242d 294 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
594bfb84 295 workerChoiceStrategy
b2b1d84e 296 )
23ff945a
JB
297 })
298
299 it('Verify that setWorkerChoiceStrategy() works with FAIR_SHARE and dynamic pool', () => {
594bfb84 300 const workerChoiceStrategy = WorkerChoiceStrategies.FAIR_SHARE
23ff945a
JB
301 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
302 dynamicPool
303 )
594bfb84 304 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
95c83464
JB
305 expect(
306 workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 307 workerChoiceStrategy
95c83464
JB
308 )
309 ).toBeInstanceOf(FairShareWorkerChoiceStrategy)
d710242d 310 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
594bfb84 311 workerChoiceStrategy
b2b1d84e 312 )
23ff945a
JB
313 })
314
c15273f2 315 it('Verify that setWorkerChoiceStrategy() works with WEIGHTED_ROUND_ROBIN and fixed pool', () => {
594bfb84 316 const workerChoiceStrategy = WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
c15273f2
JB
317 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
318 fixedPool
319 )
594bfb84 320 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
95c83464
JB
321 expect(
322 workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 323 workerChoiceStrategy
95c83464
JB
324 )
325 ).toBeInstanceOf(WeightedRoundRobinWorkerChoiceStrategy)
d710242d 326 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
594bfb84 327 workerChoiceStrategy
b2b1d84e 328 )
c15273f2 329 })
23ff945a 330
c15273f2 331 it('Verify that setWorkerChoiceStrategy() works with WEIGHTED_ROUND_ROBIN and dynamic pool', () => {
594bfb84 332 const workerChoiceStrategy = WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
c15273f2
JB
333 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
334 dynamicPool
335 )
594bfb84 336 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
95c83464
JB
337 expect(
338 workerChoiceStrategyContext.workerChoiceStrategies.get(
594bfb84 339 workerChoiceStrategy
95c83464
JB
340 )
341 ).toBeInstanceOf(WeightedRoundRobinWorkerChoiceStrategy)
d710242d 342 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
594bfb84 343 workerChoiceStrategy
b2b1d84e 344 )
c15273f2 345 })
2fc5cae3 346
8beab0d3
JB
347 it('Verify that setWorkerChoiceStrategy() works with INTERLEAVED_WEIGHTED_ROUND_ROBIN and fixed pool', () => {
348 const workerChoiceStrategy =
349 WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
350 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
351 fixedPool
352 )
353 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
354 expect(
355 workerChoiceStrategyContext.workerChoiceStrategies.get(
356 workerChoiceStrategy
357 )
358 ).toBeInstanceOf(InterleavedWeightedRoundRobinWorkerChoiceStrategy)
359 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
360 workerChoiceStrategy
361 )
362 })
363
364 it('Verify that setWorkerChoiceStrategy() works with INTERLEAVED_WEIGHTED_ROUND_ROBIN and dynamic pool', () => {
365 const workerChoiceStrategy =
366 WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
367 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
368 dynamicPool
369 )
370 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
371 expect(
372 workerChoiceStrategyContext.workerChoiceStrategies.get(
373 workerChoiceStrategy
374 )
375 ).toBeInstanceOf(InterleavedWeightedRoundRobinWorkerChoiceStrategy)
376 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
377 workerChoiceStrategy
378 )
379 })
380
9e45c2c4 381 it('Verify that worker choice strategy options enable median runtime pool statistics', () => {
2fc5cae3
JB
382 const wwrWorkerChoiceStrategy = WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
383 let workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
384 fixedPool,
385 wwrWorkerChoiceStrategy,
386 {
932fc8be 387 runTime: { median: true }
2fc5cae3
JB
388 }
389 )
87de9ff5 390 expect(
932fc8be
JB
391 workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime
392 .average
87de9ff5
JB
393 ).toBe(false)
394 expect(
932fc8be 395 workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.median
87de9ff5 396 ).toBe(true)
2fc5cae3
JB
397 workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
398 dynamicPool,
399 wwrWorkerChoiceStrategy,
400 {
932fc8be 401 runTime: { median: true }
2fc5cae3
JB
402 }
403 )
87de9ff5 404 expect(
932fc8be
JB
405 workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime
406 .average
87de9ff5
JB
407 ).toBe(false)
408 expect(
932fc8be 409 workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.median
87de9ff5 410 ).toBe(true)
2fc5cae3
JB
411 const fsWorkerChoiceStrategy = WorkerChoiceStrategies.FAIR_SHARE
412 workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
413 fixedPool,
414 fsWorkerChoiceStrategy,
415 {
932fc8be 416 runTime: { median: true }
2fc5cae3
JB
417 }
418 )
87de9ff5 419 expect(
932fc8be
JB
420 workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime
421 .average
87de9ff5
JB
422 ).toBe(false)
423 expect(
932fc8be 424 workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.median
87de9ff5 425 ).toBe(true)
2fc5cae3
JB
426 workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
427 dynamicPool,
428 fsWorkerChoiceStrategy,
429 {
932fc8be 430 runTime: { median: true }
2fc5cae3
JB
431 }
432 )
87de9ff5 433 expect(
932fc8be
JB
434 workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime
435 .average
87de9ff5
JB
436 ).toBe(false)
437 expect(
932fc8be 438 workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.median
87de9ff5 439 ).toBe(true)
2fc5cae3 440 })
40ad1d27 441})