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