test: cleanup helpers
[poolifier.git] / tests / pools / cluster / fixed.test.js
CommitLineData
a61a0724 1const { expect } = require('expect')
cdace0e5 2const { FixedClusterPool, PoolEvents } = require('../../../lib')
2d2e32c2 3const { WorkerFunctions } = require('../../test-types')
85a3f8a7 4const TestUtils = require('../../test-utils')
325f50bc 5
a35560ba 6describe('Fixed cluster pool test suite', () => {
e1ffb94f
JB
7 const numberOfWorkers = 6
8 const pool = new FixedClusterPool(
9 numberOfWorkers,
10 './tests/worker-files/cluster/testWorker.js',
11 {
12 errorHandler: e => console.error(e)
13 }
14 )
594bfb84
JB
15 const queuePool = new FixedClusterPool(
16 numberOfWorkers,
17 './tests/worker-files/cluster/testWorker.js',
18 {
19 enableTasksQueue: true,
20 tasksQueueOptions: {
21 concurrency: 2
22 },
23 errorHandler: e => console.error(e)
24 }
25 )
e1ffb94f
JB
26 const emptyPool = new FixedClusterPool(
27 numberOfWorkers,
28 './tests/worker-files/cluster/emptyWorker.js',
29 { exitHandler: () => console.log('empty pool worker exited') }
30 )
31 const echoPool = new FixedClusterPool(
32 numberOfWorkers,
33 './tests/worker-files/cluster/echoWorker.js'
34 )
35 const errorPool = new FixedClusterPool(
36 numberOfWorkers,
37 './tests/worker-files/cluster/errorWorker.js',
38 {
39 errorHandler: e => console.error(e)
40 }
41 )
42 const asyncErrorPool = new FixedClusterPool(
43 numberOfWorkers,
44 './tests/worker-files/cluster/asyncErrorWorker.js',
45 {
46 errorHandler: e => console.error(e)
47 }
48 )
49 const asyncPool = new FixedClusterPool(
50 numberOfWorkers,
51 './tests/worker-files/cluster/asyncWorker.js'
52 )
53
8bc77620
APA
54 after('Destroy all pools', async () => {
55 // We need to clean up the resources after our test
56 await echoPool.destroy()
57 await asyncPool.destroy()
58 await errorPool.destroy()
59 await asyncErrorPool.destroy()
60 await emptyPool.destroy()
594bfb84 61 await queuePool.destroy()
8bc77620
APA
62 })
63
325f50bc 64 it('Verify that the function is executed in a worker cluster', async () => {
6db75ad9
JB
65 let result = await pool.execute({
66 function: WorkerFunctions.fibonacci
67 })
70a4f5ea 68 expect(result).toBe(121393)
6db75ad9
JB
69 result = await pool.execute({
70 function: WorkerFunctions.factorial
71 })
70a4f5ea 72 expect(result).toBe(9.33262154439441e157)
325f50bc
S
73 })
74
318d4156 75 it('Verify that is possible to invoke the execute() method without input', async () => {
325f50bc 76 const result = await pool.execute()
6db75ad9 77 expect(result).toBe(false)
325f50bc
S
78 })
79
aee46736 80 it("Verify that 'busy' event is emitted", async () => {
7c0ba920 81 let poolBusy = 0
aee46736 82 pool.emitter.on(PoolEvents.busy, () => ++poolBusy)
7c0ba920 83 for (let i = 0; i < numberOfWorkers * 2; i++) {
8cbb82eb 84 pool.execute()
7c0ba920 85 }
14916bf9
JB
86 // The `busy` event is triggered when the number of submitted tasks at once reach the number of fixed pool workers.
87 // So in total numberOfWorkers + 1 times for a loop submitting up to numberOfWorkers * 2 tasks to the fixed pool.
88 expect(poolBusy).toBe(numberOfWorkers + 1)
7c0ba920
JB
89 })
90
594bfb84 91 it('Verify that tasks queuing is working', async () => {
d3d4b67d 92 const promises = new Set()
ee9f5295 93 const maxMultiplier = 2
594bfb84 94 for (let i = 0; i < numberOfWorkers * maxMultiplier; i++) {
d3d4b67d 95 promises.add(queuePool.execute())
594bfb84 96 }
d3d4b67d 97 expect(promises.size).toBe(numberOfWorkers * maxMultiplier)
594bfb84 98 for (const workerNode of queuePool.workerNodes) {
a4e07f72 99 expect(workerNode.workerUsage.tasks.executing).toBeLessThanOrEqual(
594bfb84
JB
100 queuePool.opts.tasksQueueOptions.concurrency
101 )
a4e07f72 102 expect(workerNode.workerUsage.tasks.executed).toBe(0)
4d8bf9e4 103 expect(workerNode.tasksQueue.size).toBeGreaterThan(0)
594bfb84 104 }
a4e07f72 105 expect(queuePool.info.executingTasks).toBe(numberOfWorkers)
6b27d407
JB
106 expect(queuePool.info.queuedTasks).toBe(
107 numberOfWorkers * maxMultiplier - numberOfWorkers
108 )
109 expect(queuePool.info.maxQueuedTasks).toBe(
d3d4b67d
JB
110 numberOfWorkers * maxMultiplier - numberOfWorkers
111 )
594bfb84
JB
112 await Promise.all(promises)
113 for (const workerNode of queuePool.workerNodes) {
a4e07f72
JB
114 expect(workerNode.workerUsage.tasks.executing).toBe(0)
115 expect(workerNode.workerUsage.tasks.executed).toBeGreaterThan(0)
116 expect(workerNode.workerUsage.tasks.executed).toBeLessThanOrEqual(
117 maxMultiplier
118 )
4d8bf9e4 119 expect(workerNode.tasksQueue.size).toBe(0)
594bfb84
JB
120 }
121 })
122
325f50bc
S
123 it('Verify that is possible to have a worker that return undefined', async () => {
124 const result = await emptyPool.execute()
6db75ad9 125 expect(result).toBeUndefined()
325f50bc
S
126 })
127
128 it('Verify that data are sent to the worker correctly', async () => {
129 const data = { f: 10 }
130 const result = await echoPool.execute(data)
e1ffb94f 131 expect(result).toStrictEqual(data)
325f50bc
S
132 })
133
134 it('Verify that error handling is working properly:sync', async () => {
135 const data = { f: 10 }
d46660cd
JB
136 let taskError
137 errorPool.emitter.on(PoolEvents.taskError, e => {
138 taskError = e
139 })
325f50bc
S
140 let inError
141 try {
142 await errorPool.execute(data)
143 } catch (e) {
144 inError = e
145 }
146 expect(inError).toBeDefined()
8620fb25 147 expect(typeof inError === 'string').toBe(true)
325f50bc 148 expect(inError).toBe('Error Message from ClusterWorker')
d46660cd 149 expect(taskError).toStrictEqual({
82f36766
JB
150 message: 'Error Message from ClusterWorker',
151 data
d46660cd 152 })
18482cec
JB
153 expect(
154 errorPool.workerNodes.some(
a4e07f72 155 workerNode => workerNode.workerUsage.tasks.failed === 1
18482cec
JB
156 )
157 ).toBe(true)
325f50bc
S
158 })
159
160 it('Verify that error handling is working properly:async', async () => {
161 const data = { f: 10 }
4f0b85b3
JB
162 let taskError
163 asyncErrorPool.emitter.on(PoolEvents.taskError, e => {
164 taskError = e
165 })
325f50bc
S
166 let inError
167 try {
168 await asyncErrorPool.execute(data)
169 } catch (e) {
170 inError = e
171 }
172 expect(inError).toBeDefined()
8620fb25 173 expect(typeof inError === 'string').toBe(true)
325f50bc 174 expect(inError).toBe('Error Message from ClusterWorker:async')
4f0b85b3 175 expect(taskError).toStrictEqual({
82f36766
JB
176 message: 'Error Message from ClusterWorker:async',
177 data
4f0b85b3 178 })
18482cec
JB
179 expect(
180 asyncErrorPool.workerNodes.some(
a4e07f72 181 workerNode => workerNode.workerUsage.tasks.failed === 1
18482cec
JB
182 )
183 ).toBe(true)
325f50bc
S
184 })
185
186 it('Verify that async function is working properly', async () => {
187 const data = { f: 10 }
15e5141f 188 const startTime = performance.now()
325f50bc 189 const result = await asyncPool.execute(data)
15e5141f 190 const usedTime = performance.now() - startTime
e1ffb94f 191 expect(result).toStrictEqual(data)
325f50bc
S
192 expect(usedTime).toBeGreaterThanOrEqual(2000)
193 })
194
195 it('Shutdown test', async () => {
2c039e43
JB
196 const exitPromise = TestUtils.waitWorkerEvents(
197 pool,
198 'exit',
199 numberOfWorkers
200 )
45dbbb14 201 await pool.destroy()
bdacc2d2
JB
202 const numberOfExitEvents = await exitPromise
203 expect(numberOfExitEvents).toBe(numberOfWorkers)
325f50bc
S
204 })
205
1a76932b
JB
206 it('Verify that cluster pool options are checked', async () => {
207 const workerFilePath = './tests/worker-files/cluster/testWorker.js'
208 let pool1 = new FixedClusterPool(numberOfWorkers, workerFilePath)
209 expect(pool1.opts.env).toBeUndefined()
210 expect(pool1.opts.settings).toBeUndefined()
211 await pool1.destroy()
212 pool1 = new FixedClusterPool(numberOfWorkers, workerFilePath, {
213 env: { TEST: 'test' },
214 settings: { args: ['--use', 'http'], silent: true }
215 })
216 expect(pool1.opts.env).toStrictEqual({ TEST: 'test' })
217 expect(pool1.opts.settings).toStrictEqual({
218 args: ['--use', 'http'],
219 silent: true
220 })
221 expect({ ...pool1.opts.settings, exec: workerFilePath }).toStrictEqual({
222 args: ['--use', 'http'],
223 silent: true,
224 exec: workerFilePath
225 })
226 await pool1.destroy()
227 })
228
325f50bc
S
229 it('Should work even without opts in input', async () => {
230 const pool1 = new FixedClusterPool(
e1ffb94f 231 numberOfWorkers,
76b1e974 232 './tests/worker-files/cluster/testWorker.js'
325f50bc 233 )
6db75ad9
JB
234 const res = await pool1.execute()
235 expect(res).toBe(false)
8bc77620
APA
236 // We need to clean up the resources after our test
237 await pool1.destroy()
325f50bc 238 })
8d3782fa
JB
239
240 it('Verify that a pool with zero worker fails', async () => {
241 expect(
242 () =>
243 new FixedClusterPool(0, './tests/worker-files/cluster/testWorker.js')
d4aeae5a 244 ).toThrowError('Cannot instantiate a fixed pool with no worker')
8d3782fa 245 })
325f50bc 246})