refactor: move worker setup into worker node constructor
[poolifier.git] / tests / pools / worker-node.test.mjs
CommitLineData
c3719753 1import { MessageChannel } from 'node:worker_threads'
a074ffee
JB
2import { expect } from 'expect'
3import { WorkerNode } from '../../lib/pools/worker-node.js'
4import { WorkerTypes } from '../../lib/index.js'
5import { CircularArray } from '../../lib/circular-array.js'
6import { Deque } from '../../lib/deque.js'
7import { DEFAULT_TASK_NAME } from '../../lib/utils.js'
26fb3c18
JB
8
9describe('Worker node test suite', () => {
c3719753
JB
10 const threadWorkerNode = new WorkerNode(
11 WorkerTypes.thread,
12 './tests/worker-files/thread/testWorker.mjs',
13 { tasksQueueBackPressureSize: 12 }
14 )
15 const clusterWorkerNode = new WorkerNode(
16 WorkerTypes.cluster,
17 './tests/worker-files/cluster/testWorker.js',
18 { tasksQueueBackPressureSize: 12 }
19 )
26fb3c18
JB
20
21 it('Worker node instantiation', () => {
948faff7 22 expect(() => new WorkerNode()).toThrow(
c3719753 23 new TypeError('Cannot construct a worker node without a worker type')
26fb3c18 24 )
c3719753
JB
25 expect(
26 () =>
27 new WorkerNode(
28 'invalidWorkerType',
29 './tests/worker-files/thread/testWorker.mjs',
30 { tasksQueueBackPressureSize: 12 }
31 )
32 ).toThrow(
33 new TypeError(
34 "Cannot construct a worker node with an invalid worker type 'invalidWorkerType'"
35 )
36 )
37 expect(
38 () =>
39 new WorkerNode(
40 WorkerTypes.thread,
41 './tests/worker-files/thread/testWorker.mjs'
42 )
43 ).toThrow(
26fb3c18 44 new TypeError(
c3719753 45 'Cannot construct a worker node without worker node options'
26fb3c18
JB
46 )
47 )
48 expect(
c3719753
JB
49 () =>
50 new WorkerNode(
51 WorkerTypes.thread,
52 './tests/worker-files/thread/testWorker.mjs',
53 ''
54 )
948faff7 55 ).toThrow(
26fb3c18 56 new TypeError(
c3719753 57 'Cannot construct a worker node with invalid options: must be a plain object'
26fb3c18
JB
58 )
59 )
c3719753
JB
60 expect(
61 () =>
62 new WorkerNode(
63 WorkerTypes.thread,
64 './tests/worker-files/thread/testWorker.mjs',
65 {}
66 )
67 ).toThrow(
5b49e864 68 new TypeError(
c3719753 69 'Cannot construct a worker node without a tasks queue back pressure size option'
5b49e864
JB
70 )
71 )
c3719753
JB
72 expect(
73 () =>
74 new WorkerNode(
75 WorkerTypes.thread,
76 './tests/worker-files/thread/testWorker.mjs',
77 { tasksQueueBackPressureSize: 'invalidTasksQueueBackPressureSize' }
78 )
79 ).toThrow(
80 new TypeError(
81 'Cannot construct a worker node with a tasks queue back pressure size option that is not an integer'
82 )
83 )
84 expect(
85 () =>
86 new WorkerNode(
87 WorkerTypes.thread,
88 './tests/worker-files/thread/testWorker.mjs',
89 { tasksQueueBackPressureSize: 0.2 }
90 )
91 ).toThrow(
92 new TypeError(
93 'Cannot construct a worker node with a tasks queue back pressure size option that is not an integer'
94 )
95 )
96 expect(
97 () =>
98 new WorkerNode(
99 WorkerTypes.thread,
100 './tests/worker-files/thread/testWorker.mjs',
101 { tasksQueueBackPressureSize: 0 }
102 )
103 ).toThrow(
5b49e864 104 new RangeError(
c3719753 105 'Cannot construct a worker node with a tasks queue back pressure size option that is not a positive integer'
5b49e864
JB
106 )
107 )
c3719753
JB
108 expect(
109 () =>
110 new WorkerNode(
111 WorkerTypes.thread,
112 './tests/worker-files/thread/testWorker.mjs',
113 { tasksQueueBackPressureSize: -1 }
114 )
115 ).toThrow(
5b49e864 116 new RangeError(
c3719753 117 'Cannot construct a worker node with a tasks queue back pressure size option that is not a positive integer'
5b49e864
JB
118 )
119 )
75de9f41 120 expect(threadWorkerNode).toBeInstanceOf(WorkerNode)
75de9f41 121 expect(threadWorkerNode.info).toStrictEqual({
c3719753 122 id: threadWorkerNode.worker.threadId,
26fb3c18
JB
123 type: WorkerTypes.thread,
124 dynamic: false,
125 ready: false
126 })
75de9f41
JB
127 expect(threadWorkerNode.usage).toStrictEqual({
128 tasks: {
129 executed: 0,
130 executing: 0,
131 queued: 0,
132 maxQueued: 0,
463226a4 133 sequentiallyStolen: 0,
75de9f41
JB
134 stolen: 0,
135 failed: 0
136 },
137 runTime: {
4ba4c7f9 138 history: new CircularArray()
75de9f41
JB
139 },
140 waitTime: {
4ba4c7f9 141 history: new CircularArray()
75de9f41
JB
142 },
143 elu: {
144 idle: {
4ba4c7f9 145 history: new CircularArray()
75de9f41
JB
146 },
147 active: {
4ba4c7f9 148 history: new CircularArray()
75de9f41
JB
149 }
150 }
151 })
152 expect(threadWorkerNode.messageChannel).toBeInstanceOf(MessageChannel)
153 expect(threadWorkerNode.tasksQueueBackPressureSize).toBe(12)
154 expect(threadWorkerNode.tasksQueue).toBeInstanceOf(Deque)
155 expect(threadWorkerNode.tasksQueue.size).toBe(0)
68f1f531
JB
156 expect(threadWorkerNode.tasksQueueSize()).toBe(
157 threadWorkerNode.tasksQueue.size
158 )
159 expect(threadWorkerNode.onBackPressureStarted).toBe(false)
75de9f41
JB
160 expect(threadWorkerNode.taskFunctionsUsage).toBeInstanceOf(Map)
161
162 expect(clusterWorkerNode).toBeInstanceOf(WorkerNode)
75de9f41 163 expect(clusterWorkerNode.info).toStrictEqual({
c3719753 164 id: clusterWorkerNode.worker.id,
75de9f41
JB
165 type: WorkerTypes.cluster,
166 dynamic: false,
167 ready: false
168 })
169 expect(clusterWorkerNode.usage).toStrictEqual({
26fb3c18
JB
170 tasks: {
171 executed: 0,
172 executing: 0,
173 queued: 0,
174 maxQueued: 0,
463226a4 175 sequentiallyStolen: 0,
26fb3c18
JB
176 stolen: 0,
177 failed: 0
178 },
179 runTime: {
4ba4c7f9 180 history: new CircularArray()
26fb3c18
JB
181 },
182 waitTime: {
4ba4c7f9 183 history: new CircularArray()
26fb3c18
JB
184 },
185 elu: {
186 idle: {
4ba4c7f9 187 history: new CircularArray()
26fb3c18
JB
188 },
189 active: {
4ba4c7f9 190 history: new CircularArray()
26fb3c18
JB
191 }
192 }
193 })
75de9f41
JB
194 expect(clusterWorkerNode.messageChannel).toBeUndefined()
195 expect(clusterWorkerNode.tasksQueueBackPressureSize).toBe(12)
196 expect(clusterWorkerNode.tasksQueue).toBeInstanceOf(Deque)
197 expect(clusterWorkerNode.tasksQueue.size).toBe(0)
68f1f531
JB
198 expect(clusterWorkerNode.tasksQueueSize()).toBe(
199 clusterWorkerNode.tasksQueue.size
200 )
201 expect(clusterWorkerNode.onBackPressureStarted).toBe(false)
75de9f41 202 expect(clusterWorkerNode.taskFunctionsUsage).toBeInstanceOf(Map)
26fb3c18
JB
203 })
204
205 it('Worker node getTaskFunctionWorkerUsage()', () => {
206 expect(() =>
75de9f41 207 threadWorkerNode.getTaskFunctionWorkerUsage('invalidTaskFunction')
948faff7 208 ).toThrow(
26fb3c18
JB
209 new TypeError(
210 "Cannot get task function worker usage for task function name 'invalidTaskFunction' when task function names list is not yet defined"
211 )
212 )
66979634 213 threadWorkerNode.info.taskFunctionNames = [DEFAULT_TASK_NAME, 'fn1']
26fb3c18 214 expect(() =>
75de9f41 215 threadWorkerNode.getTaskFunctionWorkerUsage('invalidTaskFunction')
948faff7 216 ).toThrow(
26fb3c18
JB
217 new TypeError(
218 "Cannot get task function worker usage for task function name 'invalidTaskFunction' when task function names list has less than 3 elements"
219 )
220 )
66979634 221 threadWorkerNode.info.taskFunctionNames = [DEFAULT_TASK_NAME, 'fn1', 'fn2']
6cd5248f 222 expect(
75de9f41 223 threadWorkerNode.getTaskFunctionWorkerUsage(DEFAULT_TASK_NAME)
6cd5248f 224 ).toStrictEqual({
26fb3c18
JB
225 tasks: {
226 executed: 0,
227 executing: 0,
228 queued: 0,
463226a4 229 sequentiallyStolen: 0,
5ad42e34 230 stolen: 0,
26fb3c18
JB
231 failed: 0
232 },
233 runTime: {
4ba4c7f9 234 history: new CircularArray()
26fb3c18
JB
235 },
236 waitTime: {
4ba4c7f9 237 history: new CircularArray()
26fb3c18
JB
238 },
239 elu: {
240 idle: {
4ba4c7f9 241 history: new CircularArray()
26fb3c18
JB
242 },
243 active: {
4ba4c7f9 244 history: new CircularArray()
26fb3c18
JB
245 }
246 }
247 })
75de9f41 248 expect(threadWorkerNode.getTaskFunctionWorkerUsage('fn1')).toStrictEqual({
26fb3c18
JB
249 tasks: {
250 executed: 0,
251 executing: 0,
252 queued: 0,
463226a4 253 sequentiallyStolen: 0,
5ad42e34 254 stolen: 0,
26fb3c18
JB
255 failed: 0
256 },
257 runTime: {
4ba4c7f9 258 history: new CircularArray()
26fb3c18
JB
259 },
260 waitTime: {
4ba4c7f9 261 history: new CircularArray()
26fb3c18
JB
262 },
263 elu: {
264 idle: {
4ba4c7f9 265 history: new CircularArray()
26fb3c18
JB
266 },
267 active: {
4ba4c7f9 268 history: new CircularArray()
26fb3c18
JB
269 }
270 }
271 })
75de9f41 272 expect(threadWorkerNode.getTaskFunctionWorkerUsage('fn2')).toStrictEqual({
26fb3c18
JB
273 tasks: {
274 executed: 0,
275 executing: 0,
276 queued: 0,
463226a4 277 sequentiallyStolen: 0,
5ad42e34 278 stolen: 0,
26fb3c18
JB
279 failed: 0
280 },
281 runTime: {
4ba4c7f9 282 history: new CircularArray()
26fb3c18
JB
283 },
284 waitTime: {
4ba4c7f9 285 history: new CircularArray()
26fb3c18
JB
286 },
287 elu: {
288 idle: {
4ba4c7f9 289 history: new CircularArray()
26fb3c18
JB
290 },
291 active: {
4ba4c7f9 292 history: new CircularArray()
26fb3c18
JB
293 }
294 }
295 })
75de9f41 296 expect(threadWorkerNode.taskFunctionsUsage.size).toBe(2)
26fb3c18 297 })
adee6053
JB
298
299 it('Worker node deleteTaskFunctionWorkerUsage()', () => {
300 expect(threadWorkerNode.info.taskFunctionNames).toStrictEqual([
301 DEFAULT_TASK_NAME,
302 'fn1',
303 'fn2'
304 ])
305 expect(threadWorkerNode.taskFunctionsUsage.size).toBe(2)
306 expect(
307 threadWorkerNode.deleteTaskFunctionWorkerUsage('invalidTaskFunction')
308 ).toBe(false)
309 expect(threadWorkerNode.taskFunctionsUsage.size).toBe(2)
310 expect(threadWorkerNode.deleteTaskFunctionWorkerUsage('fn1')).toBe(true)
311 expect(threadWorkerNode.taskFunctionsUsage.size).toBe(1)
312 })
26fb3c18 313})