feat: conditional task performance computation at the worker level
[poolifier.git] / tests / pools / selection-strategies / worker-choice-strategy-context.test.js
1 const { expect } = require('expect')
2 const sinon = require('sinon')
3 const {
4 FixedThreadPool,
5 DynamicThreadPool,
6 WorkerChoiceStrategies
7 } = require('../../../lib')
8 const {
9 WorkerChoiceStrategyContext
10 } = require('../../../lib/pools/selection-strategies/worker-choice-strategy-context')
11 const {
12 RoundRobinWorkerChoiceStrategy
13 } = require('../../../lib/pools/selection-strategies/round-robin-worker-choice-strategy')
14 const {
15 LeastUsedWorkerChoiceStrategy
16 } = require('../../../lib/pools/selection-strategies/least-used-worker-choice-strategy')
17 const {
18 LeastBusyWorkerChoiceStrategy
19 } = require('../../../lib/pools/selection-strategies/least-busy-worker-choice-strategy')
20 const {
21 FairShareWorkerChoiceStrategy
22 } = require('../../../lib/pools/selection-strategies/fair-share-worker-choice-strategy')
23 const {
24 WeightedRoundRobinWorkerChoiceStrategy
25 } = require('../../../lib/pools/selection-strategies/weighted-round-robin-worker-choice-strategy')
26 const {
27 InterleavedWeightedRoundRobinWorkerChoiceStrategy
28 } = require('../../../lib/pools/selection-strategies/interleaved-weighted-round-robin-worker-choice-strategy')
29
30 describe('Worker choice strategy context test suite', () => {
31 const min = 1
32 const max = 3
33 let fixedPool, dynamicPool
34
35 before(() => {
36 fixedPool = new FixedThreadPool(
37 max,
38 './tests/worker-files/thread/testWorker.js'
39 )
40 dynamicPool = new DynamicThreadPool(
41 min,
42 max,
43 './tests/worker-files/thread/testWorker.js'
44 )
45 })
46
47 afterEach(() => {
48 sinon.restore()
49 })
50
51 after(async () => {
52 await fixedPool.destroy()
53 await dynamicPool.destroy()
54 })
55
56 it('Verify that constructor() initializes the context with all the available worker choice strategies', () => {
57 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
58 fixedPool
59 )
60 expect(workerChoiceStrategyContext.workerChoiceStrategies.size).toBe(
61 Object.keys(WorkerChoiceStrategies).length
62 )
63 })
64
65 it('Verify that execute() return the worker chosen by the strategy with fixed pool', () => {
66 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
67 fixedPool
68 )
69 const WorkerChoiceStrategyStub = sinon.createStubInstance(
70 RoundRobinWorkerChoiceStrategy,
71 {
72 choose: sinon.stub().returns(0)
73 }
74 )
75 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
76 WorkerChoiceStrategies.ROUND_ROBIN
77 )
78 workerChoiceStrategyContext.workerChoiceStrategies.set(
79 workerChoiceStrategyContext.workerChoiceStrategy,
80 WorkerChoiceStrategyStub
81 )
82 const chosenWorkerKey = workerChoiceStrategyContext.execute()
83 expect(
84 workerChoiceStrategyContext.workerChoiceStrategies.get(
85 workerChoiceStrategyContext.workerChoiceStrategy
86 ).choose.calledOnce
87 ).toBe(true)
88 expect(chosenWorkerKey).toBe(0)
89 })
90
91 it('Verify that execute() throws error if null or undefined is returned', () => {
92 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
93 fixedPool
94 )
95 const WorkerChoiceStrategyUndefinedStub = sinon.createStubInstance(
96 RoundRobinWorkerChoiceStrategy,
97 {
98 choose: sinon.stub().returns(undefined)
99 }
100 )
101 const WorkerChoiceStrategyNullStub = sinon.createStubInstance(
102 RoundRobinWorkerChoiceStrategy,
103 {
104 choose: sinon.stub().returns(null)
105 }
106 )
107 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
108 WorkerChoiceStrategies.ROUND_ROBIN
109 )
110 workerChoiceStrategyContext.workerChoiceStrategies.set(
111 workerChoiceStrategyContext.workerChoiceStrategy,
112 WorkerChoiceStrategyUndefinedStub
113 )
114 expect(() => workerChoiceStrategyContext.execute()).toThrowError(
115 new Error('Worker node key chosen is null or undefined')
116 )
117 workerChoiceStrategyContext.workerChoiceStrategies.set(
118 workerChoiceStrategyContext.workerChoiceStrategy,
119 WorkerChoiceStrategyNullStub
120 )
121 expect(() => workerChoiceStrategyContext.execute()).toThrowError(
122 new Error('Worker node key chosen is null or undefined')
123 )
124 })
125
126 it('Verify that execute() return the worker chosen by the strategy with dynamic pool', () => {
127 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
128 dynamicPool
129 )
130 const WorkerChoiceStrategyStub = sinon.createStubInstance(
131 RoundRobinWorkerChoiceStrategy,
132 {
133 choose: sinon.stub().returns(0)
134 }
135 )
136 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
137 WorkerChoiceStrategies.ROUND_ROBIN
138 )
139 workerChoiceStrategyContext.workerChoiceStrategies.set(
140 workerChoiceStrategyContext.workerChoiceStrategy,
141 WorkerChoiceStrategyStub
142 )
143 const chosenWorkerKey = workerChoiceStrategyContext.execute()
144 expect(
145 workerChoiceStrategyContext.workerChoiceStrategies.get(
146 workerChoiceStrategyContext.workerChoiceStrategy
147 ).choose.calledOnce
148 ).toBe(true)
149 expect(chosenWorkerKey).toBe(0)
150 })
151
152 it('Verify that setWorkerChoiceStrategy() works with ROUND_ROBIN and fixed pool', () => {
153 const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN
154 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
155 fixedPool
156 )
157 expect(
158 workerChoiceStrategyContext.workerChoiceStrategies.get(
159 workerChoiceStrategy
160 )
161 ).toBeInstanceOf(RoundRobinWorkerChoiceStrategy)
162 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
163 workerChoiceStrategy
164 )
165 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
166 expect(
167 workerChoiceStrategyContext.workerChoiceStrategies.get(
168 workerChoiceStrategy
169 )
170 ).toBeInstanceOf(RoundRobinWorkerChoiceStrategy)
171 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
172 workerChoiceStrategy
173 )
174 })
175
176 it('Verify that setWorkerChoiceStrategy() works with ROUND_ROBIN and dynamic pool', () => {
177 const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN
178 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
179 dynamicPool
180 )
181 expect(
182 workerChoiceStrategyContext.workerChoiceStrategies.get(
183 workerChoiceStrategy
184 )
185 ).toBeInstanceOf(RoundRobinWorkerChoiceStrategy)
186 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
187 workerChoiceStrategy
188 )
189 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
190 expect(
191 workerChoiceStrategyContext.workerChoiceStrategies.get(
192 workerChoiceStrategy
193 )
194 ).toBeInstanceOf(RoundRobinWorkerChoiceStrategy)
195 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
196 workerChoiceStrategy
197 )
198 })
199
200 it('Verify that setWorkerChoiceStrategy() works with LEAST_USED and fixed pool', () => {
201 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_USED
202 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
203 fixedPool
204 )
205 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
206 expect(
207 workerChoiceStrategyContext.workerChoiceStrategies.get(
208 workerChoiceStrategy
209 )
210 ).toBeInstanceOf(LeastUsedWorkerChoiceStrategy)
211 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
212 workerChoiceStrategy
213 )
214 })
215
216 it('Verify that setWorkerChoiceStrategy() works with LEAST_USED and dynamic pool', () => {
217 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_USED
218 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
219 dynamicPool
220 )
221 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
222 expect(
223 workerChoiceStrategyContext.workerChoiceStrategies.get(
224 workerChoiceStrategy
225 )
226 ).toBeInstanceOf(LeastUsedWorkerChoiceStrategy)
227 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
228 workerChoiceStrategy
229 )
230 })
231
232 it('Verify that setWorkerChoiceStrategy() works with LEAST_BUSY and fixed pool', () => {
233 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_BUSY
234 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
235 fixedPool
236 )
237 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
238 expect(
239 workerChoiceStrategyContext.workerChoiceStrategies.get(
240 workerChoiceStrategy
241 )
242 ).toBeInstanceOf(LeastBusyWorkerChoiceStrategy)
243 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
244 workerChoiceStrategy
245 )
246 })
247
248 it('Verify that setWorkerChoiceStrategy() works with LEAST_BUSY and dynamic pool', () => {
249 const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_BUSY
250 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
251 dynamicPool
252 )
253 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
254 expect(
255 workerChoiceStrategyContext.workerChoiceStrategies.get(
256 workerChoiceStrategy
257 )
258 ).toBeInstanceOf(LeastBusyWorkerChoiceStrategy)
259 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
260 workerChoiceStrategy
261 )
262 })
263
264 it('Verify that setWorkerChoiceStrategy() works with FAIR_SHARE and fixed pool', () => {
265 const workerChoiceStrategy = WorkerChoiceStrategies.FAIR_SHARE
266 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
267 fixedPool
268 )
269 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
270 expect(
271 workerChoiceStrategyContext.workerChoiceStrategies.get(
272 workerChoiceStrategy
273 )
274 ).toBeInstanceOf(FairShareWorkerChoiceStrategy)
275 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
276 workerChoiceStrategy
277 )
278 })
279
280 it('Verify that setWorkerChoiceStrategy() works with FAIR_SHARE and dynamic pool', () => {
281 const workerChoiceStrategy = WorkerChoiceStrategies.FAIR_SHARE
282 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
283 dynamicPool
284 )
285 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
286 expect(
287 workerChoiceStrategyContext.workerChoiceStrategies.get(
288 workerChoiceStrategy
289 )
290 ).toBeInstanceOf(FairShareWorkerChoiceStrategy)
291 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
292 workerChoiceStrategy
293 )
294 })
295
296 it('Verify that setWorkerChoiceStrategy() works with WEIGHTED_ROUND_ROBIN and fixed pool', () => {
297 const workerChoiceStrategy = WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
298 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
299 fixedPool
300 )
301 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
302 expect(
303 workerChoiceStrategyContext.workerChoiceStrategies.get(
304 workerChoiceStrategy
305 )
306 ).toBeInstanceOf(WeightedRoundRobinWorkerChoiceStrategy)
307 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
308 workerChoiceStrategy
309 )
310 })
311
312 it('Verify that setWorkerChoiceStrategy() works with WEIGHTED_ROUND_ROBIN and dynamic pool', () => {
313 const workerChoiceStrategy = WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
314 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
315 dynamicPool
316 )
317 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
318 expect(
319 workerChoiceStrategyContext.workerChoiceStrategies.get(
320 workerChoiceStrategy
321 )
322 ).toBeInstanceOf(WeightedRoundRobinWorkerChoiceStrategy)
323 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
324 workerChoiceStrategy
325 )
326 })
327
328 it('Verify that setWorkerChoiceStrategy() works with INTERLEAVED_WEIGHTED_ROUND_ROBIN and fixed pool', () => {
329 const workerChoiceStrategy =
330 WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
331 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
332 fixedPool
333 )
334 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
335 expect(
336 workerChoiceStrategyContext.workerChoiceStrategies.get(
337 workerChoiceStrategy
338 )
339 ).toBeInstanceOf(InterleavedWeightedRoundRobinWorkerChoiceStrategy)
340 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
341 workerChoiceStrategy
342 )
343 })
344
345 it('Verify that setWorkerChoiceStrategy() works with INTERLEAVED_WEIGHTED_ROUND_ROBIN and dynamic pool', () => {
346 const workerChoiceStrategy =
347 WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
348 const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
349 dynamicPool
350 )
351 workerChoiceStrategyContext.setWorkerChoiceStrategy(workerChoiceStrategy)
352 expect(
353 workerChoiceStrategyContext.workerChoiceStrategies.get(
354 workerChoiceStrategy
355 )
356 ).toBeInstanceOf(InterleavedWeightedRoundRobinWorkerChoiceStrategy)
357 expect(workerChoiceStrategyContext.workerChoiceStrategy).toBe(
358 workerChoiceStrategy
359 )
360 })
361
362 it('Verify that worker choice strategy options enable median runtime pool statistics', () => {
363 const wwrWorkerChoiceStrategy = WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN
364 let workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
365 fixedPool,
366 wwrWorkerChoiceStrategy,
367 {
368 medRunTime: true
369 }
370 )
371 expect(workerChoiceStrategyContext.getTaskStatistics().avgRunTime).toBe(
372 false
373 )
374 expect(workerChoiceStrategyContext.getTaskStatistics().medRunTime).toBe(
375 true
376 )
377 workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
378 dynamicPool,
379 wwrWorkerChoiceStrategy,
380 {
381 medRunTime: true
382 }
383 )
384 expect(workerChoiceStrategyContext.getTaskStatistics().avgRunTime).toBe(
385 false
386 )
387 expect(workerChoiceStrategyContext.getTaskStatistics().medRunTime).toBe(
388 true
389 )
390 const fsWorkerChoiceStrategy = WorkerChoiceStrategies.FAIR_SHARE
391 workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
392 fixedPool,
393 fsWorkerChoiceStrategy,
394 {
395 medRunTime: true
396 }
397 )
398 expect(workerChoiceStrategyContext.getTaskStatistics().avgRunTime).toBe(
399 false
400 )
401 expect(workerChoiceStrategyContext.getTaskStatistics().medRunTime).toBe(
402 true
403 )
404 workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
405 dynamicPool,
406 fsWorkerChoiceStrategy,
407 {
408 medRunTime: true
409 }
410 )
411 expect(workerChoiceStrategyContext.getTaskStatistics().avgRunTime).toBe(
412 false
413 )
414 expect(workerChoiceStrategyContext.getTaskStatistics().medRunTime).toBe(
415 true
416 )
417 })
418 })