1 import { expect } from 'expect'
2 import { createStubInstance, restore, stub } from 'sinon'
7 } from '../../../lib/index.js'
8 import { WorkerChoiceStrategyContext } from '../../../lib/pools/selection-strategies/worker-choice-strategy-context.js'
9 import { RoundRobinWorkerChoiceStrategy } from '../../../lib/pools/selection-strategies/round-robin-worker-choice-strategy.js'
10 import { LeastUsedWorkerChoiceStrategy } from '../../../lib/pools/selection-strategies/least-used-worker-choice-strategy.js'
11 import { LeastBusyWorkerChoiceStrategy } from '../../../lib/pools/selection-strategies/least-busy-worker-choice-strategy.js'
12 import { LeastEluWorkerChoiceStrategy } from '../../../lib/pools/selection-strategies/least-elu-worker-choice-strategy.js'
13 import { FairShareWorkerChoiceStrategy } from '../../../lib/pools/selection-strategies/fair-share-worker-choice-strategy.js'
14 import { WeightedRoundRobinWorkerChoiceStrategy } from '../../../lib/pools/selection-strategies/weighted-round-robin-worker-choice-strategy.js'
15 import { InterleavedWeightedRoundRobinWorkerChoiceStrategy } from '../../../lib/pools/selection-strategies/interleaved-weighted-round-robin-worker-choice-strategy.js'
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 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
47 expect(workerChoiceStrategyContext.workerChoiceStrategies.size).toBe(
48 Object.keys(WorkerChoiceStrategies).length
52 it('Verify that execute() return the worker node key chosen by the strategy with fixed pool', () => {
53 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
56 const workerChoiceStrategyStub = createStubInstance(
57 RoundRobinWorkerChoiceStrategy,
59 hasPoolWorkerNodesReady: stub().returns(true),
60 choose: stub().returns(0)
63 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
64 WorkerChoiceStrategies.ROUND_ROBIN
66 workerChoiceStrategyContext.workerChoiceStrategies.set(
67 workerChoiceStrategyContext.workerChoiceStrategy,
68 workerChoiceStrategyStub
70 const chosenWorkerKey = workerChoiceStrategyContext.execute()
72 workerChoiceStrategyContext.workerChoiceStrategies.get(
73 workerChoiceStrategyContext.workerChoiceStrategy
76 expect(chosenWorkerKey).toBe(0)
79 it('Verify that execute() throws error if null or undefined is returned after retries', () => {
80 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
83 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
84 WorkerChoiceStrategies.ROUND_ROBIN
86 const workerChoiceStrategyUndefinedStub = createStubInstance(
87 RoundRobinWorkerChoiceStrategy,
89 hasPoolWorkerNodesReady: stub().returns(true),
90 choose: stub().returns(undefined)
93 workerChoiceStrategyContext.workerChoiceStrategies.set(
94 workerChoiceStrategyContext.workerChoiceStrategy,
95 workerChoiceStrategyUndefinedStub
97 expect(() => workerChoiceStrategyContext.execute()).toThrow(
98 new Error('Worker node key chosen is null or undefined after 6 retries')
100 const workerChoiceStrategyNullStub = createStubInstance(
101 RoundRobinWorkerChoiceStrategy,
103 hasPoolWorkerNodesReady: stub().returns(true),
104 choose: stub().returns(null)
107 workerChoiceStrategyContext.workerChoiceStrategies.set(
108 workerChoiceStrategyContext.workerChoiceStrategy,
109 workerChoiceStrategyNullStub
111 expect(() => workerChoiceStrategyContext.execute()).toThrow(
112 new Error('Worker node key chosen is null or undefined after 6 retries')
116 it('Verify that execute() retry until a worker node is ready and chosen', () => {
117 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
120 const workerChoiceStrategyStub = createStubInstance(
121 RoundRobinWorkerChoiceStrategy,
123 hasPoolWorkerNodesReady: stub()
135 choose: stub().returns(1)
138 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
139 WorkerChoiceStrategies.ROUND_ROBIN
141 workerChoiceStrategyContext.workerChoiceStrategies.set(
142 workerChoiceStrategyContext.workerChoiceStrategy,
143 workerChoiceStrategyStub
145 const chosenWorkerKey = workerChoiceStrategyContext.execute()
147 workerChoiceStrategyContext.workerChoiceStrategies.get(
148 workerChoiceStrategyContext.workerChoiceStrategy
149 ).hasPoolWorkerNodesReady.callCount
152 workerChoiceStrategyContext.workerChoiceStrategies.get(
153 workerChoiceStrategyContext.workerChoiceStrategy
156 expect(chosenWorkerKey).toBe(1)
159 it('Verify that execute() throws error if worker choice strategy recursion reach the maximum depth', () => {
160 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
163 const workerChoiceStrategyStub = createStubInstance(
164 RoundRobinWorkerChoiceStrategy,
166 hasPoolWorkerNodesReady: stub().returns(false),
167 choose: stub().returns(0)
170 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
171 WorkerChoiceStrategies.ROUND_ROBIN
173 workerChoiceStrategyContext.workerChoiceStrategies.set(
174 workerChoiceStrategyContext.workerChoiceStrategy,
175 workerChoiceStrategyStub
177 expect(() => workerChoiceStrategyContext.execute()).toThrow(
178 new RangeError('Maximum call stack size exceeded')
182 it('Verify that execute() return the worker node key chosen by the strategy with dynamic pool', () => {
183 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
186 const workerChoiceStrategyStub = createStubInstance(
187 RoundRobinWorkerChoiceStrategy,
189 hasPoolWorkerNodesReady: stub().returns(true),
190 choose: stub().returns(0)
193 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
194 WorkerChoiceStrategies.ROUND_ROBIN
196 workerChoiceStrategyContext.workerChoiceStrategies.set(
197 workerChoiceStrategyContext.workerChoiceStrategy,
198 workerChoiceStrategyStub
200 const chosenWorkerKey = workerChoiceStrategyContext.execute()
202 workerChoiceStrategyContext.workerChoiceStrategies.get(
203 workerChoiceStrategyContext.workerChoiceStrategy
206 expect(chosenWorkerKey).toBe(0)
209 it('Verify that setWorkerChoiceStrategy() works with ROUND_ROBIN and fixed pool', () => {
210 const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN
211 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
215 workerChoiceStrategyContext.workerChoiceStrategies.get(
218 ).toBeInstanceOf(RoundRobinWorkerChoiceStrategy)
219 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
222 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
224 workerChoiceStrategyContext.workerChoiceStrategies.get(
227 ).toBeInstanceOf(RoundRobinWorkerChoiceStrategy)
228 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
233 it('Verify that setWorkerChoiceStrategy() works with ROUND_ROBIN and dynamic pool', () => {
234 const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN
235 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
239 workerChoiceStrategyContext.workerChoiceStrategies.get(
242 ).toBeInstanceOf(RoundRobinWorkerChoiceStrategy)
243 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
246 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
248 workerChoiceStrategyContext.workerChoiceStrategies.get(
251 ).toBeInstanceOf(RoundRobinWorkerChoiceStrategy)
252 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
257 it('Verify that setWorkerChoiceStrategy() works with LEAST_USED and fixed pool', () => {
258 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_USED
259 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
262 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
264 workerChoiceStrategyContext.workerChoiceStrategies.get(
267 ).toBeInstanceOf(LeastUsedWorkerChoiceStrategy)
268 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
273 it('Verify that setWorkerChoiceStrategy() works with LEAST_USED and dynamic pool', () => {
274 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_USED
275 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
278 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
280 workerChoiceStrategyContext.workerChoiceStrategies.get(
283 ).toBeInstanceOf(LeastUsedWorkerChoiceStrategy)
284 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
289 it('Verify that setWorkerChoiceStrategy() works with LEAST_BUSY and fixed pool', () => {
290 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_BUSY
291 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
294 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
296 workerChoiceStrategyContext.workerChoiceStrategies.get(
299 ).toBeInstanceOf(LeastBusyWorkerChoiceStrategy)
300 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
305 it('Verify that setWorkerChoiceStrategy() works with LEAST_BUSY and dynamic pool', () => {
306 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_BUSY
307 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
310 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
312 workerChoiceStrategyContext.workerChoiceStrategies.get(
315 ).toBeInstanceOf(LeastBusyWorkerChoiceStrategy)
316 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
321 it('Verify that setWorkerChoiceStrategy() works with LEAST_ELU and fixed pool', () => {
322 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_ELU
323 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
326 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
328 workerChoiceStrategyContext.workerChoiceStrategies.get(
331 ).toBeInstanceOf(LeastEluWorkerChoiceStrategy)
332 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
337 it('Verify that setWorkerChoiceStrategy() works with LEAST_ELU and dynamic pool', () => {
338 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_ELU
339 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
342 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
344 workerChoiceStrategyContext.workerChoiceStrategies.get(
347 ).toBeInstanceOf(LeastEluWorkerChoiceStrategy)
348 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
353 it('Verify that setWorkerChoiceStrategy() works with FAIR_SHARE and fixed pool', () => {
354 const workerChoiceStrategy = WorkerChoiceStrategies.FAIR_SHARE
355 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
358 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
360 workerChoiceStrategyContext.workerChoiceStrategies.get(
363 ).toBeInstanceOf(FairShareWorkerChoiceStrategy)
364 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
369 it('Verify that setWorkerChoiceStrategy() works with FAIR_SHARE and dynamic pool', () => {
370 const workerChoiceStrategy = WorkerChoiceStrategies.FAIR_SHARE
371 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
374 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
376 workerChoiceStrategyContext.workerChoiceStrategies.get(
379 ).toBeInstanceOf(FairShareWorkerChoiceStrategy)
380 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
385 it('Verify that setWorkerChoiceStrategy() works with WEIGHTED_ROUND_ROBIN and fixed pool', () => {
386 const workerChoiceStrategy = WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
387 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
390 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
392 workerChoiceStrategyContext.workerChoiceStrategies.get(
395 ).toBeInstanceOf(WeightedRoundRobinWorkerChoiceStrategy)
396 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
401 it('Verify that setWorkerChoiceStrategy() works with WEIGHTED_ROUND_ROBIN and dynamic pool', () => {
402 const workerChoiceStrategy = WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
403 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
406 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
408 workerChoiceStrategyContext.workerChoiceStrategies.get(
411 ).toBeInstanceOf(WeightedRoundRobinWorkerChoiceStrategy)
412 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
417 it('Verify that setWorkerChoiceStrategy() works with INTERLEAVED_WEIGHTED_ROUND_ROBIN and fixed 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 setWorkerChoiceStrategy() works with INTERLEAVED_WEIGHTED_ROUND_ROBIN and dynamic pool', () => {
435 const workerChoiceStrategy =
436 WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
437 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
440 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
442 workerChoiceStrategyContext.workerChoiceStrategies.get(
445 ).toBeInstanceOf(InterleavedWeightedRoundRobinWorkerChoiceStrategy)
446 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
451 it('Verify that worker choice strategy options enable median runtime pool statistics', () => {
452 const wwrWorkerChoiceStrategy = WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
453 let workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
455 wwrWorkerChoiceStrategy,
457 runTime: { median: true }
461 workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime
465 workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.median
467 workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
469 wwrWorkerChoiceStrategy,
471 runTime: { median: true }
475 workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime
479 workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.median
481 const fsWorkerChoiceStrategy = WorkerChoiceStrategies.FAIR_SHARE
482 workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
484 fsWorkerChoiceStrategy,
486 runTime: { median: true }
490 workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime
494 workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.median
496 workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
498 fsWorkerChoiceStrategy,
500 runTime: { median: true }
504 workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime
508 workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.median