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