refactor: remove home made random integer generator
[poolifier.git] / tests / utils.test.mjs
CommitLineData
a074ffee
JB
1import { Worker } from 'node:worker_threads'
2import cluster from 'node:cluster'
3import os from 'node:os'
4import { randomInt } from 'node:crypto'
5import { expect } from 'expect'
6import {
9274aa14
JB
7 DEFAULT_MEASUREMENT_STATISTICS_REQUIREMENTS,
8 DEFAULT_TASK_NAME,
9274aa14 9 EMPTY_FUNCTION,
afe0d5bf 10 availableParallelism,
dc021bcc 11 average,
39618ede 12 buildWorkerChoiceStrategyOptions,
98446b39 13 exponentialDelay,
39618ede 14 getWorkerChoiceStrategyRetries,
9fe8fd69 15 getWorkerId,
a074ffee 16 getWorkerType,
78ac1a90 17 isAsyncFunction,
59317253 18 isKillBehavior,
afe0d5bf 19 isPlainObject,
90d6701c 20 max,
afe0d5bf 21 median,
90d6701c 22 min,
55082af9 23 // once,
a91f7b35 24 round,
970b38d6 25 secureRandom,
bfc75cca 26 sleep
d35e5717 27} from '../lib/utils.cjs'
39618ede
JB
28import {
29 FixedClusterPool,
30 FixedThreadPool,
31 KillBehaviors,
32 WorkerTypes
33} from '../lib/index.cjs'
aba955e1
JB
34
35describe('Utils test suite', () => {
9274aa14
JB
36 it('Verify DEFAULT_TASK_NAME value', () => {
37 expect(DEFAULT_TASK_NAME).toBe('default')
38 })
39
40 it('Verify EMPTY_FUNCTION value', () => {
41 expect(EMPTY_FUNCTION).toStrictEqual(expect.any(Function))
42 })
43
9274aa14
JB
44 it('Verify DEFAULT_MEASUREMENT_STATISTICS_REQUIREMENTS values', () => {
45 expect(DEFAULT_MEASUREMENT_STATISTICS_REQUIREMENTS).toStrictEqual({
46 aggregate: false,
47 average: false,
48 median: false
49 })
50 })
51
afe0d5bf 52 it('Verify availableParallelism() behavior', () => {
9fe8fd69
JB
53 const parallelism = availableParallelism()
54 expect(typeof parallelism === 'number').toBe(true)
37e31fac 55 expect(Number.isSafeInteger(parallelism)).toBe(true)
562a4037
JB
56 let expectedParallelism = 1
57 try {
58 expectedParallelism = os.availableParallelism()
59 } catch {
60 expectedParallelism = os.cpus().length
61 }
62 expect(parallelism).toBe(expectedParallelism)
9fe8fd69
JB
63 })
64
65 it('Verify getWorkerType() behavior', () => {
66 expect(
b2fd3f4a 67 getWorkerType(new Worker('./tests/worker-files/thread/testWorker.mjs'))
9fe8fd69
JB
68 ).toBe(WorkerTypes.thread)
69 expect(getWorkerType(cluster.fork())).toBe(WorkerTypes.cluster)
70 })
71
72 it('Verify getWorkerId() behavior', () => {
b2fd3f4a
JB
73 const threadWorker = new Worker(
74 './tests/worker-files/thread/testWorker.mjs'
75 )
9fe8fd69
JB
76 const clusterWorker = cluster.fork()
77 expect(getWorkerId(threadWorker)).toBe(threadWorker.threadId)
78 expect(getWorkerId(clusterWorker)).toBe(clusterWorker.id)
afe0d5bf
JB
79 })
80
bb9423b7 81 it('Verify sleep() behavior', async () => {
65deb7f0 82 const start = performance.now()
b91134ce
JB
83 const sleepMs = 1000
84 await sleep(sleepMs)
6543999f 85 const elapsed = performance.now() - start
b91134ce 86 expect(elapsed).toBeGreaterThanOrEqual(sleepMs - 1)
98446b39
JB
87 })
88
89 it('Verify exponentialDelay() behavior', () => {
1f0766e7
JB
90 const delay = exponentialDelay(randomInt(1000))
91 expect(typeof delay === 'number').toBe(true)
92 expect(delay).toBeGreaterThanOrEqual(Number.MIN_VALUE)
93 expect(delay).toBeLessThanOrEqual(Number.MAX_VALUE)
98446b39
JB
94 })
95
dc021bcc
JB
96 it('Verify average() computation', () => {
97 expect(average([])).toBe(0)
98 expect(average([0.08])).toBe(0.08)
99 expect(average([0.25, 4.75, 3.05, 6.04, 1.01, 2.02, 5.03])).toBe(
100 3.1642857142857146
101 )
102 expect(average([0.25, 4.75, 3.05, 6.04, 1.01, 2.02])).toBe(
103 2.8533333333333335
104 )
105 })
106
bb615bd0 107 it('Verify median() computation', () => {
4a45e8d2 108 expect(median([])).toBe(0)
76845835
JB
109 expect(median([0.08])).toBe(0.08)
110 expect(median([0.25, 4.75, 3.05, 6.04, 1.01, 2.02, 5.03])).toBe(3.05)
111 expect(median([0.25, 4.75, 3.05, 6.04, 1.01, 2.02])).toBe(2.535)
aba955e1
JB
112 })
113
afe0d5bf
JB
114 it('Verify round() behavior', () => {
115 expect(round(0)).toBe(0)
116 expect(round(0.5, 0)).toBe(1)
117 expect(round(0.5)).toBe(0.5)
118 expect(round(-0.5, 0)).toBe(-1)
119 expect(round(-0.5)).toBe(-0.5)
120 expect(round(1.005)).toBe(1.01)
121 expect(round(2.175)).toBe(2.18)
122 expect(round(5.015)).toBe(5.02)
123 expect(round(-1.005)).toBe(-1.01)
124 expect(round(-2.175)).toBe(-2.18)
125 expect(round(-5.015)).toBe(-5.02)
126 })
127
aba955e1
JB
128 it('Verify isPlainObject() behavior', () => {
129 expect(isPlainObject(null)).toBe(false)
130 expect(isPlainObject(undefined)).toBe(false)
131 expect(isPlainObject(true)).toBe(false)
132 expect(isPlainObject(false)).toBe(false)
133 expect(isPlainObject(0)).toBe(false)
134 expect(isPlainObject('')).toBe(false)
135 expect(isPlainObject([])).toBe(false)
136 expect(isPlainObject(() => {})).toBe(false)
137 expect(isPlainObject(new Date())).toBe(false)
138 expect(isPlainObject(new RegExp())).toBe(false)
139 expect(isPlainObject(new Error())).toBe(false)
140 expect(isPlainObject(new Map())).toBe(false)
141 expect(isPlainObject(new Set())).toBe(false)
142 expect(isPlainObject(new WeakMap())).toBe(false)
143 expect(isPlainObject(new WeakSet())).toBe(false)
144 expect(isPlainObject(new Int8Array())).toBe(false)
145 expect(isPlainObject(new Uint8Array())).toBe(false)
146 expect(isPlainObject(new Uint8ClampedArray())).toBe(false)
147 expect(isPlainObject(new Int16Array())).toBe(false)
148 expect(isPlainObject(new Uint16Array())).toBe(false)
149 expect(isPlainObject(new Int32Array())).toBe(false)
150 expect(isPlainObject(new Uint32Array())).toBe(false)
151 expect(isPlainObject(new Float32Array())).toBe(false)
152 expect(isPlainObject(new Float64Array())).toBe(false)
153 expect(isPlainObject(new BigInt64Array())).toBe(false)
154 expect(isPlainObject(new BigUint64Array())).toBe(false)
155 expect(isPlainObject(new Promise(() => {}))).toBe(false)
156 expect(isPlainObject(new WeakRef({}))).toBe(false)
157 expect(isPlainObject(new FinalizationRegistry(() => {}))).toBe(false)
158 expect(isPlainObject(new ArrayBuffer())).toBe(false)
159 expect(isPlainObject(new SharedArrayBuffer())).toBe(false)
160 expect(isPlainObject(new DataView(new ArrayBuffer()))).toBe(false)
161 expect(isPlainObject({})).toBe(true)
162 expect(isPlainObject({ a: 1 })).toBe(true)
163 })
47aacbaa
JB
164
165 it('Verify isKillBehavior() behavior', () => {
166 expect(isKillBehavior(KillBehaviors.SOFT, KillBehaviors.SOFT)).toBe(true)
167 expect(isKillBehavior(KillBehaviors.SOFT, KillBehaviors.HARD)).toBe(false)
168 expect(isKillBehavior(KillBehaviors.HARD, KillBehaviors.HARD)).toBe(true)
169 expect(isKillBehavior(KillBehaviors.HARD, KillBehaviors.SOFT)).toBe(false)
170 expect(isKillBehavior(KillBehaviors.SOFT)).toBe(false)
171 expect(isKillBehavior(KillBehaviors.HARD)).toBe(false)
172 expect(isKillBehavior(KillBehaviors.HARD, null)).toBe(false)
78ac1a90 173 expect(isKillBehavior(KillBehaviors.HARD, undefined)).toBe(false)
47aacbaa
JB
174 expect(isKillBehavior(KillBehaviors.SOFT, 'unknown')).toBe(false)
175 })
78ac1a90
JB
176
177 it('Verify isAsyncFunction() behavior', () => {
178 expect(isAsyncFunction(null)).toBe(false)
179 expect(isAsyncFunction(undefined)).toBe(false)
180 expect(isAsyncFunction(true)).toBe(false)
181 expect(isAsyncFunction(false)).toBe(false)
182 expect(isAsyncFunction(0)).toBe(false)
183 expect(isAsyncFunction('')).toBe(false)
184 expect(isAsyncFunction([])).toBe(false)
185 expect(isAsyncFunction(new Date())).toBe(false)
186 expect(isAsyncFunction(new RegExp())).toBe(false)
187 expect(isAsyncFunction(new Error())).toBe(false)
188 expect(isAsyncFunction(new Map())).toBe(false)
189 expect(isAsyncFunction(new Set())).toBe(false)
190 expect(isAsyncFunction(new WeakMap())).toBe(false)
191 expect(isAsyncFunction(new WeakSet())).toBe(false)
192 expect(isAsyncFunction(new Int8Array())).toBe(false)
193 expect(isAsyncFunction(new Uint8Array())).toBe(false)
194 expect(isAsyncFunction(new Uint8ClampedArray())).toBe(false)
195 expect(isAsyncFunction(new Int16Array())).toBe(false)
196 expect(isAsyncFunction(new Uint16Array())).toBe(false)
197 expect(isAsyncFunction(new Int32Array())).toBe(false)
198 expect(isAsyncFunction(new Uint32Array())).toBe(false)
199 expect(isAsyncFunction(new Float32Array())).toBe(false)
200 expect(isAsyncFunction(new Float64Array())).toBe(false)
201 expect(isAsyncFunction(new BigInt64Array())).toBe(false)
202 expect(isAsyncFunction(new BigUint64Array())).toBe(false)
203 expect(isAsyncFunction(new Promise(() => {}))).toBe(false)
204 expect(isAsyncFunction(new WeakRef({}))).toBe(false)
205 expect(isAsyncFunction(new FinalizationRegistry(() => {}))).toBe(false)
206 expect(isAsyncFunction(new ArrayBuffer())).toBe(false)
207 expect(isAsyncFunction(new SharedArrayBuffer())).toBe(false)
208 expect(isAsyncFunction(new DataView(new ArrayBuffer()))).toBe(false)
209 expect(isAsyncFunction({})).toBe(false)
210 expect(isAsyncFunction({ a: 1 })).toBe(false)
211 expect(isAsyncFunction(() => {})).toBe(false)
212 expect(isAsyncFunction(function () {})).toBe(false)
213 expect(isAsyncFunction(function named () {})).toBe(false)
214 expect(isAsyncFunction(async () => {})).toBe(true)
215 expect(isAsyncFunction(async function () {})).toBe(true)
216 expect(isAsyncFunction(async function named () {})).toBe(true)
217 })
a91f7b35 218
970b38d6
JB
219 it('Verify secureRandom() behavior', () => {
220 const randomNumber = secureRandom()
221 expect(typeof randomNumber === 'number').toBe(true)
222 expect(randomNumber).toBeGreaterThanOrEqual(0)
223 expect(randomNumber).toBeLessThan(1)
224 })
90d6701c
JB
225
226 it('Verify min() behavior', () => {
625449e0 227 expect(min()).toBe(Infinity)
90d6701c
JB
228 expect(min(1, 2)).toBe(1)
229 expect(min(2, 1)).toBe(1)
230 expect(min(1, 1)).toBe(1)
231 })
232
233 it('Verify max() behavior', () => {
625449e0 234 expect(max()).toBe(-Infinity)
90d6701c
JB
235 expect(max(1, 2)).toBe(2)
236 expect(max(2, 1)).toBe(2)
237 expect(max(1, 1)).toBe(1)
238 })
d91689fd 239
39618ede
JB
240 it('Verify getWorkerChoiceStrategyRetries() behavior', async () => {
241 const numberOfThreads = 4
242 const pool = new FixedThreadPool(
243 numberOfThreads,
244 './tests/worker-files/thread/testWorker.mjs'
245 )
246 expect(getWorkerChoiceStrategyRetries(pool)).toBe(pool.info.maxSize * 2)
125c84e4
JB
247 const workerChoiceStrategyOptions = {
248 runTime: { median: true },
249 waitTime: { median: true },
250 elu: { median: true },
251 weights: {
252 0: 100,
253 1: 100
254 }
255 }
256 expect(
257 getWorkerChoiceStrategyRetries(pool, workerChoiceStrategyOptions)
258 ).toBe(
259 pool.info.maxSize +
260 Object.keys(workerChoiceStrategyOptions.weights).length
261 )
39618ede
JB
262 await pool.destroy()
263 })
264
265 it('Verify buildWorkerChoiceStrategyOptions() behavior', async () => {
266 const numberOfWorkers = 4
267 const pool = new FixedClusterPool(
268 numberOfWorkers,
269 './tests/worker-files/cluster/testWorker.cjs'
270 )
271 expect(buildWorkerChoiceStrategyOptions(pool)).toStrictEqual({
00e1bdeb
JB
272 runTime: { median: false },
273 waitTime: { median: false },
274 elu: { median: false },
275 weights: expect.objectContaining({
276 0: expect.any(Number),
39618ede 277 [pool.info.maxSize - 1]: expect.any(Number)
00e1bdeb
JB
278 })
279 })
125c84e4
JB
280 const workerChoiceStrategyOptions = {
281 runTime: { median: true },
282 waitTime: { median: true },
283 elu: { median: true },
284 weights: {
285 0: 100,
286 1: 100
287 }
288 }
289 expect(
290 buildWorkerChoiceStrategyOptions(pool, workerChoiceStrategyOptions)
291 ).toStrictEqual(workerChoiceStrategyOptions)
39618ede 292 await pool.destroy()
00e1bdeb
JB
293 })
294
55082af9
JB
295 // it('Verify once()', () => {
296 // let called = 0
297 // const fn = () => ++called
298 // const onceFn = once(fn, this)
299 // const result1 = onceFn()
300 // expect(called).toBe(1)
301 // expect(result1).toBe(1)
302 // const result2 = onceFn()
303 // expect(called).toBe(1)
304 // expect(result2).toBe(1)
305 // const result3 = onceFn()
306 // expect(called).toBe(1)
307 // expect(result3).toBe(1)
308 // })
aba955e1 309})