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