Fix tests with WRR worker choice strategy
[poolifier.git] / tests / pools / abstract / abstract-pool.test.js
CommitLineData
a61a0724 1const { expect } = require('expect')
e843b904
JB
2const {
3 FixedClusterPool,
4 FixedThreadPool,
5 WorkerChoiceStrategies
6} = require('../../../lib/index')
7c0ba920 7const numberOfWorkers = 1
bf9549ae
JB
8const workerNotFoundInTasksUsageMapError = new Error(
9 'Worker could not be found in worker tasks usage map'
10)
bf9549ae 11class StubPoolWithWorkerTasksUsageMapClear extends FixedThreadPool {
3ec964d6 12 removeAllWorker () {
bf9549ae 13 this.workersTasksUsage.clear()
3ec964d6 14 }
15}
3ec964d6 16class StubPoolWithIsMainMethod extends FixedThreadPool {
17 isMain () {
18 return false
19 }
20}
21
a35560ba 22describe('Abstract pool test suite', () => {
3ec964d6 23 it('Simulate pool creation from a non main thread/process', () => {
8d3782fa
JB
24 expect(
25 () =>
26 new StubPoolWithIsMainMethod(
7c0ba920 27 numberOfWorkers,
8d3782fa
JB
28 './tests/worker-files/thread/testWorker.js',
29 {
30 errorHandler: e => console.error(e)
31 }
32 )
33 ).toThrowError(new Error('Cannot start a pool from a worker!'))
3ec964d6 34 })
c510fea7
APA
35
36 it('Verify that filePath is checked', () => {
292ad316
JB
37 const expectedError = new Error(
38 'Please specify a file with a worker implementation'
39 )
7c0ba920 40 expect(() => new FixedThreadPool(numberOfWorkers)).toThrowError(
292ad316 41 expectedError
8d3782fa 42 )
7c0ba920 43 expect(() => new FixedThreadPool(numberOfWorkers, '')).toThrowError(
292ad316 44 expectedError
8d3782fa
JB
45 )
46 })
47
48 it('Verify that numberOfWorkers is checked', () => {
49 expect(() => new FixedThreadPool()).toThrowError(
50 new Error(
51 'Cannot instantiate a pool without specifying the number of workers'
52 )
53 )
54 })
55
56 it('Verify that a negative number of workers is checked', () => {
57 expect(
58 () =>
59 new FixedClusterPool(-1, './tests/worker-files/cluster/testWorker.js')
60 ).toThrowError(
61 new Error('Cannot instantiate a pool with a negative number of workers')
62 )
63 })
64
65 it('Verify that a non integer number of workers is checked', () => {
66 expect(
67 () =>
68 new FixedThreadPool(0.25, './tests/worker-files/thread/testWorker.js')
69 ).toThrowError(
70 new Error(
71 'Cannot instantiate a pool with a non integer number of workers'
72 )
73 )
c510fea7 74 })
7c0ba920
JB
75
76 it('Verify that pool options are checked', () => {
77 let pool = new FixedThreadPool(
78 numberOfWorkers,
79 './tests/worker-files/thread/testWorker.js'
80 )
8620fb25 81 expect(pool.opts.enableEvents).toBe(true)
7c0ba920 82 expect(pool.emitter).toBeDefined()
e843b904
JB
83 expect(pool.opts.workerChoiceStrategy).toBe(
84 WorkerChoiceStrategies.ROUND_ROBIN
85 )
35cf1c03
JB
86 expect(pool.opts.messageHandler).toBeUndefined()
87 expect(pool.opts.errorHandler).toBeUndefined()
88 expect(pool.opts.onlineHandler).toBeUndefined()
89 expect(pool.opts.exitHandler).toBeUndefined()
7c0ba920 90 pool.destroy()
35cf1c03 91 const testHandler = () => console.log('test handler executed')
7c0ba920
JB
92 pool = new FixedThreadPool(
93 numberOfWorkers,
94 './tests/worker-files/thread/testWorker.js',
95 {
e843b904 96 workerChoiceStrategy: WorkerChoiceStrategies.LESS_RECENTLY_USED,
35cf1c03
JB
97 enableEvents: false,
98 messageHandler: testHandler,
99 errorHandler: testHandler,
100 onlineHandler: testHandler,
101 exitHandler: testHandler
7c0ba920
JB
102 }
103 )
8620fb25 104 expect(pool.opts.enableEvents).toBe(false)
7c0ba920 105 expect(pool.emitter).toBeUndefined()
e843b904
JB
106 expect(pool.opts.workerChoiceStrategy).toBe(
107 WorkerChoiceStrategies.LESS_RECENTLY_USED
108 )
35cf1c03
JB
109 expect(pool.opts.messageHandler).toStrictEqual(testHandler)
110 expect(pool.opts.errorHandler).toStrictEqual(testHandler)
111 expect(pool.opts.onlineHandler).toStrictEqual(testHandler)
112 expect(pool.opts.exitHandler).toStrictEqual(testHandler)
7c0ba920
JB
113 pool.destroy()
114 })
115
bf9549ae
JB
116 it('Simulate worker not found during increaseWorkerRunningTasks', () => {
117 const pool = new StubPoolWithWorkerTasksUsageMapClear(
118 numberOfWorkers,
119 './tests/worker-files/cluster/testWorker.js'
120 )
121 // Simulate worker not found.
122 pool.removeAllWorker()
123 expect(() => pool.increaseWorkerRunningTasks()).toThrowError(
124 workerNotFoundInTasksUsageMapError
125 )
126 pool.destroy()
127 })
128
129 it('Simulate worker not found during decreaseWorkerRunningTasks', () => {
130 const pool = new StubPoolWithWorkerTasksUsageMapClear(
131 numberOfWorkers,
132 './tests/worker-files/cluster/testWorker.js',
133 {
134 errorHandler: e => console.error(e)
135 }
136 )
137 // Simulate worker not found.
138 pool.removeAllWorker()
139 expect(() => pool.decreaseWorkerRunningTasks()).toThrowError(
140 workerNotFoundInTasksUsageMapError
141 )
142 pool.destroy()
143 })
144
145 it('Simulate worker not found during stepWorkerRunTasks', () => {
146 const pool = new StubPoolWithWorkerTasksUsageMapClear(
147 numberOfWorkers,
148 './tests/worker-files/cluster/testWorker.js',
149 {
150 errorHandler: e => console.error(e)
151 }
152 )
153 // Simulate worker not found.
154 pool.removeAllWorker()
155 expect(() => pool.stepWorkerRunTasks()).toThrowError(
156 workerNotFoundInTasksUsageMapError
157 )
158 pool.destroy()
159 })
160
10fcfaf4 161 it('Simulate worker not found during updateWorkerTasksRunTime with strategy not requiring it', () => {
bf9549ae
JB
162 const pool = new StubPoolWithWorkerTasksUsageMapClear(
163 numberOfWorkers,
164 './tests/worker-files/cluster/testWorker.js',
165 {
166 errorHandler: e => console.error(e)
167 }
168 )
169 // Simulate worker not found.
170 pool.removeAllWorker()
10fcfaf4
JB
171 expect(() => pool.updateWorkerTasksRunTime()).not.toThrowError()
172 pool.destroy()
173 })
174
175 it('Simulate worker not found during updateWorkerTasksRunTime with strategy requiring it', () => {
176 const pool = new StubPoolWithWorkerTasksUsageMapClear(
177 numberOfWorkers,
178 './tests/worker-files/cluster/testWorker.js',
179 {
180 workerChoiceStrategy: WorkerChoiceStrategies.FAIR_SHARE,
181 errorHandler: e => console.error(e)
182 }
183 )
184 // Simulate worker not found.
185 pool.removeAllWorker()
bf9549ae
JB
186 expect(() => pool.updateWorkerTasksRunTime()).toThrowError(
187 workerNotFoundInTasksUsageMapError
188 )
189 pool.destroy()
190 })
191
192 it('Verify that worker pool tasks usage are initialized', () => {
193 const pool = new FixedClusterPool(
194 numberOfWorkers,
195 './tests/worker-files/cluster/testWorker.js'
196 )
197 for (const tasksUsage of pool.workersTasksUsage.values()) {
198 expect(tasksUsage).toBeDefined()
199 expect(tasksUsage.run).toBe(0)
200 expect(tasksUsage.running).toBe(0)
201 expect(tasksUsage.runTime).toBe(0)
202 expect(tasksUsage.avgRunTime).toBe(0)
203 }
204 pool.destroy()
205 })
206
207 it('Verify that worker pool tasks usage are computed', async () => {
208 const pool = new FixedClusterPool(
209 numberOfWorkers,
210 './tests/worker-files/cluster/testWorker.js'
211 )
212 const promises = []
213 for (let i = 0; i < numberOfWorkers * 2; i++) {
6db75ad9 214 promises.push(pool.execute())
bf9549ae
JB
215 }
216 for (const tasksUsage of pool.workersTasksUsage.values()) {
217 expect(tasksUsage).toBeDefined()
218 expect(tasksUsage.run).toBe(0)
219 expect(tasksUsage.running).toBe(numberOfWorkers * 2)
220 expect(tasksUsage.runTime).toBe(0)
221 expect(tasksUsage.avgRunTime).toBe(0)
222 }
223 await Promise.all(promises)
224 for (const tasksUsage of pool.workersTasksUsage.values()) {
225 expect(tasksUsage).toBeDefined()
226 expect(tasksUsage.run).toBe(numberOfWorkers * 2)
227 expect(tasksUsage.running).toBe(0)
228 expect(tasksUsage.runTime).toBeGreaterThanOrEqual(0)
229 expect(tasksUsage.avgRunTime).toBeGreaterThanOrEqual(0)
230 }
231 pool.destroy()
232 })
233
cf597bc5 234 it("Verify that pool event emitter 'busy' event can register a callback", async () => {
7c0ba920
JB
235 const pool = new FixedThreadPool(
236 numberOfWorkers,
237 './tests/worker-files/thread/testWorker.js'
238 )
239 const promises = []
240 let poolBusy = 0
241 pool.emitter.on('busy', () => poolBusy++)
242 for (let i = 0; i < numberOfWorkers * 2; i++) {
6db75ad9 243 promises.push(pool.execute())
7c0ba920 244 }
cf597bc5 245 await Promise.all(promises)
14916bf9
JB
246 // The `busy` event is triggered when the number of submitted tasks at once reach the number of fixed pool workers.
247 // So in total numberOfWorkers + 1 times for a loop submitting up to numberOfWorkers * 2 tasks to the fixed pool.
248 expect(poolBusy).toBe(numberOfWorkers + 1)
7c0ba920
JB
249 pool.destroy()
250 })
3ec964d6 251})