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
18 it('Verify worker options default values', () => {
19 const worker
= new ThreadWorker(() => {})
20 expect(worker
.opts
.maxInactiveTime
).toStrictEqual(60000)
21 expect(worker
.opts
.killBehavior
).toBe(KillBehaviors
.SOFT
)
22 expect(worker
.opts
.killHandler
).toStrictEqual(EMPTY_FUNCTION
)
23 expect(worker
.opts
.async
).toBe(undefined)
26 it('Verify that worker options are set at worker creation', () => {
27 const killHandler
= () => {
28 console
.info('Worker received kill message')
30 const worker
= new ClusterWorker(() => {}, {
31 maxInactiveTime
: 6000,
32 killBehavior
: KillBehaviors
.HARD
,
36 expect(worker
.opts
.maxInactiveTime
).toStrictEqual(6000)
37 expect(worker
.opts
.killBehavior
).toBe(KillBehaviors
.HARD
)
38 expect(worker
.opts
.killHandler
).toStrictEqual(killHandler
)
39 expect(worker
.opts
.async
).toBe(undefined)
42 it('Verify that taskFunctions parameter is mandatory', () => {
43 expect(() => new ClusterWorker()).toThrowError(
44 'taskFunctions parameter is mandatory'
48 it('Verify that taskFunctions parameter is a function or a plain object', () => {
49 expect(() => new ClusterWorker(0)).toThrowError(
51 'taskFunctions parameter is not a function or a plain object'
54 expect(() => new ClusterWorker('')).toThrowError(
56 'taskFunctions parameter is not a function or a plain object'
59 expect(() => new ClusterWorker(true)).toThrowError(
61 'taskFunctions parameter is not a function or a plain object'
64 expect(() => new ClusterWorker([])).toThrowError(
66 'taskFunctions parameter is not a function or a plain object'
69 expect(() => new ClusterWorker(new Map())).toThrowError(
71 'taskFunctions parameter is not a function or a plain object'
74 expect(() => new ClusterWorker(new Set())).toThrowError(
76 'taskFunctions parameter is not a function or a plain object'
79 expect(() => new ClusterWorker(new WeakMap())).toThrowError(
81 'taskFunctions parameter is not a function or a plain object'
84 expect(() => new ClusterWorker(new WeakSet())).toThrowError(
86 'taskFunctions parameter is not a function or a plain object'
91 it('Verify that taskFunctions parameter is not an empty object', () => {
92 expect(() => new ClusterWorker({})).toThrowError(
93 new Error('taskFunctions parameter object is empty')
97 it('Verify that taskFunctions parameter with unique function is taken', () => {
98 const worker
= new ThreadWorker(() => {})
99 expect(worker
.taskFunctions
.get('default')).toBeInstanceOf(Function
)
100 expect(worker
.taskFunctions
.get('fn1')).toBeInstanceOf(Function
)
101 expect(worker
.taskFunctions
.size
).toBe(2)
102 expect(worker
.taskFunctions
.get('default')).toStrictEqual(
103 worker
.taskFunctions
.get('fn1')
107 it('Verify that taskFunctions parameter with multiple task functions contains function', () => {
112 expect(() => new ThreadWorker({ fn1
, fn2
})).toThrowError(
113 new TypeError('A taskFunctions parameter object value is not a function')
117 it('Verify that taskFunctions parameter with multiple task functions is taken', () => {
124 const worker
= new ClusterWorker({ fn1
, fn2
})
125 expect(worker
.taskFunctions
.get('default')).toBeInstanceOf(Function
)
126 expect(worker
.taskFunctions
.get('fn1')).toBeInstanceOf(Function
)
127 expect(worker
.taskFunctions
.get('fn2')).toBeInstanceOf(Function
)
128 expect(worker
.taskFunctions
.size
).toBe(3)
129 expect(worker
.taskFunctions
.get('default')).toStrictEqual(
130 worker
.taskFunctions
.get('fn1')
134 it('Verify that sync kill handler is called when worker is killed', () => {
135 const worker
= new ClusterWorker(() => {}, {
136 killHandler
: sinon
.stub().returns()
138 worker
.isMain
= false
139 worker
.getMainWorker
= sinon
.stub().returns({
141 send
: sinon
.stub().returns()
143 worker
.handleKillMessage()
144 expect(worker
.getMainWorker().send
.calledOnce
).toBe(true)
145 expect(worker
.opts
.killHandler
.calledOnce
).toBe(true)
148 it('Verify that async kill handler is called when worker is killed', () => {
149 const killHandlerStub
= sinon
.stub().returns()
150 const worker
= new ClusterWorker(() => {}, {
151 killHandler
: async () => Promise
.resolve(killHandlerStub())
153 worker
.isMain
= false
154 worker
.handleKillMessage()
155 expect(killHandlerStub
.calledOnce
).toBe(true)
158 it('Verify that handleError() method works properly', () => {
159 const error
= new Error('Error as an error')
160 const worker
= new ClusterWorker(() => {})
161 expect(worker
.handleError(error
)).not
.toBeInstanceOf(Error
)
162 expect(worker
.handleError(error
)).toStrictEqual(error
.message
)
163 const errorMessage
= 'Error as a string'
164 expect(worker
.handleError(errorMessage
)).toStrictEqual(errorMessage
)
167 it('Verify that getMainWorker() throw error if main worker is not set', () => {
169 new StubWorkerWithMainWorker(() => {}).getMainWorker()
170 ).toThrowError('Main worker not set')
173 it('Verify that hasTaskFunction() works', () => {
180 const worker
= new ClusterWorker({ fn1
, fn2
})
181 expect(worker
.hasTaskFunction('default')).toBe(true)
182 expect(worker
.hasTaskFunction('fn1')).toBe(true)
183 expect(worker
.hasTaskFunction('fn2')).toBe(true)
184 expect(worker
.hasTaskFunction('fn3')).toBe(false)
187 it('Verify that addTaskFunction() works', () => {
194 const fn1Replacement
= () => {
197 const worker
= new ThreadWorker(fn1
)
198 expect(worker
.taskFunctions
.get('default')).toBeInstanceOf(Function
)
199 expect(worker
.taskFunctions
.get('fn1')).toBeInstanceOf(Function
)
200 expect(worker
.taskFunctions
.size
).toBe(2)
201 expect(worker
.taskFunctions
.get('default')).toStrictEqual(
202 worker
.taskFunctions
.get('fn1')
204 expect(() => worker
.addTaskFunction('default', fn2
)).toThrowError(
205 new Error('Cannot add a task function with the default reserved name')
207 worker
.addTaskFunction('fn2', fn2
)
208 expect(worker
.taskFunctions
.get('default')).toBeInstanceOf(Function
)
209 expect(worker
.taskFunctions
.get('fn1')).toBeInstanceOf(Function
)
210 expect(worker
.taskFunctions
.get('fn2')).toBeInstanceOf(Function
)
211 expect(worker
.taskFunctions
.size
).toBe(3)
212 expect(worker
.taskFunctions
.get('default')).toStrictEqual(
213 worker
.taskFunctions
.get('fn1')
215 worker
.addTaskFunction('fn1', fn1Replacement
)
216 expect(worker
.taskFunctions
.get('default')).toBeInstanceOf(Function
)
217 expect(worker
.taskFunctions
.get('fn1')).toBeInstanceOf(Function
)
218 expect(worker
.taskFunctions
.get('fn2')).toBeInstanceOf(Function
)
219 expect(worker
.taskFunctions
.size
).toBe(3)
220 expect(worker
.taskFunctions
.get('default')).toStrictEqual(
221 worker
.taskFunctions
.get('fn1')
225 it('Verify that removeTaskFunction() works', () => {
232 const worker
= new ClusterWorker({ fn1
, fn2
})
233 worker
.getMainWorker
= sinon
.stub().returns({
235 send
: sinon
.stub().returns()
237 expect(worker
.taskFunctions
.get('default')).toBeInstanceOf(Function
)
238 expect(worker
.taskFunctions
.get('fn1')).toBeInstanceOf(Function
)
239 expect(worker
.taskFunctions
.get('fn2')).toBeInstanceOf(Function
)
240 expect(worker
.taskFunctions
.size
).toBe(3)
241 expect(worker
.taskFunctions
.get('default')).toStrictEqual(
242 worker
.taskFunctions
.get('fn1')
244 expect(() => worker
.removeTaskFunction('default')).toThrowError(
246 'Cannot remove the task function with the default reserved name'
249 expect(() => worker
.removeTaskFunction('fn1')).toThrowError(
251 'Cannot remove the task function used as the default task function'
254 worker
.removeTaskFunction('fn2')
255 expect(worker
.taskFunctions
.get('default')).toBeInstanceOf(Function
)
256 expect(worker
.taskFunctions
.get('fn1')).toBeInstanceOf(Function
)
257 expect(worker
.taskFunctions
.get('fn2')).toBeUndefined()
258 expect(worker
.taskFunctions
.size
).toBe(2)
259 expect(worker
.getMainWorker().send
.calledOnce
).toBe(true)
262 it('Verify that listTaskFunctions() works', () => {
269 const worker
= new ClusterWorker({ fn1
, fn2
})
270 expect(worker
.listTaskFunctions()).toStrictEqual(['default', 'fn1', 'fn2'])
273 it('Verify that setDefaultTaskFunction() works', () => {
280 const worker
= new ThreadWorker({ fn1
, fn2
})
281 expect(worker
.taskFunctions
.get('default')).toBeInstanceOf(Function
)
282 expect(worker
.taskFunctions
.get('fn1')).toBeInstanceOf(Function
)
283 expect(worker
.taskFunctions
.get('fn2')).toBeInstanceOf(Function
)
284 expect(worker
.taskFunctions
.size
).toBe(3)
285 expect(worker
.taskFunctions
.get('default')).toStrictEqual(
286 worker
.taskFunctions
.get('fn1')
288 expect(() => worker
.setDefaultTaskFunction('default')).toThrowError(
290 'Cannot set the default task function reserved name as the default task function'
293 worker
.setDefaultTaskFunction('fn1')
294 expect(worker
.taskFunctions
.get('default')).toStrictEqual(
295 worker
.taskFunctions
.get('fn1')
297 worker
.setDefaultTaskFunction('fn2')
298 expect(worker
.taskFunctions
.get('default')).toStrictEqual(
299 worker
.taskFunctions
.get('fn2')