1 import { expect } from 'expect'
2 import { createStubInstance, restore, stub } from 'sinon'
7 WorkerChoiceStrategies,
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 { WorkerChoiceStrategiesContext } from '../../../lib/pools/selection-strategies/worker-choice-strategies-context.cjs'
18 describe('Worker choice strategies context test suite', () => {
21 let dynamicPool, fixedPool
23 before('Create pools', () => {
24 fixedPool = new FixedThreadPool(
26 './tests/worker-files/thread/testWorker.mjs'
28 dynamicPool = new DynamicThreadPool(
31 './tests/worker-files/thread/testWorker.mjs'
39 after('Destroy pools', async () => {
40 await fixedPool.destroy()
41 await dynamicPool.destroy()
44 it('Verify that constructor() initializes the context with the default choice strategy', () => {
45 let workerChoiceStrategiesContext = new WorkerChoiceStrategiesContext(
48 expect(workerChoiceStrategiesContext.workerChoiceStrategies.size).toBe(1)
50 workerChoiceStrategiesContext.workerChoiceStrategies.get(
51 workerChoiceStrategiesContext.defaultWorkerChoiceStrategy
53 ).toBeInstanceOf(RoundRobinWorkerChoiceStrategy)
54 workerChoiceStrategiesContext = new WorkerChoiceStrategiesContext(
57 expect(workerChoiceStrategiesContext.workerChoiceStrategies.size).toBe(1)
59 workerChoiceStrategiesContext.workerChoiceStrategies.get(
60 workerChoiceStrategiesContext.defaultWorkerChoiceStrategy
62 ).toBeInstanceOf(RoundRobinWorkerChoiceStrategy)
65 it('Verify that constructor() initializes the context with retries attribute properly set', () => {
66 let workerChoiceStrategiesContext = new WorkerChoiceStrategiesContext(
69 expect(workerChoiceStrategiesContext.retries).toBe(
70 fixedPool.info.maxSize * 2
72 workerChoiceStrategiesContext = new WorkerChoiceStrategiesContext(
75 expect(workerChoiceStrategiesContext.retries).toBe(
76 dynamicPool.info.maxSize * 2
80 it('Verify that execute() throws error if null or undefined is returned after retries', () => {
81 const workerChoiceStrategiesContext = new WorkerChoiceStrategiesContext(
84 expect(workerChoiceStrategiesContext.defaultWorkerChoiceStrategy).toBe(
85 WorkerChoiceStrategies.ROUND_ROBIN
87 const workerChoiceStrategyUndefinedStub = createStubInstance(
88 RoundRobinWorkerChoiceStrategy,
90 choose: stub().returns(undefined),
93 workerChoiceStrategiesContext.workerChoiceStrategies.set(
94 workerChoiceStrategiesContext.defaultWorkerChoiceStrategy,
95 workerChoiceStrategyUndefinedStub
97 expect(() => workerChoiceStrategiesContext.execute()).toThrow(
99 `Worker node key chosen is null or undefined after ${workerChoiceStrategiesContext.retries} retries`
102 const workerChoiceStrategyNullStub = createStubInstance(
103 RoundRobinWorkerChoiceStrategy,
105 choose: stub().returns(null),
108 workerChoiceStrategiesContext.workerChoiceStrategies.set(
109 workerChoiceStrategiesContext.defaultWorkerChoiceStrategy,
110 workerChoiceStrategyNullStub
112 expect(() => workerChoiceStrategiesContext.execute()).toThrow(
114 `Worker node key chosen is null or undefined after ${workerChoiceStrategiesContext.retries} retries`
119 it('Verify that execute() retry until a worker node is chosen', () => {
120 const workerChoiceStrategiesContext = new WorkerChoiceStrategiesContext(
123 const workerChoiceStrategyStub = createStubInstance(
124 RoundRobinWorkerChoiceStrategy,
140 expect(workerChoiceStrategiesContext.defaultWorkerChoiceStrategy).toBe(
141 WorkerChoiceStrategies.ROUND_ROBIN
143 workerChoiceStrategiesContext.workerChoiceStrategies.set(
144 workerChoiceStrategiesContext.defaultWorkerChoiceStrategy,
145 workerChoiceStrategyStub
147 const chosenWorkerKey = workerChoiceStrategiesContext.execute()
149 workerChoiceStrategiesContext.workerChoiceStrategies.get(
150 workerChoiceStrategiesContext.defaultWorkerChoiceStrategy
153 expect(chosenWorkerKey).toBe(1)
156 it('Verify that execute() return the worker node key chosen by the strategy with fixed pool', () => {
157 const workerChoiceStrategiesContext = new WorkerChoiceStrategiesContext(
160 const workerChoiceStrategyStub = createStubInstance(
161 RoundRobinWorkerChoiceStrategy,
163 choose: stub().returns(0),
166 expect(workerChoiceStrategiesContext.defaultWorkerChoiceStrategy).toBe(
167 WorkerChoiceStrategies.ROUND_ROBIN
169 workerChoiceStrategiesContext.workerChoiceStrategies.set(
170 workerChoiceStrategiesContext.defaultWorkerChoiceStrategy,
171 workerChoiceStrategyStub
173 const chosenWorkerKey = workerChoiceStrategiesContext.execute()
175 workerChoiceStrategiesContext.workerChoiceStrategies.get(
176 workerChoiceStrategiesContext.defaultWorkerChoiceStrategy
179 expect(chosenWorkerKey).toBe(0)
182 it('Verify that execute() return the worker node key chosen by the strategy with dynamic pool', () => {
183 const workerChoiceStrategiesContext = new WorkerChoiceStrategiesContext(
186 const workerChoiceStrategyStub = createStubInstance(
187 RoundRobinWorkerChoiceStrategy,
189 choose: stub().returns(0),
192 expect(workerChoiceStrategiesContext.defaultWorkerChoiceStrategy).toBe(
193 WorkerChoiceStrategies.ROUND_ROBIN
195 workerChoiceStrategiesContext.workerChoiceStrategies.set(
196 workerChoiceStrategiesContext.defaultWorkerChoiceStrategy,
197 workerChoiceStrategyStub
199 const chosenWorkerKey = workerChoiceStrategiesContext.execute()
201 workerChoiceStrategiesContext.workerChoiceStrategies.get(
202 workerChoiceStrategiesContext.defaultWorkerChoiceStrategy
205 expect(chosenWorkerKey).toBe(0)
208 it('Verify that setDefaultWorkerChoiceStrategy() works with ROUND_ROBIN and fixed pool', () => {
209 const workerChoiceStrategiesContext = new WorkerChoiceStrategiesContext(
213 workerChoiceStrategiesContext.workerChoiceStrategies.get(
214 workerChoiceStrategiesContext.defaultWorkerChoiceStrategy
216 ).toBeInstanceOf(RoundRobinWorkerChoiceStrategy)
217 workerChoiceStrategiesContext.setDefaultWorkerChoiceStrategy(
218 WorkerChoiceStrategies.ROUND_ROBIN
221 workerChoiceStrategiesContext.workerChoiceStrategies.get(
222 workerChoiceStrategiesContext.defaultWorkerChoiceStrategy
224 ).toBeInstanceOf(RoundRobinWorkerChoiceStrategy)
227 it('Verify that setDefaultWorkerChoiceStrategy() works with ROUND_ROBIN and dynamic pool', () => {
228 const workerChoiceStrategiesContext = new WorkerChoiceStrategiesContext(
232 workerChoiceStrategiesContext.workerChoiceStrategies.get(
233 workerChoiceStrategiesContext.defaultWorkerChoiceStrategy
235 ).toBeInstanceOf(RoundRobinWorkerChoiceStrategy)
236 workerChoiceStrategiesContext.setDefaultWorkerChoiceStrategy(
237 WorkerChoiceStrategies.ROUND_ROBIN
240 workerChoiceStrategiesContext.workerChoiceStrategies.get(
241 workerChoiceStrategiesContext.defaultWorkerChoiceStrategy
243 ).toBeInstanceOf(RoundRobinWorkerChoiceStrategy)
246 it('Verify that setDefaultWorkerChoiceStrategy() works with LEAST_USED and fixed pool', () => {
247 const workerChoiceStrategiesContext = new WorkerChoiceStrategiesContext(
250 workerChoiceStrategiesContext.setDefaultWorkerChoiceStrategy(
251 WorkerChoiceStrategies.LEAST_USED
254 workerChoiceStrategiesContext.workerChoiceStrategies.get(
255 workerChoiceStrategiesContext.defaultWorkerChoiceStrategy
257 ).toBeInstanceOf(LeastUsedWorkerChoiceStrategy)
260 it('Verify that setDefaultWorkerChoiceStrategy() works with LEAST_USED and dynamic pool', () => {
261 const workerChoiceStrategiesContext = new WorkerChoiceStrategiesContext(
264 workerChoiceStrategiesContext.setDefaultWorkerChoiceStrategy(
265 WorkerChoiceStrategies.LEAST_USED
268 workerChoiceStrategiesContext.workerChoiceStrategies.get(
269 workerChoiceStrategiesContext.defaultWorkerChoiceStrategy
271 ).toBeInstanceOf(LeastUsedWorkerChoiceStrategy)
274 it('Verify that setDefaultWorkerChoiceStrategy() works with LEAST_BUSY and fixed pool', () => {
275 const workerChoiceStrategiesContext = new WorkerChoiceStrategiesContext(
278 workerChoiceStrategiesContext.setDefaultWorkerChoiceStrategy(
279 WorkerChoiceStrategies.LEAST_BUSY
282 workerChoiceStrategiesContext.workerChoiceStrategies.get(
283 workerChoiceStrategiesContext.defaultWorkerChoiceStrategy
285 ).toBeInstanceOf(LeastBusyWorkerChoiceStrategy)
288 it('Verify that setDefaultWorkerChoiceStrategy() works with LEAST_BUSY and dynamic pool', () => {
289 const workerChoiceStrategiesContext = new WorkerChoiceStrategiesContext(
292 workerChoiceStrategiesContext.setDefaultWorkerChoiceStrategy(
293 WorkerChoiceStrategies.LEAST_BUSY
296 workerChoiceStrategiesContext.workerChoiceStrategies.get(
297 workerChoiceStrategiesContext.defaultWorkerChoiceStrategy
299 ).toBeInstanceOf(LeastBusyWorkerChoiceStrategy)
302 it('Verify that setDefaultWorkerChoiceStrategy() works with LEAST_ELU and fixed pool', () => {
303 const workerChoiceStrategiesContext = new WorkerChoiceStrategiesContext(
306 workerChoiceStrategiesContext.setDefaultWorkerChoiceStrategy(
307 WorkerChoiceStrategies.LEAST_ELU
310 workerChoiceStrategiesContext.workerChoiceStrategies.get(
311 workerChoiceStrategiesContext.defaultWorkerChoiceStrategy
313 ).toBeInstanceOf(LeastEluWorkerChoiceStrategy)
316 it('Verify that setDefaultWorkerChoiceStrategy() works with LEAST_ELU and dynamic pool', () => {
317 const workerChoiceStrategiesContext = new WorkerChoiceStrategiesContext(
320 workerChoiceStrategiesContext.setDefaultWorkerChoiceStrategy(
321 WorkerChoiceStrategies.LEAST_ELU
324 workerChoiceStrategiesContext.workerChoiceStrategies.get(
325 workerChoiceStrategiesContext.defaultWorkerChoiceStrategy
327 ).toBeInstanceOf(LeastEluWorkerChoiceStrategy)
330 it('Verify that setDefaultWorkerChoiceStrategy() works with FAIR_SHARE and fixed pool', () => {
331 const workerChoiceStrategiesContext = new WorkerChoiceStrategiesContext(
334 workerChoiceStrategiesContext.setDefaultWorkerChoiceStrategy(
335 WorkerChoiceStrategies.FAIR_SHARE
338 workerChoiceStrategiesContext.workerChoiceStrategies.get(
339 workerChoiceStrategiesContext.defaultWorkerChoiceStrategy
341 ).toBeInstanceOf(FairShareWorkerChoiceStrategy)
344 it('Verify that setDefaultWorkerChoiceStrategy() works with FAIR_SHARE and dynamic pool', () => {
345 const workerChoiceStrategiesContext = new WorkerChoiceStrategiesContext(
348 workerChoiceStrategiesContext.setDefaultWorkerChoiceStrategy(
349 WorkerChoiceStrategies.FAIR_SHARE
352 workerChoiceStrategiesContext.workerChoiceStrategies.get(
353 workerChoiceStrategiesContext.defaultWorkerChoiceStrategy
355 ).toBeInstanceOf(FairShareWorkerChoiceStrategy)
358 it('Verify that setDefaultWorkerChoiceStrategy() works with WEIGHTED_ROUND_ROBIN and fixed pool', () => {
359 const workerChoiceStrategiesContext = new WorkerChoiceStrategiesContext(
362 workerChoiceStrategiesContext.setDefaultWorkerChoiceStrategy(
363 WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
366 workerChoiceStrategiesContext.workerChoiceStrategies.get(
367 workerChoiceStrategiesContext.defaultWorkerChoiceStrategy
369 ).toBeInstanceOf(WeightedRoundRobinWorkerChoiceStrategy)
372 it('Verify that setDefaultWorkerChoiceStrategy() works with WEIGHTED_ROUND_ROBIN and dynamic pool', () => {
373 const workerChoiceStrategiesContext = new WorkerChoiceStrategiesContext(
376 workerChoiceStrategiesContext.setDefaultWorkerChoiceStrategy(
377 WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
380 workerChoiceStrategiesContext.workerChoiceStrategies.get(
381 workerChoiceStrategiesContext.defaultWorkerChoiceStrategy
383 ).toBeInstanceOf(WeightedRoundRobinWorkerChoiceStrategy)
386 it('Verify that setDefaultWorkerChoiceStrategy() works with INTERLEAVED_WEIGHTED_ROUND_ROBIN and fixed pool', () => {
387 const workerChoiceStrategiesContext = new WorkerChoiceStrategiesContext(
390 workerChoiceStrategiesContext.setDefaultWorkerChoiceStrategy(
391 WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
394 workerChoiceStrategiesContext.workerChoiceStrategies.get(
395 workerChoiceStrategiesContext.defaultWorkerChoiceStrategy
397 ).toBeInstanceOf(InterleavedWeightedRoundRobinWorkerChoiceStrategy)
400 it('Verify that setDefaultWorkerChoiceStrategy() works with INTERLEAVED_WEIGHTED_ROUND_ROBIN and dynamic pool', () => {
401 const workerChoiceStrategiesContext = new WorkerChoiceStrategiesContext(
404 workerChoiceStrategiesContext.setDefaultWorkerChoiceStrategy(
405 WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
408 workerChoiceStrategiesContext.workerChoiceStrategies.get(
409 workerChoiceStrategiesContext.defaultWorkerChoiceStrategy
411 ).toBeInstanceOf(InterleavedWeightedRoundRobinWorkerChoiceStrategy)
414 it('Verify that worker choice strategy options enable median runtime pool statistics', () => {
415 const wwrWorkerChoiceStrategy = WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
416 let workerChoiceStrategiesContext = new WorkerChoiceStrategiesContext(
418 [wwrWorkerChoiceStrategy],
420 runTime: { median: true },
421 waitTime: { median: true },
425 workerChoiceStrategiesContext.getTaskStatisticsRequirements().runTime
429 workerChoiceStrategiesContext.getTaskStatisticsRequirements().runTime
433 workerChoiceStrategiesContext.getTaskStatisticsRequirements().waitTime
437 workerChoiceStrategiesContext.getTaskStatisticsRequirements().waitTime
440 workerChoiceStrategiesContext = new WorkerChoiceStrategiesContext(
442 [wwrWorkerChoiceStrategy],
444 runTime: { median: true },
445 waitTime: { median: true },
449 workerChoiceStrategiesContext.getTaskStatisticsRequirements().runTime
453 workerChoiceStrategiesContext.getTaskStatisticsRequirements().runTime
457 workerChoiceStrategiesContext.getTaskStatisticsRequirements().waitTime
461 workerChoiceStrategiesContext.getTaskStatisticsRequirements().waitTime
464 const fsWorkerChoiceStrategy = WorkerChoiceStrategies.FAIR_SHARE
465 workerChoiceStrategiesContext = new WorkerChoiceStrategiesContext(
467 [fsWorkerChoiceStrategy],
469 runTime: { median: true },
470 waitTime: { median: true },
474 workerChoiceStrategiesContext.getTaskStatisticsRequirements().runTime
478 workerChoiceStrategiesContext.getTaskStatisticsRequirements().runTime
482 workerChoiceStrategiesContext.getTaskStatisticsRequirements().waitTime
486 workerChoiceStrategiesContext.getTaskStatisticsRequirements().waitTime
489 workerChoiceStrategiesContext = new WorkerChoiceStrategiesContext(
491 [fsWorkerChoiceStrategy],
493 runTime: { median: true },
494 waitTime: { median: true },
498 workerChoiceStrategiesContext.getTaskStatisticsRequirements().runTime
502 workerChoiceStrategiesContext.getTaskStatisticsRequirements().runTime
506 workerChoiceStrategiesContext.getTaskStatisticsRequirements().waitTime
510 workerChoiceStrategiesContext.getTaskStatisticsRequirements().waitTime