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()
141 choose: stub().returns(1)
144 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
145 WorkerChoiceStrategies.ROUND_ROBIN
147 workerChoiceStrategyContext.workerChoiceStrategies.set(
148 workerChoiceStrategyContext.workerChoiceStrategy,
149 workerChoiceStrategyStub
151 const chosenWorkerKey = workerChoiceStrategyContext.execute()
153 workerChoiceStrategyContext.workerChoiceStrategies.get(
154 workerChoiceStrategyContext.workerChoiceStrategy
155 ).hasPoolWorkerNodesReady.callCount
158 workerChoiceStrategyContext.workerChoiceStrategies.get(
159 workerChoiceStrategyContext.workerChoiceStrategy
162 expect(chosenWorkerKey).toBe(1)
165 it('Verify that execute() throws error if worker choice strategy consecutive executions has been reached', () => {
166 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
169 const workerChoiceStrategyStub = createStubInstance(
170 RoundRobinWorkerChoiceStrategy,
172 hasPoolWorkerNodesReady: stub().returns(false),
173 choose: stub().returns(0)
176 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
177 WorkerChoiceStrategies.ROUND_ROBIN
179 workerChoiceStrategyContext.workerChoiceStrategies.set(
180 workerChoiceStrategyContext.workerChoiceStrategy,
181 workerChoiceStrategyStub
183 expect(() => workerChoiceStrategyContext.execute()).toThrow(
185 'Worker choice strategy consecutive executions has exceeded the maximum of 10000'
190 it('Verify that execute() return the worker node key chosen by the strategy with dynamic pool', () => {
191 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
194 const workerChoiceStrategyStub = createStubInstance(
195 RoundRobinWorkerChoiceStrategy,
197 hasPoolWorkerNodesReady: stub().returns(true),
198 choose: stub().returns(0)
201 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
202 WorkerChoiceStrategies.ROUND_ROBIN
204 workerChoiceStrategyContext.workerChoiceStrategies.set(
205 workerChoiceStrategyContext.workerChoiceStrategy,
206 workerChoiceStrategyStub
208 const chosenWorkerKey = workerChoiceStrategyContext.execute()
210 workerChoiceStrategyContext.workerChoiceStrategies.get(
211 workerChoiceStrategyContext.workerChoiceStrategy
214 expect(chosenWorkerKey).toBe(0)
217 it('Verify that setWorkerChoiceStrategy() works with ROUND_ROBIN and fixed pool', () => {
218 const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN
219 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
223 workerChoiceStrategyContext.workerChoiceStrategies.get(
226 ).toBeInstanceOf(RoundRobinWorkerChoiceStrategy)
227 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
230 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
232 workerChoiceStrategyContext.workerChoiceStrategies.get(
235 ).toBeInstanceOf(RoundRobinWorkerChoiceStrategy)
236 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
241 it('Verify that setWorkerChoiceStrategy() works with ROUND_ROBIN and dynamic pool', () => {
242 const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN
243 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
247 workerChoiceStrategyContext.workerChoiceStrategies.get(
250 ).toBeInstanceOf(RoundRobinWorkerChoiceStrategy)
251 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
254 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
256 workerChoiceStrategyContext.workerChoiceStrategies.get(
259 ).toBeInstanceOf(RoundRobinWorkerChoiceStrategy)
260 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
265 it('Verify that setWorkerChoiceStrategy() works with LEAST_USED and fixed pool', () => {
266 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_USED
267 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
270 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
272 workerChoiceStrategyContext.workerChoiceStrategies.get(
275 ).toBeInstanceOf(LeastUsedWorkerChoiceStrategy)
276 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
281 it('Verify that setWorkerChoiceStrategy() works with LEAST_USED and dynamic pool', () => {
282 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_USED
283 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
286 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
288 workerChoiceStrategyContext.workerChoiceStrategies.get(
291 ).toBeInstanceOf(LeastUsedWorkerChoiceStrategy)
292 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
297 it('Verify that setWorkerChoiceStrategy() works with LEAST_BUSY and fixed pool', () => {
298 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_BUSY
299 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
302 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
304 workerChoiceStrategyContext.workerChoiceStrategies.get(
307 ).toBeInstanceOf(LeastBusyWorkerChoiceStrategy)
308 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
313 it('Verify that setWorkerChoiceStrategy() works with LEAST_BUSY and dynamic pool', () => {
314 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_BUSY
315 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
318 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
320 workerChoiceStrategyContext.workerChoiceStrategies.get(
323 ).toBeInstanceOf(LeastBusyWorkerChoiceStrategy)
324 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
329 it('Verify that setWorkerChoiceStrategy() works with LEAST_ELU and fixed pool', () => {
330 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_ELU
331 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
334 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
336 workerChoiceStrategyContext.workerChoiceStrategies.get(
339 ).toBeInstanceOf(LeastEluWorkerChoiceStrategy)
340 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
345 it('Verify that setWorkerChoiceStrategy() works with LEAST_ELU and dynamic pool', () => {
346 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_ELU
347 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
350 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
352 workerChoiceStrategyContext.workerChoiceStrategies.get(
355 ).toBeInstanceOf(LeastEluWorkerChoiceStrategy)
356 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
361 it('Verify that setWorkerChoiceStrategy() works with FAIR_SHARE and fixed pool', () => {
362 const workerChoiceStrategy = WorkerChoiceStrategies.FAIR_SHARE
363 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
366 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
368 workerChoiceStrategyContext.workerChoiceStrategies.get(
371 ).toBeInstanceOf(FairShareWorkerChoiceStrategy)
372 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
377 it('Verify that setWorkerChoiceStrategy() works with FAIR_SHARE and dynamic pool', () => {
378 const workerChoiceStrategy = WorkerChoiceStrategies.FAIR_SHARE
379 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
382 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
384 workerChoiceStrategyContext.workerChoiceStrategies.get(
387 ).toBeInstanceOf(FairShareWorkerChoiceStrategy)
388 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
393 it('Verify that setWorkerChoiceStrategy() works with WEIGHTED_ROUND_ROBIN and fixed pool', () => {
394 const workerChoiceStrategy = WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
395 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
398 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
400 workerChoiceStrategyContext.workerChoiceStrategies.get(
403 ).toBeInstanceOf(WeightedRoundRobinWorkerChoiceStrategy)
404 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
409 it('Verify that setWorkerChoiceStrategy() works with WEIGHTED_ROUND_ROBIN and dynamic pool', () => {
410 const workerChoiceStrategy = WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
411 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
414 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
416 workerChoiceStrategyContext.workerChoiceStrategies.get(
419 ).toBeInstanceOf(WeightedRoundRobinWorkerChoiceStrategy)
420 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
425 it('Verify that setWorkerChoiceStrategy() works with INTERLEAVED_WEIGHTED_ROUND_ROBIN and fixed pool', () => {
426 const workerChoiceStrategy =
427 WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
428 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
431 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
433 workerChoiceStrategyContext.workerChoiceStrategies.get(
436 ).toBeInstanceOf(InterleavedWeightedRoundRobinWorkerChoiceStrategy)
437 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
442 it('Verify that setWorkerChoiceStrategy() works with INTERLEAVED_WEIGHTED_ROUND_ROBIN and dynamic pool', () => {
443 const workerChoiceStrategy =
444 WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
445 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
448 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
450 workerChoiceStrategyContext.workerChoiceStrategies.get(
453 ).toBeInstanceOf(InterleavedWeightedRoundRobinWorkerChoiceStrategy)
454 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
459 it('Verify that worker choice strategy options enable median runtime pool statistics', () => {
460 const wwrWorkerChoiceStrategy = WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
461 let workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
463 wwrWorkerChoiceStrategy,
465 runTime: { median: true }
469 workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime
473 workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.median
475 workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
477 wwrWorkerChoiceStrategy,
479 runTime: { median: true }
483 workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime
487 workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.median
489 const fsWorkerChoiceStrategy = WorkerChoiceStrategies.FAIR_SHARE
490 workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
492 fsWorkerChoiceStrategy,
494 runTime: { median: true }
498 workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime
502 workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.median
504 workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
506 fsWorkerChoiceStrategy,
508 runTime: { median: true }
512 workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime
516 workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.median