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() return the worker node key chosen by the strategy with fixed pool', () => {
64 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
67 const workerChoiceStrategyStub = createStubInstance(
68 RoundRobinWorkerChoiceStrategy,
70 hasPoolWorkerNodesReady: stub().returns(true),
71 choose: stub().returns(0)
74 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
75 WorkerChoiceStrategies.ROUND_ROBIN
77 workerChoiceStrategyContext.workerChoiceStrategies.set(
78 workerChoiceStrategyContext.workerChoiceStrategy,
79 workerChoiceStrategyStub
81 const chosenWorkerKey = workerChoiceStrategyContext.execute()
83 workerChoiceStrategyContext.workerChoiceStrategies.get(
84 workerChoiceStrategyContext.workerChoiceStrategy
87 expect(chosenWorkerKey).toBe(0)
90 it('Verify that execute() throws error if null or undefined is returned after retries', () => {
91 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
94 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
95 WorkerChoiceStrategies.ROUND_ROBIN
97 const workerChoiceStrategyUndefinedStub = createStubInstance(
98 RoundRobinWorkerChoiceStrategy,
100 hasPoolWorkerNodesReady: stub().returns(true),
101 choose: stub().returns(undefined)
104 workerChoiceStrategyContext.workerChoiceStrategies.set(
105 workerChoiceStrategyContext.workerChoiceStrategy,
106 workerChoiceStrategyUndefinedStub
108 expect(() => workerChoiceStrategyContext.execute()).toThrow(
110 `Worker node key chosen is null or undefined after ${workerChoiceStrategyContext.retries} retries`
113 const workerChoiceStrategyNullStub = createStubInstance(
114 RoundRobinWorkerChoiceStrategy,
116 hasPoolWorkerNodesReady: stub().returns(true),
117 choose: stub().returns(null)
120 workerChoiceStrategyContext.workerChoiceStrategies.set(
121 workerChoiceStrategyContext.workerChoiceStrategy,
122 workerChoiceStrategyNullStub
124 expect(() => workerChoiceStrategyContext.execute()).toThrow(
126 `Worker node key chosen is null or undefined after ${workerChoiceStrategyContext.retries} retries`
131 it('Verify that execute() retry until a worker node is ready and chosen', () => {
132 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
135 const workerChoiceStrategyStub = createStubInstance(
136 RoundRobinWorkerChoiceStrategy,
138 hasPoolWorkerNodesReady: stub()
150 choose: stub().returns(1)
153 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
154 WorkerChoiceStrategies.ROUND_ROBIN
156 workerChoiceStrategyContext.workerChoiceStrategies.set(
157 workerChoiceStrategyContext.workerChoiceStrategy,
158 workerChoiceStrategyStub
160 const chosenWorkerKey = workerChoiceStrategyContext.execute()
162 workerChoiceStrategyContext.workerChoiceStrategies.get(
163 workerChoiceStrategyContext.workerChoiceStrategy
166 expect(chosenWorkerKey).toBe(1)
169 it('Verify that execute() return the worker node key chosen by the strategy with dynamic pool', () => {
170 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
173 const workerChoiceStrategyStub = createStubInstance(
174 RoundRobinWorkerChoiceStrategy,
176 hasPoolWorkerNodesReady: stub().returns(true),
177 choose: stub().returns(0)
180 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
181 WorkerChoiceStrategies.ROUND_ROBIN
183 workerChoiceStrategyContext.workerChoiceStrategies.set(
184 workerChoiceStrategyContext.workerChoiceStrategy,
185 workerChoiceStrategyStub
187 const chosenWorkerKey = workerChoiceStrategyContext.execute()
189 workerChoiceStrategyContext.workerChoiceStrategies.get(
190 workerChoiceStrategyContext.workerChoiceStrategy
193 expect(chosenWorkerKey).toBe(0)
196 it('Verify that setWorkerChoiceStrategy() works with ROUND_ROBIN and fixed pool', () => {
197 const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN
198 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
202 workerChoiceStrategyContext.workerChoiceStrategies.get(
205 ).toBeInstanceOf(RoundRobinWorkerChoiceStrategy)
206 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
209 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
211 workerChoiceStrategyContext.workerChoiceStrategies.get(
214 ).toBeInstanceOf(RoundRobinWorkerChoiceStrategy)
215 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
220 it('Verify that setWorkerChoiceStrategy() works with ROUND_ROBIN and dynamic pool', () => {
221 const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN
222 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
226 workerChoiceStrategyContext.workerChoiceStrategies.get(
229 ).toBeInstanceOf(RoundRobinWorkerChoiceStrategy)
230 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
233 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
235 workerChoiceStrategyContext.workerChoiceStrategies.get(
238 ).toBeInstanceOf(RoundRobinWorkerChoiceStrategy)
239 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
244 it('Verify that setWorkerChoiceStrategy() works with LEAST_USED and fixed pool', () => {
245 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_USED
246 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
249 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
251 workerChoiceStrategyContext.workerChoiceStrategies.get(
254 ).toBeInstanceOf(LeastUsedWorkerChoiceStrategy)
255 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
260 it('Verify that setWorkerChoiceStrategy() works with LEAST_USED and dynamic pool', () => {
261 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_USED
262 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
265 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
267 workerChoiceStrategyContext.workerChoiceStrategies.get(
270 ).toBeInstanceOf(LeastUsedWorkerChoiceStrategy)
271 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
276 it('Verify that setWorkerChoiceStrategy() works with LEAST_BUSY and fixed pool', () => {
277 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_BUSY
278 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
281 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
283 workerChoiceStrategyContext.workerChoiceStrategies.get(
286 ).toBeInstanceOf(LeastBusyWorkerChoiceStrategy)
287 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
292 it('Verify that setWorkerChoiceStrategy() works with LEAST_BUSY and dynamic pool', () => {
293 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_BUSY
294 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
297 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
299 workerChoiceStrategyContext.workerChoiceStrategies.get(
302 ).toBeInstanceOf(LeastBusyWorkerChoiceStrategy)
303 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
308 it('Verify that setWorkerChoiceStrategy() works with LEAST_ELU and fixed pool', () => {
309 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_ELU
310 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
313 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
315 workerChoiceStrategyContext.workerChoiceStrategies.get(
318 ).toBeInstanceOf(LeastEluWorkerChoiceStrategy)
319 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
324 it('Verify that setWorkerChoiceStrategy() works with LEAST_ELU and dynamic pool', () => {
325 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_ELU
326 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
329 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
331 workerChoiceStrategyContext.workerChoiceStrategies.get(
334 ).toBeInstanceOf(LeastEluWorkerChoiceStrategy)
335 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
340 it('Verify that setWorkerChoiceStrategy() works with FAIR_SHARE and fixed pool', () => {
341 const workerChoiceStrategy = WorkerChoiceStrategies.FAIR_SHARE
342 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
345 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
347 workerChoiceStrategyContext.workerChoiceStrategies.get(
350 ).toBeInstanceOf(FairShareWorkerChoiceStrategy)
351 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
356 it('Verify that setWorkerChoiceStrategy() works with FAIR_SHARE and dynamic pool', () => {
357 const workerChoiceStrategy = WorkerChoiceStrategies.FAIR_SHARE
358 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
361 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
363 workerChoiceStrategyContext.workerChoiceStrategies.get(
366 ).toBeInstanceOf(FairShareWorkerChoiceStrategy)
367 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
372 it('Verify that setWorkerChoiceStrategy() works with WEIGHTED_ROUND_ROBIN and fixed pool', () => {
373 const workerChoiceStrategy = WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
374 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
377 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
379 workerChoiceStrategyContext.workerChoiceStrategies.get(
382 ).toBeInstanceOf(WeightedRoundRobinWorkerChoiceStrategy)
383 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
388 it('Verify that setWorkerChoiceStrategy() works with WEIGHTED_ROUND_ROBIN and dynamic pool', () => {
389 const workerChoiceStrategy = WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
390 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
393 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
395 workerChoiceStrategyContext.workerChoiceStrategies.get(
398 ).toBeInstanceOf(WeightedRoundRobinWorkerChoiceStrategy)
399 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
404 it('Verify that setWorkerChoiceStrategy() works with INTERLEAVED_WEIGHTED_ROUND_ROBIN and fixed pool', () => {
405 const workerChoiceStrategy =
406 WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
407 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
410 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
412 workerChoiceStrategyContext.workerChoiceStrategies.get(
415 ).toBeInstanceOf(InterleavedWeightedRoundRobinWorkerChoiceStrategy)
416 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
421 it('Verify that setWorkerChoiceStrategy() works with INTERLEAVED_WEIGHTED_ROUND_ROBIN and dynamic pool', () => {
422 const workerChoiceStrategy =
423 WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
424 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
427 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
429 workerChoiceStrategyContext.workerChoiceStrategies.get(
432 ).toBeInstanceOf(InterleavedWeightedRoundRobinWorkerChoiceStrategy)
433 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
438 it('Verify that worker choice strategy options enable median runtime pool statistics', () => {
439 const wwrWorkerChoiceStrategy = WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
440 let workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
442 wwrWorkerChoiceStrategy,
444 runTime: { median: true }
448 workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime
452 workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.median
454 workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
456 wwrWorkerChoiceStrategy,
458 runTime: { median: true }
462 workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime
466 workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.median
468 const fsWorkerChoiceStrategy = WorkerChoiceStrategies.FAIR_SHARE
469 workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
471 fsWorkerChoiceStrategy,
473 runTime: { median: true }
477 workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime
481 workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.median
483 workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
485 fsWorkerChoiceStrategy,
487 runTime: { median: true }
491 workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime
495 workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.median