1 import { expect } from 'expect'
2 import { createStubInstance, restore, stub } from 'sinon'
7 } from '../../../lib/index.cjs'
8 import { WorkerChoiceStrategyContext } from '../../../lib/pools/selection-strategies/worker-choice-strategy-context.cjs'
9 import { RoundRobinWorkerChoiceStrategy } from '../../../lib/pools/selection-strategies/round-robin-worker-choice-strategy.cjs'
10 import { LeastUsedWorkerChoiceStrategy } from '../../../lib/pools/selection-strategies/least-used-worker-choice-strategy.cjs'
11 import { LeastBusyWorkerChoiceStrategy } from '../../../lib/pools/selection-strategies/least-busy-worker-choice-strategy.cjs'
12 import { LeastEluWorkerChoiceStrategy } from '../../../lib/pools/selection-strategies/least-elu-worker-choice-strategy.cjs'
13 import { FairShareWorkerChoiceStrategy } from '../../../lib/pools/selection-strategies/fair-share-worker-choice-strategy.cjs'
14 import { WeightedRoundRobinWorkerChoiceStrategy } from '../../../lib/pools/selection-strategies/weighted-round-robin-worker-choice-strategy.cjs'
15 import { InterleavedWeightedRoundRobinWorkerChoiceStrategy } from '../../../lib/pools/selection-strategies/interleaved-weighted-round-robin-worker-choice-strategy.cjs'
17 describe('Worker choice strategy context test suite', () => {
20 let fixedPool, dynamicPool
23 fixedPool = new FixedThreadPool(
25 './tests/worker-files/thread/testWorker.mjs'
27 dynamicPool = new DynamicThreadPool(
30 './tests/worker-files/thread/testWorker.mjs'
39 await fixedPool.destroy()
40 await dynamicPool.destroy()
43 it('Verify that constructor() initializes the context with all the available worker choice strategies', () => {
44 let workerChoiceStrategyContext = new WorkerChoiceStrategyContext(fixedPool)
45 expect(workerChoiceStrategyContext.workerChoiceStrategies.size).toBe(
46 Object.keys(WorkerChoiceStrategies).length
48 workerChoiceStrategyContext = new WorkerChoiceStrategyContext(dynamicPool)
49 expect(workerChoiceStrategyContext.workerChoiceStrategies.size).toBe(
50 Object.keys(WorkerChoiceStrategies).length
54 it('Verify that constructor() initializes the context with retries attribute properly set', () => {
55 let workerChoiceStrategyContext = new WorkerChoiceStrategyContext(fixedPool)
56 expect(workerChoiceStrategyContext.retries).toBe(fixedPool.info.maxSize * 2)
57 workerChoiceStrategyContext = new WorkerChoiceStrategyContext(dynamicPool)
58 expect(workerChoiceStrategyContext.retries).toBe(
59 dynamicPool.info.maxSize * 2
63 it('Verify that execute() throws error if null or undefined is returned after retries', () => {
64 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
67 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
68 WorkerChoiceStrategies.ROUND_ROBIN
70 const workerChoiceStrategyUndefinedStub = createStubInstance(
71 RoundRobinWorkerChoiceStrategy,
73 choose: stub().returns(undefined)
76 workerChoiceStrategyContext.workerChoiceStrategies.set(
77 workerChoiceStrategyContext.workerChoiceStrategy,
78 workerChoiceStrategyUndefinedStub
80 expect(() => workerChoiceStrategyContext.execute()).toThrow(
82 `Worker node key chosen is null or undefined after ${workerChoiceStrategyContext.retries} retries`
85 const workerChoiceStrategyNullStub = createStubInstance(
86 RoundRobinWorkerChoiceStrategy,
88 choose: stub().returns(null)
91 workerChoiceStrategyContext.workerChoiceStrategies.set(
92 workerChoiceStrategyContext.workerChoiceStrategy,
93 workerChoiceStrategyNullStub
95 expect(() => workerChoiceStrategyContext.execute()).toThrow(
97 `Worker node key chosen is null or undefined after ${workerChoiceStrategyContext.retries} retries`
102 it('Verify that execute() retry until a worker node is chosen', () => {
103 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
106 const workerChoiceStrategyStub = createStubInstance(
107 RoundRobinWorkerChoiceStrategy,
123 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
124 WorkerChoiceStrategies.ROUND_ROBIN
126 workerChoiceStrategyContext.workerChoiceStrategies.set(
127 workerChoiceStrategyContext.workerChoiceStrategy,
128 workerChoiceStrategyStub
130 const chosenWorkerKey = workerChoiceStrategyContext.execute()
132 workerChoiceStrategyContext.workerChoiceStrategies.get(
133 workerChoiceStrategyContext.workerChoiceStrategy
136 expect(chosenWorkerKey).toBe(1)
139 it('Verify that execute() return the worker node key chosen by the strategy with fixed pool', () => {
140 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
143 const workerChoiceStrategyStub = createStubInstance(
144 RoundRobinWorkerChoiceStrategy,
146 choose: stub().returns(0)
149 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
150 WorkerChoiceStrategies.ROUND_ROBIN
152 workerChoiceStrategyContext.workerChoiceStrategies.set(
153 workerChoiceStrategyContext.workerChoiceStrategy,
154 workerChoiceStrategyStub
156 const chosenWorkerKey = workerChoiceStrategyContext.execute()
158 workerChoiceStrategyContext.workerChoiceStrategies.get(
159 workerChoiceStrategyContext.workerChoiceStrategy
162 expect(chosenWorkerKey).toBe(0)
165 it('Verify that execute() return the worker node key chosen by the strategy with dynamic pool', () => {
166 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
169 const workerChoiceStrategyStub = createStubInstance(
170 RoundRobinWorkerChoiceStrategy,
172 choose: stub().returns(0)
175 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
176 WorkerChoiceStrategies.ROUND_ROBIN
178 workerChoiceStrategyContext.workerChoiceStrategies.set(
179 workerChoiceStrategyContext.workerChoiceStrategy,
180 workerChoiceStrategyStub
182 const chosenWorkerKey = workerChoiceStrategyContext.execute()
184 workerChoiceStrategyContext.workerChoiceStrategies.get(
185 workerChoiceStrategyContext.workerChoiceStrategy
188 expect(chosenWorkerKey).toBe(0)
191 it('Verify that setWorkerChoiceStrategy() works with ROUND_ROBIN and fixed pool', () => {
192 const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN
193 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
197 workerChoiceStrategyContext.workerChoiceStrategies.get(
200 ).toBeInstanceOf(RoundRobinWorkerChoiceStrategy)
201 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
204 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
206 workerChoiceStrategyContext.workerChoiceStrategies.get(
209 ).toBeInstanceOf(RoundRobinWorkerChoiceStrategy)
210 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
215 it('Verify that setWorkerChoiceStrategy() works with ROUND_ROBIN and dynamic pool', () => {
216 const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN
217 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
221 workerChoiceStrategyContext.workerChoiceStrategies.get(
224 ).toBeInstanceOf(RoundRobinWorkerChoiceStrategy)
225 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
228 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
230 workerChoiceStrategyContext.workerChoiceStrategies.get(
233 ).toBeInstanceOf(RoundRobinWorkerChoiceStrategy)
234 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
239 it('Verify that setWorkerChoiceStrategy() works with LEAST_USED and fixed pool', () => {
240 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_USED
241 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
244 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
246 workerChoiceStrategyContext.workerChoiceStrategies.get(
249 ).toBeInstanceOf(LeastUsedWorkerChoiceStrategy)
250 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
255 it('Verify that setWorkerChoiceStrategy() works with LEAST_USED and dynamic pool', () => {
256 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_USED
257 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
260 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
262 workerChoiceStrategyContext.workerChoiceStrategies.get(
265 ).toBeInstanceOf(LeastUsedWorkerChoiceStrategy)
266 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
271 it('Verify that setWorkerChoiceStrategy() works with LEAST_BUSY and fixed pool', () => {
272 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_BUSY
273 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
276 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
278 workerChoiceStrategyContext.workerChoiceStrategies.get(
281 ).toBeInstanceOf(LeastBusyWorkerChoiceStrategy)
282 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
287 it('Verify that setWorkerChoiceStrategy() works with LEAST_BUSY and dynamic pool', () => {
288 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_BUSY
289 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
292 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
294 workerChoiceStrategyContext.workerChoiceStrategies.get(
297 ).toBeInstanceOf(LeastBusyWorkerChoiceStrategy)
298 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
303 it('Verify that setWorkerChoiceStrategy() works with LEAST_ELU and fixed pool', () => {
304 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_ELU
305 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
308 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
310 workerChoiceStrategyContext.workerChoiceStrategies.get(
313 ).toBeInstanceOf(LeastEluWorkerChoiceStrategy)
314 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
319 it('Verify that setWorkerChoiceStrategy() works with LEAST_ELU and dynamic pool', () => {
320 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_ELU
321 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
324 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
326 workerChoiceStrategyContext.workerChoiceStrategies.get(
329 ).toBeInstanceOf(LeastEluWorkerChoiceStrategy)
330 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
335 it('Verify that setWorkerChoiceStrategy() works with FAIR_SHARE and fixed pool', () => {
336 const workerChoiceStrategy = WorkerChoiceStrategies.FAIR_SHARE
337 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
340 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
342 workerChoiceStrategyContext.workerChoiceStrategies.get(
345 ).toBeInstanceOf(FairShareWorkerChoiceStrategy)
346 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
351 it('Verify that setWorkerChoiceStrategy() works with FAIR_SHARE and dynamic pool', () => {
352 const workerChoiceStrategy = WorkerChoiceStrategies.FAIR_SHARE
353 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
356 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
358 workerChoiceStrategyContext.workerChoiceStrategies.get(
361 ).toBeInstanceOf(FairShareWorkerChoiceStrategy)
362 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
367 it('Verify that setWorkerChoiceStrategy() works with WEIGHTED_ROUND_ROBIN and fixed pool', () => {
368 const workerChoiceStrategy = WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
369 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
372 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
374 workerChoiceStrategyContext.workerChoiceStrategies.get(
377 ).toBeInstanceOf(WeightedRoundRobinWorkerChoiceStrategy)
378 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
383 it('Verify that setWorkerChoiceStrategy() works with WEIGHTED_ROUND_ROBIN and dynamic pool', () => {
384 const workerChoiceStrategy = WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
385 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
388 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
390 workerChoiceStrategyContext.workerChoiceStrategies.get(
393 ).toBeInstanceOf(WeightedRoundRobinWorkerChoiceStrategy)
394 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
399 it('Verify that setWorkerChoiceStrategy() works with INTERLEAVED_WEIGHTED_ROUND_ROBIN and fixed pool', () => {
400 const workerChoiceStrategy =
401 WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
402 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
405 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
407 workerChoiceStrategyContext.workerChoiceStrategies.get(
410 ).toBeInstanceOf(InterleavedWeightedRoundRobinWorkerChoiceStrategy)
411 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
416 it('Verify that setWorkerChoiceStrategy() works with INTERLEAVED_WEIGHTED_ROUND_ROBIN and dynamic pool', () => {
417 const workerChoiceStrategy =
418 WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
419 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
422 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
424 workerChoiceStrategyContext.workerChoiceStrategies.get(
427 ).toBeInstanceOf(InterleavedWeightedRoundRobinWorkerChoiceStrategy)
428 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
433 it('Verify that worker choice strategy options enable median runtime pool statistics', () => {
434 const wwrWorkerChoiceStrategy = WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
435 let workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
437 wwrWorkerChoiceStrategy,
439 runTime: { median: true }
443 workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime
447 workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.median
449 workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
451 wwrWorkerChoiceStrategy,
453 runTime: { median: true }
457 workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime
461 workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.median
463 const fsWorkerChoiceStrategy = WorkerChoiceStrategies.FAIR_SHARE
464 workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
466 fsWorkerChoiceStrategy,
468 runTime: { median: true }
472 workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime
476 workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.median
478 workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
480 fsWorkerChoiceStrategy,
482 runTime: { median: true }
486 workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime
490 workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.median