docs: spell fix in README.md
[poolifier.git] / tests / pools / thread / fixed.test.js
CommitLineData
a61a0724 1const { expect } = require('expect')
cdace0e5 2const { FixedThreadPool, PoolEvents } = require('../../../lib')
2d2e32c2 3const { WorkerFunctions } = require('../../test-types')
85a3f8a7 4const TestUtils = require('../../test-utils')
506c2a14 5
a35560ba 6describe('Fixed thread pool test suite', () => {
e1ffb94f
JB
7 const numberOfThreads = 6
8 const pool = new FixedThreadPool(
9 numberOfThreads,
10 './tests/worker-files/thread/testWorker.js',
11 {
12 errorHandler: e => console.error(e)
13 }
14 )
594bfb84
JB
15 const queuePool = new FixedThreadPool(
16 numberOfThreads,
17 './tests/worker-files/thread/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 FixedThreadPool(
27 numberOfThreads,
28 './tests/worker-files/thread/emptyWorker.js',
29 { exitHandler: () => console.log('empty pool worker exited') }
30 )
31 const echoPool = new FixedThreadPool(
32 numberOfThreads,
33 './tests/worker-files/thread/echoWorker.js'
34 )
35 const errorPool = new FixedThreadPool(
36 numberOfThreads,
37 './tests/worker-files/thread/errorWorker.js',
38 {
39 errorHandler: e => console.error(e)
40 }
41 )
42 const asyncErrorPool = new FixedThreadPool(
43 numberOfThreads,
44 './tests/worker-files/thread/asyncErrorWorker.js',
45 {
46 errorHandler: e => console.error(e)
47 }
48 )
49 const asyncPool = new FixedThreadPool(
50 numberOfThreads,
51 './tests/worker-files/thread/asyncWorker.js'
52 )
53
0e2503fc
JB
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()
7c0ba920 59 await asyncErrorPool.destroy()
0e2503fc 60 await emptyPool.destroy()
594bfb84 61 await queuePool.destroy()
0e2503fc
JB
62 })
63
506c2a14 64 it('Verify that the function is executed in a worker thread', 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)
506c2a14 73 })
74
318d4156 75 it('Verify that is possible to invoke the execute() method without input', async () => {
106744f7 76 const result = await pool.execute()
6db75ad9 77 expect(result).toBe(false)
106744f7 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 < numberOfThreads * 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 numberOfThreads + 1 times for a loop submitting up to numberOfThreads * 2 tasks to the fixed pool.
88 expect(poolBusy).toBe(numberOfThreads + 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 < numberOfThreads * maxMultiplier; i++) {
d3d4b67d 95 promises.add(queuePool.execute())
594bfb84 96 }
d3d4b67d 97 expect(promises.size).toBe(numberOfThreads * maxMultiplier)
594bfb84
JB
98 for (const workerNode of queuePool.workerNodes) {
99 expect(workerNode.tasksUsage.running).toBeLessThanOrEqual(
100 queuePool.opts.tasksQueueOptions.concurrency
101 )
1ab50fe5 102 expect(workerNode.tasksUsage.ran).toBe(0)
4d8bf9e4 103 expect(workerNode.tasksQueue.size).toBeGreaterThan(0)
594bfb84 104 }
6b27d407
JB
105 expect(queuePool.info.runningTasks).toBe(numberOfThreads)
106 expect(queuePool.info.queuedTasks).toBe(
107 numberOfThreads * maxMultiplier - numberOfThreads
108 )
109 expect(queuePool.info.maxQueuedTasks).toBe(
d3d4b67d
JB
110 numberOfThreads * maxMultiplier - numberOfThreads
111 )
594bfb84
JB
112 await Promise.all(promises)
113 for (const workerNode of queuePool.workerNodes) {
114 expect(workerNode.tasksUsage.running).toBe(0)
1ab50fe5
JB
115 expect(workerNode.tasksUsage.ran).toBeGreaterThan(0)
116 expect(workerNode.tasksUsage.ran).toBeLessThanOrEqual(maxMultiplier)
4d8bf9e4 117 expect(workerNode.tasksQueue.size).toBe(0)
594bfb84
JB
118 }
119 })
120
106744f7 121 it('Verify that is possible to have a worker that return undefined', async () => {
122 const result = await emptyPool.execute()
6db75ad9 123 expect(result).toBeUndefined()
106744f7 124 })
125
126 it('Verify that data are sent to the worker correctly', async () => {
127 const data = { f: 10 }
128 const result = await echoPool.execute(data)
e1ffb94f 129 expect(result).toStrictEqual(data)
106744f7 130 })
131
7c0ba920 132 it('Verify that error handling is working properly:sync', async () => {
106744f7 133 const data = { f: 10 }
134 let inError
135 try {
136 await errorPool.execute(data)
137 } catch (e) {
138 inError = e
139 }
7c0ba920
JB
140 expect(inError).toBeDefined()
141 expect(inError).toBeInstanceOf(Error)
142 expect(inError.message).toBeDefined()
8620fb25 143 expect(typeof inError.message === 'string').toBe(true)
0302f8ec 144 expect(inError.message).toBe('Error Message from ThreadWorker')
18482cec
JB
145 expect(
146 errorPool.workerNodes.some(
147 workerNode => workerNode.tasksUsage.error === 1
148 )
149 ).toBe(true)
7c0ba920
JB
150 })
151
152 it('Verify that error handling is working properly:async', async () => {
153 const data = { f: 10 }
154 let inError
155 try {
156 await asyncErrorPool.execute(data)
157 } catch (e) {
158 inError = e
159 }
160 expect(inError).toBeDefined()
161 expect(inError).toBeInstanceOf(Error)
162 expect(inError.message).toBeDefined()
8620fb25 163 expect(typeof inError.message === 'string').toBe(true)
0302f8ec 164 expect(inError.message).toBe('Error Message from ThreadWorker:async')
18482cec
JB
165 expect(
166 asyncErrorPool.workerNodes.some(
167 workerNode => workerNode.tasksUsage.error === 1
168 )
169 ).toBe(true)
106744f7 170 })
171
7784f548 172 it('Verify that async function is working properly', async () => {
173 const data = { f: 10 }
15e5141f 174 const startTime = performance.now()
7784f548 175 const result = await asyncPool.execute(data)
15e5141f 176 const usedTime = performance.now() - startTime
e1ffb94f 177 expect(result).toStrictEqual(data)
32d490eb 178 expect(usedTime).toBeGreaterThanOrEqual(2000)
7784f548 179 })
180
506c2a14 181 it('Shutdown test', async () => {
85a3f8a7 182 const exitPromise = TestUtils.waitExits(pool, numberOfThreads)
1f9a5a44 183 await pool.destroy()
bdacc2d2
JB
184 const numberOfExitEvents = await exitPromise
185 expect(numberOfExitEvents).toBe(numberOfThreads)
506c2a14 186 })
187
188 it('Should work even without opts in input', async () => {
76b1e974 189 const pool1 = new FixedThreadPool(
e1ffb94f 190 numberOfThreads,
76b1e974
S
191 './tests/worker-files/thread/testWorker.js'
192 )
6db75ad9
JB
193 const res = await pool1.execute()
194 expect(res).toBe(false)
0e2503fc
JB
195 // We need to clean up the resources after our test
196 await pool1.destroy()
506c2a14 197 })
8d3782fa
JB
198
199 it('Verify that a pool with zero worker fails', async () => {
200 expect(
201 () => new FixedThreadPool(0, './tests/worker-files/thread/testWorker.js')
d4aeae5a 202 ).toThrowError('Cannot instantiate a fixed pool with no worker')
8d3782fa 203 })
506c2a14 204})