test: switch thread worker to ESM
[poolifier.git] / tests / utils.test.mjs
1 import { Worker } from 'node:worker_threads'
2 import cluster from 'node:cluster'
3 import os from 'node:os'
4 import { randomInt } from 'node:crypto'
5 import { expect } from 'expect'
6 import {
7 DEFAULT_MEASUREMENT_STATISTICS_REQUIREMENTS,
8 DEFAULT_TASK_NAME,
9 DEFAULT_WORKER_CHOICE_STRATEGY_OPTIONS,
10 EMPTY_FUNCTION,
11 availableParallelism,
12 average,
13 exponentialDelay,
14 getWorkerId,
15 getWorkerType,
16 isAsyncFunction,
17 isKillBehavior,
18 isPlainObject,
19 max,
20 median,
21 min,
22 round,
23 secureRandom,
24 sleep
25 } from '../lib/utils.js'
26 import { KillBehaviors, WorkerTypes } from '../lib/index.js'
27
28 describe('Utils test suite', () => {
29 it('Verify DEFAULT_TASK_NAME value', () => {
30 expect(DEFAULT_TASK_NAME).toBe('default')
31 })
32
33 it('Verify EMPTY_FUNCTION value', () => {
34 expect(EMPTY_FUNCTION).toStrictEqual(expect.any(Function))
35 })
36
37 it('Verify DEFAULT_WORKER_CHOICE_STRATEGY_OPTIONS values', () => {
38 expect(DEFAULT_WORKER_CHOICE_STRATEGY_OPTIONS).toStrictEqual({
39 retries: 6,
40 runTime: { median: false },
41 waitTime: { median: false },
42 elu: { median: false }
43 })
44 })
45
46 it('Verify DEFAULT_MEASUREMENT_STATISTICS_REQUIREMENTS values', () => {
47 expect(DEFAULT_MEASUREMENT_STATISTICS_REQUIREMENTS).toStrictEqual({
48 aggregate: false,
49 average: false,
50 median: false
51 })
52 })
53
54 it('Verify availableParallelism() behavior', () => {
55 const parallelism = availableParallelism()
56 expect(typeof parallelism === 'number').toBe(true)
57 expect(Number.isSafeInteger(parallelism)).toBe(true)
58 let expectedParallelism = 1
59 try {
60 expectedParallelism = os.availableParallelism()
61 } catch {
62 expectedParallelism = os.cpus().length
63 }
64 expect(parallelism).toBe(expectedParallelism)
65 })
66
67 it('Verify getWorkerType() behavior', () => {
68 expect(
69 getWorkerType(new Worker('./tests/worker-files/thread/testWorker.mjs'))
70 ).toBe(WorkerTypes.thread)
71 expect(getWorkerType(cluster.fork())).toBe(WorkerTypes.cluster)
72 })
73
74 it('Verify getWorkerId() behavior', () => {
75 const threadWorker = new Worker(
76 './tests/worker-files/thread/testWorker.mjs'
77 )
78 const clusterWorker = cluster.fork()
79 expect(getWorkerId(threadWorker)).toBe(threadWorker.threadId)
80 expect(getWorkerId(clusterWorker)).toBe(clusterWorker.id)
81 })
82
83 it('Verify sleep() behavior', async () => {
84 const start = performance.now()
85 await sleep(1000)
86 const elapsed = performance.now() - start
87 expect(elapsed).toBeGreaterThanOrEqual(999)
88 })
89
90 it('Verify exponentialDelay() behavior', () => {
91 const delay = exponentialDelay(randomInt(1000))
92 expect(typeof delay === 'number').toBe(true)
93 expect(delay).toBeGreaterThanOrEqual(Number.MIN_VALUE)
94 expect(delay).toBeLessThanOrEqual(Number.MAX_VALUE)
95 })
96
97 it('Verify average() computation', () => {
98 expect(average([])).toBe(0)
99 expect(average([0.08])).toBe(0.08)
100 expect(average([0.25, 4.75, 3.05, 6.04, 1.01, 2.02, 5.03])).toBe(
101 3.1642857142857146
102 )
103 expect(average([0.25, 4.75, 3.05, 6.04, 1.01, 2.02])).toBe(
104 2.8533333333333335
105 )
106 })
107
108 it('Verify median() computation', () => {
109 expect(median([])).toBe(0)
110 expect(median([0.08])).toBe(0.08)
111 expect(median([0.25, 4.75, 3.05, 6.04, 1.01, 2.02, 5.03])).toBe(3.05)
112 expect(median([0.25, 4.75, 3.05, 6.04, 1.01, 2.02])).toBe(2.535)
113 })
114
115 it('Verify round() behavior', () => {
116 expect(round(0)).toBe(0)
117 expect(round(0.5, 0)).toBe(1)
118 expect(round(0.5)).toBe(0.5)
119 expect(round(-0.5, 0)).toBe(-1)
120 expect(round(-0.5)).toBe(-0.5)
121 expect(round(1.005)).toBe(1.01)
122 expect(round(2.175)).toBe(2.18)
123 expect(round(5.015)).toBe(5.02)
124 expect(round(-1.005)).toBe(-1.01)
125 expect(round(-2.175)).toBe(-2.18)
126 expect(round(-5.015)).toBe(-5.02)
127 })
128
129 it('Verify isPlainObject() behavior', () => {
130 expect(isPlainObject(null)).toBe(false)
131 expect(isPlainObject(undefined)).toBe(false)
132 expect(isPlainObject(true)).toBe(false)
133 expect(isPlainObject(false)).toBe(false)
134 expect(isPlainObject(0)).toBe(false)
135 expect(isPlainObject('')).toBe(false)
136 expect(isPlainObject([])).toBe(false)
137 expect(isPlainObject(() => {})).toBe(false)
138 expect(isPlainObject(new Date())).toBe(false)
139 expect(isPlainObject(new RegExp())).toBe(false)
140 expect(isPlainObject(new Error())).toBe(false)
141 expect(isPlainObject(new Map())).toBe(false)
142 expect(isPlainObject(new Set())).toBe(false)
143 expect(isPlainObject(new WeakMap())).toBe(false)
144 expect(isPlainObject(new WeakSet())).toBe(false)
145 expect(isPlainObject(new Int8Array())).toBe(false)
146 expect(isPlainObject(new Uint8Array())).toBe(false)
147 expect(isPlainObject(new Uint8ClampedArray())).toBe(false)
148 expect(isPlainObject(new Int16Array())).toBe(false)
149 expect(isPlainObject(new Uint16Array())).toBe(false)
150 expect(isPlainObject(new Int32Array())).toBe(false)
151 expect(isPlainObject(new Uint32Array())).toBe(false)
152 expect(isPlainObject(new Float32Array())).toBe(false)
153 expect(isPlainObject(new Float64Array())).toBe(false)
154 expect(isPlainObject(new BigInt64Array())).toBe(false)
155 expect(isPlainObject(new BigUint64Array())).toBe(false)
156 expect(isPlainObject(new Promise(() => {}))).toBe(false)
157 expect(isPlainObject(new WeakRef({}))).toBe(false)
158 expect(isPlainObject(new FinalizationRegistry(() => {}))).toBe(false)
159 expect(isPlainObject(new ArrayBuffer())).toBe(false)
160 expect(isPlainObject(new SharedArrayBuffer())).toBe(false)
161 expect(isPlainObject(new DataView(new ArrayBuffer()))).toBe(false)
162 expect(isPlainObject({})).toBe(true)
163 expect(isPlainObject({ a: 1 })).toBe(true)
164 })
165
166 it('Verify isKillBehavior() behavior', () => {
167 expect(isKillBehavior(KillBehaviors.SOFT, KillBehaviors.SOFT)).toBe(true)
168 expect(isKillBehavior(KillBehaviors.SOFT, KillBehaviors.HARD)).toBe(false)
169 expect(isKillBehavior(KillBehaviors.HARD, KillBehaviors.HARD)).toBe(true)
170 expect(isKillBehavior(KillBehaviors.HARD, KillBehaviors.SOFT)).toBe(false)
171 expect(isKillBehavior(KillBehaviors.SOFT)).toBe(false)
172 expect(isKillBehavior(KillBehaviors.HARD)).toBe(false)
173 expect(isKillBehavior(KillBehaviors.HARD, null)).toBe(false)
174 expect(isKillBehavior(KillBehaviors.HARD, undefined)).toBe(false)
175 expect(isKillBehavior(KillBehaviors.SOFT, 'unknown')).toBe(false)
176 })
177
178 it('Verify isAsyncFunction() behavior', () => {
179 expect(isAsyncFunction(null)).toBe(false)
180 expect(isAsyncFunction(undefined)).toBe(false)
181 expect(isAsyncFunction(true)).toBe(false)
182 expect(isAsyncFunction(false)).toBe(false)
183 expect(isAsyncFunction(0)).toBe(false)
184 expect(isAsyncFunction('')).toBe(false)
185 expect(isAsyncFunction([])).toBe(false)
186 expect(isAsyncFunction(new Date())).toBe(false)
187 expect(isAsyncFunction(new RegExp())).toBe(false)
188 expect(isAsyncFunction(new Error())).toBe(false)
189 expect(isAsyncFunction(new Map())).toBe(false)
190 expect(isAsyncFunction(new Set())).toBe(false)
191 expect(isAsyncFunction(new WeakMap())).toBe(false)
192 expect(isAsyncFunction(new WeakSet())).toBe(false)
193 expect(isAsyncFunction(new Int8Array())).toBe(false)
194 expect(isAsyncFunction(new Uint8Array())).toBe(false)
195 expect(isAsyncFunction(new Uint8ClampedArray())).toBe(false)
196 expect(isAsyncFunction(new Int16Array())).toBe(false)
197 expect(isAsyncFunction(new Uint16Array())).toBe(false)
198 expect(isAsyncFunction(new Int32Array())).toBe(false)
199 expect(isAsyncFunction(new Uint32Array())).toBe(false)
200 expect(isAsyncFunction(new Float32Array())).toBe(false)
201 expect(isAsyncFunction(new Float64Array())).toBe(false)
202 expect(isAsyncFunction(new BigInt64Array())).toBe(false)
203 expect(isAsyncFunction(new BigUint64Array())).toBe(false)
204 expect(isAsyncFunction(new Promise(() => {}))).toBe(false)
205 expect(isAsyncFunction(new WeakRef({}))).toBe(false)
206 expect(isAsyncFunction(new FinalizationRegistry(() => {}))).toBe(false)
207 expect(isAsyncFunction(new ArrayBuffer())).toBe(false)
208 expect(isAsyncFunction(new SharedArrayBuffer())).toBe(false)
209 expect(isAsyncFunction(new DataView(new ArrayBuffer()))).toBe(false)
210 expect(isAsyncFunction({})).toBe(false)
211 expect(isAsyncFunction({ a: 1 })).toBe(false)
212 expect(isAsyncFunction(() => {})).toBe(false)
213 expect(isAsyncFunction(function () {})).toBe(false)
214 expect(isAsyncFunction(function named () {})).toBe(false)
215 expect(isAsyncFunction(async () => {})).toBe(true)
216 expect(isAsyncFunction(async function () {})).toBe(true)
217 expect(isAsyncFunction(async function named () {})).toBe(true)
218 })
219
220 it('Verify secureRandom() behavior', () => {
221 const randomNumber = secureRandom()
222 expect(typeof randomNumber === 'number').toBe(true)
223 expect(randomNumber).toBeGreaterThanOrEqual(0)
224 expect(randomNumber).toBeLessThan(1)
225 })
226
227 it('Verify min() behavior', () => {
228 expect(min()).toBe(Infinity)
229 expect(min(1, 2)).toBe(1)
230 expect(min(2, 1)).toBe(1)
231 expect(min(1, 1)).toBe(1)
232 })
233
234 it('Verify max() behavior', () => {
235 expect(max()).toBe(-Infinity)
236 expect(max(1, 2)).toBe(2)
237 expect(max(2, 1)).toBe(2)
238 expect(max(1, 1)).toBe(1)
239 })
240 })