1 const { expect
} = require('expect')
6 } = require('../../../lib/index')
8 describe('Abstract pool test suite', () => {
9 const numberOfWorkers
= 1
10 const workerNotFoundInTasksUsageMapError
= new Error(
11 'Worker could not be found in worker tasks usage map'
13 class StubPoolWithWorkerTasksUsageMapClear
extends FixedThreadPool
{
15 this.workersTasksUsage
.clear()
18 class StubPoolWithIsMainMethod
extends FixedThreadPool
{
24 it('Simulate pool creation from a non main thread/process', () => {
27 new StubPoolWithIsMainMethod(
29 './tests/worker-files/thread/testWorker.js',
31 errorHandler
: e
=> console
.error(e
)
34 ).toThrowError(new Error('Cannot start a pool from a worker!'))
37 it('Verify that filePath is checked', () => {
38 const expectedError
= new Error(
39 'Please specify a file with a worker implementation'
41 expect(() => new FixedThreadPool(numberOfWorkers
)).toThrowError(
44 expect(() => new FixedThreadPool(numberOfWorkers
, '')).toThrowError(
49 it('Verify that numberOfWorkers is checked', () => {
50 expect(() => new FixedThreadPool()).toThrowError(
52 'Cannot instantiate a pool without specifying the number of workers'
57 it('Verify that a negative number of workers is checked', () => {
60 new FixedClusterPool(-1, './tests/worker-files/cluster/testWorker.js')
62 new Error('Cannot instantiate a pool with a negative number of workers')
66 it('Verify that a non integer number of workers is checked', () => {
69 new FixedThreadPool(0.25, './tests/worker-files/thread/testWorker.js')
72 'Cannot instantiate a pool with a non integer number of workers'
77 it('Verify that pool options are checked', async () => {
78 let pool
= new FixedThreadPool(
80 './tests/worker-files/thread/testWorker.js'
82 expect(pool
.opts
.enableEvents
).toBe(true)
83 expect(pool
.emitter
).toBeDefined()
84 expect(pool
.opts
.workerChoiceStrategy
).toBe(
85 WorkerChoiceStrategies
.ROUND_ROBIN
87 expect(pool
.opts
.messageHandler
).toBeUndefined()
88 expect(pool
.opts
.errorHandler
).toBeUndefined()
89 expect(pool
.opts
.onlineHandler
).toBeUndefined()
90 expect(pool
.opts
.exitHandler
).toBeUndefined()
92 const testHandler
= () => console
.log('test handler executed')
93 pool
= new FixedThreadPool(
95 './tests/worker-files/thread/testWorker.js',
97 workerChoiceStrategy
: WorkerChoiceStrategies
.LESS_RECENTLY_USED
,
99 messageHandler
: testHandler
,
100 errorHandler
: testHandler
,
101 onlineHandler
: testHandler
,
102 exitHandler
: testHandler
105 expect(pool
.opts
.enableEvents
).toBe(false)
106 expect(pool
.emitter
).toBeUndefined()
107 expect(pool
.opts
.workerChoiceStrategy
).toBe(
108 WorkerChoiceStrategies
.LESS_RECENTLY_USED
110 expect(pool
.opts
.messageHandler
).toStrictEqual(testHandler
)
111 expect(pool
.opts
.errorHandler
).toStrictEqual(testHandler
)
112 expect(pool
.opts
.onlineHandler
).toStrictEqual(testHandler
)
113 expect(pool
.opts
.exitHandler
).toStrictEqual(testHandler
)
117 it('Simulate worker not found during increaseWorkerRunningTasks', async () => {
118 const pool
= new StubPoolWithWorkerTasksUsageMapClear(
120 './tests/worker-files/cluster/testWorker.js'
122 // Simulate worker not found.
123 pool
.removeAllWorker()
124 expect(() => pool
.increaseWorkerRunningTasks()).toThrowError(
125 workerNotFoundInTasksUsageMapError
130 it('Simulate worker not found during decreaseWorkerRunningTasks', async () => {
131 const pool
= new StubPoolWithWorkerTasksUsageMapClear(
133 './tests/worker-files/cluster/testWorker.js',
135 errorHandler
: e
=> console
.error(e
)
138 // Simulate worker not found.
139 pool
.removeAllWorker()
140 expect(() => pool
.decreaseWorkerRunningTasks()).toThrowError(
141 workerNotFoundInTasksUsageMapError
146 it('Simulate worker not found during stepWorkerRunTasks', async () => {
147 const pool
= new StubPoolWithWorkerTasksUsageMapClear(
149 './tests/worker-files/cluster/testWorker.js',
151 errorHandler
: e
=> console
.error(e
)
154 // Simulate worker not found.
155 pool
.removeAllWorker()
156 expect(() => pool
.stepWorkerRunTasks()).toThrowError(
157 workerNotFoundInTasksUsageMapError
162 it('Simulate worker not found during updateWorkerTasksRunTime with strategy not requiring it', async () => {
163 const pool
= new StubPoolWithWorkerTasksUsageMapClear(
165 './tests/worker-files/cluster/testWorker.js',
167 errorHandler
: e
=> console
.error(e
)
170 // Simulate worker not found.
171 pool
.removeAllWorker()
172 expect(() => pool
.updateWorkerTasksRunTime()).not
.toThrowError()
176 it('Simulate worker not found during updateWorkerTasksRunTime with strategy requiring it', async () => {
177 const pool
= new StubPoolWithWorkerTasksUsageMapClear(
179 './tests/worker-files/cluster/testWorker.js',
181 workerChoiceStrategy
: WorkerChoiceStrategies
.FAIR_SHARE
,
182 errorHandler
: e
=> console
.error(e
)
185 // Simulate worker not found.
186 pool
.removeAllWorker()
187 expect(() => pool
.updateWorkerTasksRunTime()).toThrowError(
188 workerNotFoundInTasksUsageMapError
193 it('Verify that worker pool tasks usage are initialized', async () => {
194 const pool
= new FixedClusterPool(
196 './tests/worker-files/cluster/testWorker.js'
198 for (const tasksUsage
of pool
.workersTasksUsage
.values()) {
199 expect(tasksUsage
).toBeDefined()
200 expect(tasksUsage
.run
).toBe(0)
201 expect(tasksUsage
.running
).toBe(0)
202 expect(tasksUsage
.runTime
).toBe(0)
203 expect(tasksUsage
.avgRunTime
).toBe(0)
208 it('Verify that worker pool tasks usage are computed', async () => {
209 const pool
= new FixedClusterPool(
211 './tests/worker-files/cluster/testWorker.js'
214 for (let i
= 0; i
< numberOfWorkers
* 2; i
++) {
215 promises
.push(pool
.execute())
217 for (const tasksUsage
of pool
.workersTasksUsage
.values()) {
218 expect(tasksUsage
).toBeDefined()
219 expect(tasksUsage
.run
).toBe(0)
220 expect(tasksUsage
.running
).toBe(numberOfWorkers
* 2)
221 expect(tasksUsage
.runTime
).toBe(0)
222 expect(tasksUsage
.avgRunTime
).toBe(0)
224 await Promise
.all(promises
)
225 for (const tasksUsage
of pool
.workersTasksUsage
.values()) {
226 expect(tasksUsage
).toBeDefined()
227 expect(tasksUsage
.run
).toBe(numberOfWorkers
* 2)
228 expect(tasksUsage
.running
).toBe(0)
229 expect(tasksUsage
.runTime
).toBeGreaterThanOrEqual(0)
230 expect(tasksUsage
.avgRunTime
).toBeGreaterThanOrEqual(0)
235 it('Verify that worker pool tasks usage are reset at worker choice strategy change', async () => {
236 const pool
= new FixedThreadPool(
238 './tests/worker-files/thread/testWorker.js'
241 for (let i
= 0; i
< numberOfWorkers
* 2; i
++) {
242 promises
.push(pool
.execute())
244 await Promise
.all(promises
)
245 for (const tasksUsage
of pool
.workersTasksUsage
.values()) {
246 expect(tasksUsage
).toBeDefined()
247 expect(tasksUsage
.run
).toBe(numberOfWorkers
* 2)
248 expect(tasksUsage
.running
).toBe(0)
249 expect(tasksUsage
.runTime
).toBeGreaterThanOrEqual(0)
250 expect(tasksUsage
.avgRunTime
).toBeGreaterThanOrEqual(0)
252 pool
.setWorkerChoiceStrategy(WorkerChoiceStrategies
.FAIR_SHARE
)
253 for (const tasksUsage
of pool
.workersTasksUsage
.values()) {
254 expect(tasksUsage
).toBeDefined()
255 expect(tasksUsage
.run
).toBe(0)
256 expect(tasksUsage
.running
).toBe(0)
257 expect(tasksUsage
.runTime
).toBe(0)
258 expect(tasksUsage
.avgRunTime
).toBe(0)
263 it("Verify that pool event emitter 'busy' event can register a callback", async () => {
264 const pool
= new FixedThreadPool(
266 './tests/worker-files/thread/testWorker.js'
270 pool
.emitter
.on('busy', () => poolBusy
++)
271 for (let i
= 0; i
< numberOfWorkers
* 2; i
++) {
272 promises
.push(pool
.execute())
274 await Promise
.all(promises
)
275 // The `busy` event is triggered when the number of submitted tasks at once reach the number of fixed pool workers.
276 // So in total numberOfWorkers + 1 times for a loop submitting up to numberOfWorkers * 2 tasks to the fixed pool.
277 expect(poolBusy
).toBe(numberOfWorkers
+ 1)