test: refine UTs
[poolifier.git] / tests / utils.test.js
1 const { randomInt } = require('crypto')
2 const { Worker } = require('worker_threads')
3 const cluster = require('cluster')
4 const os = require('os')
5 const { expect } = require('expect')
6 const {
7 CircularArray,
8 DEFAULT_CIRCULAR_ARRAY_SIZE
9 } = require('../lib/circular-array')
10 const {
11 DEFAULT_MEASUREMENT_STATISTICS_REQUIREMENTS,
12 DEFAULT_TASK_NAME,
13 DEFAULT_WORKER_CHOICE_STRATEGY_OPTIONS,
14 EMPTY_FUNCTION,
15 availableParallelism,
16 average,
17 exponentialDelay,
18 getWorkerType,
19 getWorkerId,
20 isAsyncFunction,
21 isKillBehavior,
22 isPlainObject,
23 median,
24 round,
25 secureRandom,
26 sleep,
27 updateMeasurementStatistics
28 } = require('../lib/utils')
29 const { KillBehaviors, WorkerTypes } = require('../lib')
30
31 describe('Utils test suite', () => {
32 it('Verify DEFAULT_TASK_NAME value', () => {
33 expect(DEFAULT_TASK_NAME).toBe('default')
34 })
35
36 it('Verify EMPTY_FUNCTION value', () => {
37 expect(EMPTY_FUNCTION).toStrictEqual(expect.any(Function))
38 })
39
40 it('Verify DEFAULT_WORKER_CHOICE_STRATEGY_OPTIONS values', () => {
41 expect(DEFAULT_WORKER_CHOICE_STRATEGY_OPTIONS).toStrictEqual({
42 retries: 6,
43 runTime: { median: false },
44 waitTime: { median: false },
45 elu: { median: false }
46 })
47 })
48
49 it('Verify DEFAULT_MEASUREMENT_STATISTICS_REQUIREMENTS values', () => {
50 expect(DEFAULT_MEASUREMENT_STATISTICS_REQUIREMENTS).toStrictEqual({
51 aggregate: false,
52 average: false,
53 median: false
54 })
55 })
56
57 it('Verify availableParallelism() behavior', () => {
58 const parallelism = availableParallelism()
59 expect(typeof parallelism === 'number').toBe(true)
60 let expectedParallelism = 1
61 try {
62 expectedParallelism = os.availableParallelism()
63 } catch {
64 expectedParallelism = os.cpus().length
65 }
66 expect(parallelism).toBe(expectedParallelism)
67 expect(Number.isSafeInteger(parallelism)).toBe(true)
68 })
69
70 it('Verify getWorkerType() behavior', () => {
71 expect(
72 getWorkerType(new Worker('./tests/worker-files/thread/testWorker.js'))
73 ).toBe(WorkerTypes.thread)
74 expect(getWorkerType(cluster.fork())).toBe(WorkerTypes.cluster)
75 })
76
77 it('Verify getWorkerId() behavior', () => {
78 const threadWorker = new Worker('./tests/worker-files/thread/testWorker.js')
79 const clusterWorker = cluster.fork()
80 expect(getWorkerId(threadWorker)).toBe(threadWorker.threadId)
81 expect(getWorkerId(clusterWorker)).toBe(clusterWorker.id)
82 })
83
84 it('Verify sleep() behavior', async () => {
85 const start = performance.now()
86 await sleep(1000)
87 const elapsed = performance.now() - start
88 expect(elapsed).toBeGreaterThanOrEqual(999)
89 })
90
91 it('Verify exponentialDelay() behavior', () => {
92 const delay = exponentialDelay(randomInt(1000))
93 expect(typeof delay === 'number').toBe(true)
94 expect(delay).toBeGreaterThanOrEqual(Number.MIN_VALUE)
95 expect(delay).toBeLessThanOrEqual(Number.MAX_VALUE)
96 })
97
98 it('Verify average() computation', () => {
99 expect(average([])).toBe(0)
100 expect(average([0.08])).toBe(0.08)
101 expect(average([0.25, 4.75, 3.05, 6.04, 1.01, 2.02, 5.03])).toBe(
102 3.1642857142857146
103 )
104 expect(average([0.25, 4.75, 3.05, 6.04, 1.01, 2.02])).toBe(
105 2.8533333333333335
106 )
107 })
108
109 it('Verify median() computation', () => {
110 expect(median([])).toBe(0)
111 expect(median([0.08])).toBe(0.08)
112 expect(median([0.25, 4.75, 3.05, 6.04, 1.01, 2.02, 5.03])).toBe(3.05)
113 expect(median([0.25, 4.75, 3.05, 6.04, 1.01, 2.02])).toBe(2.535)
114 })
115
116 it('Verify round() behavior', () => {
117 expect(round(0)).toBe(0)
118 expect(round(0.5, 0)).toBe(1)
119 expect(round(0.5)).toBe(0.5)
120 expect(round(-0.5, 0)).toBe(-1)
121 expect(round(-0.5)).toBe(-0.5)
122 expect(round(1.005)).toBe(1.01)
123 expect(round(2.175)).toBe(2.18)
124 expect(round(5.015)).toBe(5.02)
125 expect(round(-1.005)).toBe(-1.01)
126 expect(round(-2.175)).toBe(-2.18)
127 expect(round(-5.015)).toBe(-5.02)
128 })
129
130 it('Verify isPlainObject() behavior', () => {
131 expect(isPlainObject(null)).toBe(false)
132 expect(isPlainObject(undefined)).toBe(false)
133 expect(isPlainObject(true)).toBe(false)
134 expect(isPlainObject(false)).toBe(false)
135 expect(isPlainObject(0)).toBe(false)
136 expect(isPlainObject('')).toBe(false)
137 expect(isPlainObject([])).toBe(false)
138 expect(isPlainObject(() => {})).toBe(false)
139 expect(isPlainObject(new Date())).toBe(false)
140 expect(isPlainObject(new RegExp())).toBe(false)
141 expect(isPlainObject(new Error())).toBe(false)
142 expect(isPlainObject(new Map())).toBe(false)
143 expect(isPlainObject(new Set())).toBe(false)
144 expect(isPlainObject(new WeakMap())).toBe(false)
145 expect(isPlainObject(new WeakSet())).toBe(false)
146 expect(isPlainObject(new Int8Array())).toBe(false)
147 expect(isPlainObject(new Uint8Array())).toBe(false)
148 expect(isPlainObject(new Uint8ClampedArray())).toBe(false)
149 expect(isPlainObject(new Int16Array())).toBe(false)
150 expect(isPlainObject(new Uint16Array())).toBe(false)
151 expect(isPlainObject(new Int32Array())).toBe(false)
152 expect(isPlainObject(new Uint32Array())).toBe(false)
153 expect(isPlainObject(new Float32Array())).toBe(false)
154 expect(isPlainObject(new Float64Array())).toBe(false)
155 expect(isPlainObject(new BigInt64Array())).toBe(false)
156 expect(isPlainObject(new BigUint64Array())).toBe(false)
157 expect(isPlainObject(new Promise(() => {}))).toBe(false)
158 expect(isPlainObject(new WeakRef({}))).toBe(false)
159 expect(isPlainObject(new FinalizationRegistry(() => {}))).toBe(false)
160 expect(isPlainObject(new ArrayBuffer())).toBe(false)
161 expect(isPlainObject(new SharedArrayBuffer())).toBe(false)
162 expect(isPlainObject(new DataView(new ArrayBuffer()))).toBe(false)
163 expect(isPlainObject({})).toBe(true)
164 expect(isPlainObject({ a: 1 })).toBe(true)
165 })
166
167 it('Verify isKillBehavior() behavior', () => {
168 expect(isKillBehavior(KillBehaviors.SOFT, KillBehaviors.SOFT)).toBe(true)
169 expect(isKillBehavior(KillBehaviors.SOFT, KillBehaviors.HARD)).toBe(false)
170 expect(isKillBehavior(KillBehaviors.HARD, KillBehaviors.HARD)).toBe(true)
171 expect(isKillBehavior(KillBehaviors.HARD, KillBehaviors.SOFT)).toBe(false)
172 expect(isKillBehavior(KillBehaviors.SOFT)).toBe(false)
173 expect(isKillBehavior(KillBehaviors.HARD)).toBe(false)
174 expect(isKillBehavior(KillBehaviors.HARD, null)).toBe(false)
175 expect(isKillBehavior(KillBehaviors.HARD, undefined)).toBe(false)
176 expect(isKillBehavior(KillBehaviors.SOFT, 'unknown')).toBe(false)
177 })
178
179 it('Verify isAsyncFunction() behavior', () => {
180 expect(isAsyncFunction(null)).toBe(false)
181 expect(isAsyncFunction(undefined)).toBe(false)
182 expect(isAsyncFunction(true)).toBe(false)
183 expect(isAsyncFunction(false)).toBe(false)
184 expect(isAsyncFunction(0)).toBe(false)
185 expect(isAsyncFunction('')).toBe(false)
186 expect(isAsyncFunction([])).toBe(false)
187 expect(isAsyncFunction(new Date())).toBe(false)
188 expect(isAsyncFunction(new RegExp())).toBe(false)
189 expect(isAsyncFunction(new Error())).toBe(false)
190 expect(isAsyncFunction(new Map())).toBe(false)
191 expect(isAsyncFunction(new Set())).toBe(false)
192 expect(isAsyncFunction(new WeakMap())).toBe(false)
193 expect(isAsyncFunction(new WeakSet())).toBe(false)
194 expect(isAsyncFunction(new Int8Array())).toBe(false)
195 expect(isAsyncFunction(new Uint8Array())).toBe(false)
196 expect(isAsyncFunction(new Uint8ClampedArray())).toBe(false)
197 expect(isAsyncFunction(new Int16Array())).toBe(false)
198 expect(isAsyncFunction(new Uint16Array())).toBe(false)
199 expect(isAsyncFunction(new Int32Array())).toBe(false)
200 expect(isAsyncFunction(new Uint32Array())).toBe(false)
201 expect(isAsyncFunction(new Float32Array())).toBe(false)
202 expect(isAsyncFunction(new Float64Array())).toBe(false)
203 expect(isAsyncFunction(new BigInt64Array())).toBe(false)
204 expect(isAsyncFunction(new BigUint64Array())).toBe(false)
205 expect(isAsyncFunction(new Promise(() => {}))).toBe(false)
206 expect(isAsyncFunction(new WeakRef({}))).toBe(false)
207 expect(isAsyncFunction(new FinalizationRegistry(() => {}))).toBe(false)
208 expect(isAsyncFunction(new ArrayBuffer())).toBe(false)
209 expect(isAsyncFunction(new SharedArrayBuffer())).toBe(false)
210 expect(isAsyncFunction(new DataView(new ArrayBuffer()))).toBe(false)
211 expect(isAsyncFunction({})).toBe(false)
212 expect(isAsyncFunction({ a: 1 })).toBe(false)
213 expect(isAsyncFunction(() => {})).toBe(false)
214 expect(isAsyncFunction(function () {})).toBe(false)
215 expect(isAsyncFunction(function named () {})).toBe(false)
216 expect(isAsyncFunction(async () => {})).toBe(true)
217 expect(isAsyncFunction(async function () {})).toBe(true)
218 expect(isAsyncFunction(async function named () {})).toBe(true)
219 })
220
221 it('Verify updateMeasurementStatistics() behavior', () => {
222 const measurementStatistics = {
223 history: new CircularArray()
224 }
225 updateMeasurementStatistics(
226 measurementStatistics,
227 { aggregate: true, average: false, median: false },
228 0.01
229 )
230 expect(measurementStatistics).toStrictEqual({
231 aggregate: 0.01,
232 maximum: 0.01,
233 minimum: 0.01,
234 history: new CircularArray()
235 })
236 updateMeasurementStatistics(
237 measurementStatistics,
238 { aggregate: true, average: false, median: false },
239 0.02
240 )
241 expect(measurementStatistics).toStrictEqual({
242 aggregate: 0.03,
243 maximum: 0.02,
244 minimum: 0.01,
245 history: new CircularArray()
246 })
247 updateMeasurementStatistics(
248 measurementStatistics,
249 { aggregate: true, average: true, median: false },
250 0.001
251 )
252 expect(measurementStatistics).toStrictEqual({
253 aggregate: 0.031,
254 maximum: 0.02,
255 minimum: 0.001,
256 average: 0.001,
257 history: new CircularArray(DEFAULT_CIRCULAR_ARRAY_SIZE, 0.001)
258 })
259 updateMeasurementStatistics(
260 measurementStatistics,
261 { aggregate: true, average: true, median: false },
262 0.003
263 )
264 expect(measurementStatistics).toStrictEqual({
265 aggregate: 0.034,
266 maximum: 0.02,
267 minimum: 0.001,
268 average: 0.002,
269 history: new CircularArray(DEFAULT_CIRCULAR_ARRAY_SIZE, 0.001, 0.003)
270 })
271 updateMeasurementStatistics(
272 measurementStatistics,
273 { aggregate: true, average: false, median: true },
274 0.006
275 )
276 expect(measurementStatistics).toStrictEqual({
277 aggregate: 0.04,
278 maximum: 0.02,
279 minimum: 0.001,
280 median: 0.003,
281 history: new CircularArray(
282 DEFAULT_CIRCULAR_ARRAY_SIZE,
283 0.001,
284 0.003,
285 0.006
286 )
287 })
288 updateMeasurementStatistics(
289 measurementStatistics,
290 { aggregate: true, average: true, median: false },
291 0.01
292 )
293 expect(measurementStatistics).toStrictEqual({
294 aggregate: 0.05,
295 maximum: 0.02,
296 minimum: 0.001,
297 average: 0.005,
298 history: new CircularArray(
299 DEFAULT_CIRCULAR_ARRAY_SIZE,
300 0.001,
301 0.003,
302 0.006,
303 0.01
304 )
305 })
306 })
307
308 it('Verify secureRandom() behavior', () => {
309 const randomNumber = secureRandom()
310 expect(typeof randomNumber === 'number').toBe(true)
311 expect(randomNumber).toBeGreaterThanOrEqual(0)
312 expect(randomNumber).toBeLessThan(1)
313 })
314 })