1 import { expect } from 'expect'
2 import { createStubInstance, restore, stub } from 'sinon'
8 } from '../../../lib/index.cjs'
9 import { FairShareWorkerChoiceStrategy } from '../../../lib/pools/selection-strategies/fair-share-worker-choice-strategy.cjs'
10 import { InterleavedWeightedRoundRobinWorkerChoiceStrategy } from '../../../lib/pools/selection-strategies/interleaved-weighted-round-robin-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 { LeastUsedWorkerChoiceStrategy } from '../../../lib/pools/selection-strategies/least-used-worker-choice-strategy.cjs'
14 import { RoundRobinWorkerChoiceStrategy } from '../../../lib/pools/selection-strategies/round-robin-worker-choice-strategy.cjs'
15 import { WeightedRoundRobinWorkerChoiceStrategy } from '../../../lib/pools/selection-strategies/weighted-round-robin-worker-choice-strategy.cjs'
16 import { WorkerChoiceStrategyContext } from '../../../lib/pools/selection-strategies/worker-choice-strategy-context.cjs'
18 describe('Worker choice strategy context test suite', () => {
21 let fixedPool, dynamicPool
24 fixedPool = new FixedThreadPool(
26 './tests/worker-files/thread/testWorker.mjs'
28 dynamicPool = new DynamicThreadPool(
31 './tests/worker-files/thread/testWorker.mjs'
40 await fixedPool.destroy()
41 await dynamicPool.destroy()
44 it('Verify that constructor() initializes the context with all the available worker choice strategies', () => {
45 let workerChoiceStrategyContext = new WorkerChoiceStrategyContext(fixedPool)
46 expect(workerChoiceStrategyContext.workerChoiceStrategies.size).toBe(
47 Object.keys(WorkerChoiceStrategies).length
49 workerChoiceStrategyContext = new WorkerChoiceStrategyContext(dynamicPool)
50 expect(workerChoiceStrategyContext.workerChoiceStrategies.size).toBe(
51 Object.keys(WorkerChoiceStrategies).length
55 it('Verify that constructor() initializes the context with retries attribute properly set', () => {
56 let workerChoiceStrategyContext = new WorkerChoiceStrategyContext(fixedPool)
57 expect(workerChoiceStrategyContext.retries).toBe(fixedPool.info.maxSize * 2)
58 workerChoiceStrategyContext = new WorkerChoiceStrategyContext(dynamicPool)
59 expect(workerChoiceStrategyContext.retries).toBe(
60 dynamicPool.info.maxSize * 2
64 it('Verify that execute() throws error if null or undefined is returned after retries', () => {
65 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
68 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
69 WorkerChoiceStrategies.ROUND_ROBIN
71 const workerChoiceStrategyUndefinedStub = createStubInstance(
72 RoundRobinWorkerChoiceStrategy,
74 choose: stub().returns(undefined)
77 workerChoiceStrategyContext.workerChoiceStrategies.set(
78 workerChoiceStrategyContext.workerChoiceStrategy,
79 workerChoiceStrategyUndefinedStub
81 expect(() => workerChoiceStrategyContext.execute()).toThrow(
83 `Worker node key chosen is null or undefined after ${workerChoiceStrategyContext.retries} retries`
86 const workerChoiceStrategyNullStub = createStubInstance(
87 RoundRobinWorkerChoiceStrategy,
89 choose: stub().returns(null)
92 workerChoiceStrategyContext.workerChoiceStrategies.set(
93 workerChoiceStrategyContext.workerChoiceStrategy,
94 workerChoiceStrategyNullStub
96 expect(() => workerChoiceStrategyContext.execute()).toThrow(
98 `Worker node key chosen is null or undefined after ${workerChoiceStrategyContext.retries} retries`
103 it('Verify that execute() retry until a worker node is chosen', () => {
104 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
107 const workerChoiceStrategyStub = createStubInstance(
108 RoundRobinWorkerChoiceStrategy,
124 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
125 WorkerChoiceStrategies.ROUND_ROBIN
127 workerChoiceStrategyContext.workerChoiceStrategies.set(
128 workerChoiceStrategyContext.workerChoiceStrategy,
129 workerChoiceStrategyStub
131 const chosenWorkerKey = workerChoiceStrategyContext.execute()
133 workerChoiceStrategyContext.workerChoiceStrategies.get(
134 workerChoiceStrategyContext.workerChoiceStrategy
137 expect(chosenWorkerKey).toBe(1)
140 it('Verify that execute() return the worker node key chosen by the strategy with fixed pool', () => {
141 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
144 const workerChoiceStrategyStub = createStubInstance(
145 RoundRobinWorkerChoiceStrategy,
147 choose: stub().returns(0)
150 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
151 WorkerChoiceStrategies.ROUND_ROBIN
153 workerChoiceStrategyContext.workerChoiceStrategies.set(
154 workerChoiceStrategyContext.workerChoiceStrategy,
155 workerChoiceStrategyStub
157 const chosenWorkerKey = workerChoiceStrategyContext.execute()
159 workerChoiceStrategyContext.workerChoiceStrategies.get(
160 workerChoiceStrategyContext.workerChoiceStrategy
163 expect(chosenWorkerKey).toBe(0)
166 it('Verify that execute() return the worker node key chosen by the strategy with dynamic pool', () => {
167 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
170 const workerChoiceStrategyStub = createStubInstance(
171 RoundRobinWorkerChoiceStrategy,
173 choose: stub().returns(0)
176 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
177 WorkerChoiceStrategies.ROUND_ROBIN
179 workerChoiceStrategyContext.workerChoiceStrategies.set(
180 workerChoiceStrategyContext.workerChoiceStrategy,
181 workerChoiceStrategyStub
183 const chosenWorkerKey = workerChoiceStrategyContext.execute()
185 workerChoiceStrategyContext.workerChoiceStrategies.get(
186 workerChoiceStrategyContext.workerChoiceStrategy
189 expect(chosenWorkerKey).toBe(0)
192 it('Verify that setWorkerChoiceStrategy() works with ROUND_ROBIN and fixed pool', () => {
193 const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN
194 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
198 workerChoiceStrategyContext.workerChoiceStrategies.get(
201 ).toBeInstanceOf(RoundRobinWorkerChoiceStrategy)
202 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
205 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
207 workerChoiceStrategyContext.workerChoiceStrategies.get(
210 ).toBeInstanceOf(RoundRobinWorkerChoiceStrategy)
211 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
216 it('Verify that setWorkerChoiceStrategy() works with ROUND_ROBIN and dynamic pool', () => {
217 const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN
218 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
222 workerChoiceStrategyContext.workerChoiceStrategies.get(
225 ).toBeInstanceOf(RoundRobinWorkerChoiceStrategy)
226 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
229 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
231 workerChoiceStrategyContext.workerChoiceStrategies.get(
234 ).toBeInstanceOf(RoundRobinWorkerChoiceStrategy)
235 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
240 it('Verify that setWorkerChoiceStrategy() works with LEAST_USED and fixed pool', () => {
241 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_USED
242 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
245 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
247 workerChoiceStrategyContext.workerChoiceStrategies.get(
250 ).toBeInstanceOf(LeastUsedWorkerChoiceStrategy)
251 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
256 it('Verify that setWorkerChoiceStrategy() works with LEAST_USED and dynamic pool', () => {
257 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_USED
258 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
261 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
263 workerChoiceStrategyContext.workerChoiceStrategies.get(
266 ).toBeInstanceOf(LeastUsedWorkerChoiceStrategy)
267 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
272 it('Verify that setWorkerChoiceStrategy() works with LEAST_BUSY and fixed pool', () => {
273 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_BUSY
274 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
277 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
279 workerChoiceStrategyContext.workerChoiceStrategies.get(
282 ).toBeInstanceOf(LeastBusyWorkerChoiceStrategy)
283 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
288 it('Verify that setWorkerChoiceStrategy() works with LEAST_BUSY and dynamic pool', () => {
289 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_BUSY
290 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
293 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
295 workerChoiceStrategyContext.workerChoiceStrategies.get(
298 ).toBeInstanceOf(LeastBusyWorkerChoiceStrategy)
299 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
304 it('Verify that setWorkerChoiceStrategy() works with LEAST_ELU and fixed pool', () => {
305 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_ELU
306 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
309 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
311 workerChoiceStrategyContext.workerChoiceStrategies.get(
314 ).toBeInstanceOf(LeastEluWorkerChoiceStrategy)
315 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
320 it('Verify that setWorkerChoiceStrategy() works with LEAST_ELU and dynamic pool', () => {
321 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_ELU
322 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
325 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
327 workerChoiceStrategyContext.workerChoiceStrategies.get(
330 ).toBeInstanceOf(LeastEluWorkerChoiceStrategy)
331 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
336 it('Verify that setWorkerChoiceStrategy() works with FAIR_SHARE and fixed pool', () => {
337 const workerChoiceStrategy = WorkerChoiceStrategies.FAIR_SHARE
338 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
341 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
343 workerChoiceStrategyContext.workerChoiceStrategies.get(
346 ).toBeInstanceOf(FairShareWorkerChoiceStrategy)
347 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
352 it('Verify that setWorkerChoiceStrategy() works with FAIR_SHARE and dynamic pool', () => {
353 const workerChoiceStrategy = WorkerChoiceStrategies.FAIR_SHARE
354 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
357 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
359 workerChoiceStrategyContext.workerChoiceStrategies.get(
362 ).toBeInstanceOf(FairShareWorkerChoiceStrategy)
363 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
368 it('Verify that setWorkerChoiceStrategy() works with WEIGHTED_ROUND_ROBIN and fixed pool', () => {
369 const workerChoiceStrategy = WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
370 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
373 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
375 workerChoiceStrategyContext.workerChoiceStrategies.get(
378 ).toBeInstanceOf(WeightedRoundRobinWorkerChoiceStrategy)
379 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
384 it('Verify that setWorkerChoiceStrategy() works with WEIGHTED_ROUND_ROBIN and dynamic pool', () => {
385 const workerChoiceStrategy = WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
386 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
389 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
391 workerChoiceStrategyContext.workerChoiceStrategies.get(
394 ).toBeInstanceOf(WeightedRoundRobinWorkerChoiceStrategy)
395 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
400 it('Verify that setWorkerChoiceStrategy() works with INTERLEAVED_WEIGHTED_ROUND_ROBIN and fixed pool', () => {
401 const workerChoiceStrategy =
402 WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
403 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
406 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
408 workerChoiceStrategyContext.workerChoiceStrategies.get(
411 ).toBeInstanceOf(InterleavedWeightedRoundRobinWorkerChoiceStrategy)
412 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
417 it('Verify that setWorkerChoiceStrategy() works with INTERLEAVED_WEIGHTED_ROUND_ROBIN and dynamic pool', () => {
418 const workerChoiceStrategy =
419 WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
420 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
423 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
425 workerChoiceStrategyContext.workerChoiceStrategies.get(
428 ).toBeInstanceOf(InterleavedWeightedRoundRobinWorkerChoiceStrategy)
429 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
434 it('Verify that worker choice strategy options enable median runtime pool statistics', () => {
435 const wwrWorkerChoiceStrategy = WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
436 let workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
438 wwrWorkerChoiceStrategy,
440 runTime: { median: true }
444 workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime
448 workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.median
450 workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
452 wwrWorkerChoiceStrategy,
454 runTime: { median: true }
458 workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime
462 workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.median
464 const fsWorkerChoiceStrategy = WorkerChoiceStrategies.FAIR_SHARE
465 workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
467 fsWorkerChoiceStrategy,
469 runTime: { median: true }
473 workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime
477 workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.median
479 workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
481 fsWorkerChoiceStrategy,
483 runTime: { median: true }
487 workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime
491 workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.median