1 const { expect
} = require('expect')
2 const sinon
= require('sinon')
3 const { ClusterWorker
, KillBehaviors
, ThreadWorker
} = require('../../lib')
4 const { EMPTY_FUNCTION
} = require('../../lib/utils')
6 describe('Abstract worker test suite', () => {
7 class StubWorkerWithMainWorker
extends ThreadWorker
{
8 constructor (fn
, opts
) {
10 this.mainWorker
= undefined
14 it('Verify worker options default values', () => {
15 const worker
= new ThreadWorker(() => {})
16 expect(worker
.opts
.maxInactiveTime
).toStrictEqual(60000)
17 expect(worker
.opts
.killBehavior
).toBe(KillBehaviors
.SOFT
)
18 expect(worker
.opts
.killHandler
).toStrictEqual(EMPTY_FUNCTION
)
19 expect(worker
.opts
.async
).toBe(undefined)
22 it('Verify that worker options are set at worker creation', () => {
23 const killHandler
= () => {
24 console
.info('Worker received kill message')
26 const worker
= new ClusterWorker(() => {}, {
27 maxInactiveTime
: 6000,
28 killBehavior
: KillBehaviors
.HARD
,
32 expect(worker
.opts
.maxInactiveTime
).toStrictEqual(6000)
33 expect(worker
.opts
.killBehavior
).toBe(KillBehaviors
.HARD
)
34 expect(worker
.opts
.killHandler
).toStrictEqual(killHandler
)
35 expect(worker
.opts
.async
).toBe(undefined)
38 it('Verify that taskFunctions parameter is mandatory', () => {
39 expect(() => new ClusterWorker()).toThrowError(
40 'taskFunctions parameter is mandatory'
44 it('Verify that taskFunctions parameter is a function or a plain object', () => {
45 expect(() => new ClusterWorker(0)).toThrowError(
47 'taskFunctions parameter is not a function or a plain object'
50 expect(() => new ClusterWorker('')).toThrowError(
52 'taskFunctions parameter is not a function or a plain object'
55 expect(() => new ClusterWorker(true)).toThrowError(
57 'taskFunctions parameter is not a function or a plain object'
60 expect(() => new ClusterWorker([])).toThrowError(
62 'taskFunctions parameter is not a function or a plain object'
65 expect(() => new ClusterWorker(new Map())).toThrowError(
67 'taskFunctions parameter is not a function or a plain object'
70 expect(() => new ClusterWorker(new Set())).toThrowError(
72 'taskFunctions parameter is not a function or a plain object'
75 expect(() => new ClusterWorker(new WeakMap())).toThrowError(
77 'taskFunctions parameter is not a function or a plain object'
80 expect(() => new ClusterWorker(new WeakSet())).toThrowError(
82 'taskFunctions parameter is not a function or a plain object'
87 it('Verify that taskFunctions parameter is not an empty object', () => {
88 expect(() => new ClusterWorker({})).toThrowError(
89 new Error('taskFunctions parameter object is empty')
93 it('Verify that taskFunctions parameter with unique function is taken', () => {
94 const worker
= new ThreadWorker(() => {})
95 expect(worker
.taskFunctions
.get('default')).toBeInstanceOf(Function
)
96 expect(worker
.taskFunctions
.get('fn1')).toBeInstanceOf(Function
)
97 expect(worker
.taskFunctions
.size
).toBe(2)
98 expect(worker
.taskFunctions
.get('default')).toStrictEqual(
99 worker
.taskFunctions
.get('fn1')
103 it('Verify that taskFunctions parameter with multiple task functions contains function', () => {
108 expect(() => new ThreadWorker({ fn1
, fn2
})).toThrowError(
109 new TypeError('A taskFunctions parameter object value is not a function')
113 it('Verify that taskFunctions parameter with multiple task functions is taken', () => {
120 const worker
= new ClusterWorker({ fn1
, fn2
})
121 expect(worker
.taskFunctions
.get('default')).toBeInstanceOf(Function
)
122 expect(worker
.taskFunctions
.get('fn1')).toBeInstanceOf(Function
)
123 expect(worker
.taskFunctions
.get('fn2')).toBeInstanceOf(Function
)
124 expect(worker
.taskFunctions
.size
).toBe(3)
125 expect(worker
.taskFunctions
.get('default')).toStrictEqual(
126 worker
.taskFunctions
.get('fn1')
130 it('Verify that sync kill handler is called when worker is killed', () => {
131 const worker
= new ClusterWorker(() => {}, {
132 killHandler
: sinon
.stub().returns()
134 worker
.isMain
= false
135 worker
.getMainWorker
= sinon
.stub().returns({
137 send
: sinon
.stub().returns()
139 worker
.handleKillMessage()
140 expect(worker
.getMainWorker().send
.calledOnce
).toBe(true)
141 expect(worker
.opts
.killHandler
.calledOnce
).toBe(true)
144 it('Verify that async kill handler is called when worker is killed', () => {
145 const killHandlerStub
= sinon
.stub().returns()
146 const worker
= new ClusterWorker(() => {}, {
147 killHandler
: async () => Promise
.resolve(killHandlerStub())
149 worker
.isMain
= false
150 worker
.handleKillMessage()
151 expect(killHandlerStub
.calledOnce
).toBe(true)
154 it('Verify that handleError() method works properly', () => {
155 const error
= new Error('Error as an error')
156 const worker
= new ClusterWorker(() => {})
157 expect(worker
.handleError(error
)).not
.toBeInstanceOf(Error
)
158 expect(worker
.handleError(error
)).toStrictEqual(error
.message
)
159 const errorMessage
= 'Error as a string'
160 expect(worker
.handleError(errorMessage
)).toStrictEqual(errorMessage
)
163 it('Verify that getMainWorker() throw error if main worker is not set', () => {
165 new StubWorkerWithMainWorker(() => {}).getMainWorker()
166 ).toThrowError('Main worker not set')
169 it('Verify that hasTaskFunction() works', () => {
176 const worker
= new ClusterWorker({ fn1
, fn2
})
177 expect(worker
.hasTaskFunction('default')).toBe(true)
178 expect(worker
.hasTaskFunction('fn1')).toBe(true)
179 expect(worker
.hasTaskFunction('fn2')).toBe(true)
180 expect(worker
.hasTaskFunction('fn3')).toBe(false)
183 it('Verify that addTaskFunction() works', () => {
190 const fn1Replacement
= () => {
193 const worker
= new ThreadWorker(fn1
)
194 expect(worker
.taskFunctions
.get('default')).toBeInstanceOf(Function
)
195 expect(worker
.taskFunctions
.get('fn1')).toBeInstanceOf(Function
)
196 expect(worker
.taskFunctions
.size
).toBe(2)
197 expect(worker
.taskFunctions
.get('default')).toStrictEqual(
198 worker
.taskFunctions
.get('fn1')
200 expect(() => worker
.addTaskFunction('default', fn2
)).toThrowError(
201 new Error('Cannot add a task function with the default reserved name')
203 worker
.addTaskFunction('fn2', fn2
)
204 expect(worker
.taskFunctions
.get('default')).toBeInstanceOf(Function
)
205 expect(worker
.taskFunctions
.get('fn1')).toBeInstanceOf(Function
)
206 expect(worker
.taskFunctions
.get('fn2')).toBeInstanceOf(Function
)
207 expect(worker
.taskFunctions
.size
).toBe(3)
208 expect(worker
.taskFunctions
.get('default')).toStrictEqual(
209 worker
.taskFunctions
.get('fn1')
211 worker
.addTaskFunction('fn1', fn1Replacement
)
212 expect(worker
.taskFunctions
.get('default')).toBeInstanceOf(Function
)
213 expect(worker
.taskFunctions
.get('fn1')).toBeInstanceOf(Function
)
214 expect(worker
.taskFunctions
.get('fn2')).toBeInstanceOf(Function
)
215 expect(worker
.taskFunctions
.size
).toBe(3)
216 expect(worker
.taskFunctions
.get('default')).toStrictEqual(
217 worker
.taskFunctions
.get('fn1')
221 it('Verify that removeTaskFunction() works', () => {
228 const worker
= new ClusterWorker({ fn1
, fn2
})
229 worker
.getMainWorker
= sinon
.stub().returns({
231 send
: sinon
.stub().returns()
233 expect(worker
.taskFunctions
.get('default')).toBeInstanceOf(Function
)
234 expect(worker
.taskFunctions
.get('fn1')).toBeInstanceOf(Function
)
235 expect(worker
.taskFunctions
.get('fn2')).toBeInstanceOf(Function
)
236 expect(worker
.taskFunctions
.size
).toBe(3)
237 expect(worker
.taskFunctions
.get('default')).toStrictEqual(
238 worker
.taskFunctions
.get('fn1')
240 expect(() => worker
.removeTaskFunction('default')).toThrowError(
242 'Cannot remove the task function with the default reserved name'
245 expect(() => worker
.removeTaskFunction('fn1')).toThrowError(
247 'Cannot remove the task function used as the default task function'
250 worker
.removeTaskFunction('fn2')
251 expect(worker
.taskFunctions
.get('default')).toBeInstanceOf(Function
)
252 expect(worker
.taskFunctions
.get('fn1')).toBeInstanceOf(Function
)
253 expect(worker
.taskFunctions
.get('fn2')).toBeUndefined()
254 expect(worker
.taskFunctions
.size
).toBe(2)
255 expect(worker
.getMainWorker().send
.calledOnce
).toBe(true)
258 it('Verify that listTaskFunctions() works', () => {
265 const worker
= new ClusterWorker({ fn1
, fn2
})
266 expect(worker
.listTaskFunctions()).toStrictEqual(['default', 'fn1', 'fn2'])
269 it('Verify that setDefaultTaskFunction() works', () => {
276 const worker
= new ThreadWorker({ fn1
, fn2
})
277 expect(worker
.taskFunctions
.get('default')).toBeInstanceOf(Function
)
278 expect(worker
.taskFunctions
.get('fn1')).toBeInstanceOf(Function
)
279 expect(worker
.taskFunctions
.get('fn2')).toBeInstanceOf(Function
)
280 expect(worker
.taskFunctions
.size
).toBe(3)
281 expect(worker
.taskFunctions
.get('default')).toStrictEqual(
282 worker
.taskFunctions
.get('fn1')
284 expect(() => worker
.setDefaultTaskFunction('default')).toThrowError(
286 'Cannot set the default task function reserved name as the default task function'
289 worker
.setDefaultTaskFunction('fn1')
290 expect(worker
.taskFunctions
.get('default')).toStrictEqual(
291 worker
.taskFunctions
.get('fn1')
293 worker
.setDefaultTaskFunction('fn2')
294 expect(worker
.taskFunctions
.get('default')).toStrictEqual(
295 worker
.taskFunctions
.get('fn2')