refactor: use native node random integer generator
authorJérôme Benoit <jerome.benoit@sap.com>
Mon, 18 Mar 2024 14:19:53 +0000 (15:19 +0100)
committerJérôme Benoit <jerome.benoit@sap.com>
Mon, 18 Mar 2024 14:19:53 +0000 (15:19 +0100)
Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
src/charging-station/AutomaticTransactionGenerator.ts
src/charging-station/ChargingStation.ts
src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.ts
src/charging-station/ocpp/OCPPServiceUtils.ts
src/utils/Constants.ts
src/utils/Utils.ts
src/utils/index.ts
tests/utils/Utils.test.ts

index 40b7c7818a7731c3ea56dac4d81986a689ddc6b9..a6143a8c0a3bb7de88d668a15bf0ac28cf5b323b 100644 (file)
@@ -1,5 +1,7 @@
 // Partial Copyright Jerome Benoit. 2021-2024. All Rights Reserved.
 
+import { randomInt } from 'node:crypto'
+
 import { hoursToMilliseconds, secondsToMilliseconds } from 'date-fns'
 
 import { BaseError } from '../exception/index.js'
@@ -18,7 +20,6 @@ import {
   Constants,
   convertToDate,
   formatDurationMilliSeconds,
-  getRandomInteger,
   isValidDate,
   logger,
   logPrefix,
@@ -199,11 +200,11 @@ export class AutomaticTransactionGenerator {
         break
       }
       const wait = secondsToMilliseconds(
-        getRandomInteger(
+        randomInt(
           this.chargingStation.getAutomaticTransactionGeneratorConfiguration()
-            ?.maxDelayBetweenTwoTransactions,
+            ?.minDelayBetweenTwoTransactions,
           this.chargingStation.getAutomaticTransactionGeneratorConfiguration()
-            ?.minDelayBetweenTwoTransactions
+            ?.maxDelayBetweenTwoTransactions
         )
       )
       logger.info(`${this.logPrefix(connectorId)} waiting for ${formatDurationMilliSeconds(wait)}`)
@@ -221,9 +222,9 @@ export class AutomaticTransactionGenerator {
         if (startResponse?.idTagInfo.status === AuthorizationStatus.ACCEPTED) {
           // Wait until end of transaction
           const waitTrxEnd = secondsToMilliseconds(
-            getRandomInteger(
-              this.chargingStation.getAutomaticTransactionGeneratorConfiguration()?.maxDuration,
-              this.chargingStation.getAutomaticTransactionGeneratorConfiguration()?.minDuration
+            randomInt(
+              this.chargingStation.getAutomaticTransactionGeneratorConfiguration()?.minDuration,
+              this.chargingStation.getAutomaticTransactionGeneratorConfiguration()?.maxDuration
             )
           )
           logger.info(
index 9bf299aa750b0bcf7ac61641c7f6ef826655d80d..0a1ed4edf158e2b7519fb869eb17f03837c0c071 100644 (file)
@@ -1,6 +1,6 @@
 // Partial Copyright Jerome Benoit. 2021-2024. All Rights Reserved.
 
-import { createHash } from 'node:crypto'
+import { createHash, randomInt } from 'node:crypto'
 import { EventEmitter } from 'node:events'
 import { existsSync, type FSWatcher, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
 import { dirname, join } from 'node:path'
@@ -88,7 +88,6 @@ import {
   exponentialDelay,
   formatDurationMilliSeconds,
   formatDurationSeconds,
-  getRandomInteger,
   getWebSocketCloseEventStatusString,
   handleFileException,
   isNotEmptyArray,
@@ -1554,7 +1553,7 @@ export class ChargingStation extends EventEmitter {
             }
             const templateConnectorId =
               connectorId > 0 && stationTemplate.randomConnectors === true
-                ? getRandomInteger(templateMaxAvailableConnectors, 1)
+                ? randomInt(1, templateMaxAvailableConnectors)
                 : connectorId
             const connectorStatus = stationTemplate.Connectors[templateConnectorId]
             checkStationInfoConnectorStatus(
index 0418266499bcc5b787a72e1ef70d29c05f880812..ea7a89e9e794ece28afae25a6a5c91ef91e36f20 100644 (file)
@@ -1,5 +1,6 @@
 // Partial Copyright Jerome Benoit. 2021-2024. All Rights Reserved.
 
+import { randomInt } from 'node:crypto'
 import { createWriteStream, readdirSync } from 'node:fs'
 import { dirname, extname, join, resolve } from 'node:path'
 import { fileURLToPath, URL } from 'node:url'
@@ -104,7 +105,6 @@ import {
   convertToDate,
   convertToInt,
   formatDurationMilliSeconds,
-  getRandomInteger,
   isAsyncFunction,
   isNotEmptyArray,
   isNotEmptyString,
@@ -1346,7 +1346,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
       chargingStation.stationInfo?.firmwareUpgrade?.failureStatus ===
       OCPP16FirmwareStatus.DownloadFailed
     ) {
-      await sleep(secondsToMilliseconds(getRandomInteger(maxDelay, minDelay)))
+      await sleep(secondsToMilliseconds(randomInt(minDelay, maxDelay)))
       await chargingStation.ocppRequestService.requestHandler<
       OCPP16FirmwareStatusNotificationRequest,
       OCPP16FirmwareStatusNotificationResponse
@@ -1357,7 +1357,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
         chargingStation.stationInfo.firmwareUpgrade.failureStatus
       return
     }
-    await sleep(secondsToMilliseconds(getRandomInteger(maxDelay, minDelay)))
+    await sleep(secondsToMilliseconds(randomInt(minDelay, maxDelay)))
     await chargingStation.ocppRequestService.requestHandler<
     OCPP16FirmwareStatusNotificationRequest,
     OCPP16FirmwareStatusNotificationResponse
@@ -1413,8 +1413,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
         transactionsStarted = false
       }
     } while (transactionsStarted)
-    !wasTransactionsStarted &&
-      (await sleep(secondsToMilliseconds(getRandomInteger(maxDelay, minDelay))))
+    !wasTransactionsStarted && (await sleep(secondsToMilliseconds(randomInt(minDelay, maxDelay))))
     if (!checkChargingStation(chargingStation, chargingStation.logPrefix())) {
       return
     }
@@ -1430,7 +1429,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
       chargingStation.stationInfo?.firmwareUpgrade?.failureStatus ===
       OCPP16FirmwareStatus.InstallationFailed
     ) {
-      await sleep(secondsToMilliseconds(getRandomInteger(maxDelay, minDelay)))
+      await sleep(secondsToMilliseconds(randomInt(minDelay, maxDelay)))
       await chargingStation.ocppRequestService.requestHandler<
       OCPP16FirmwareStatusNotificationRequest,
       OCPP16FirmwareStatusNotificationResponse
@@ -1442,7 +1441,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
       return
     }
     if (chargingStation.stationInfo?.firmwareUpgrade?.reset === true) {
-      await sleep(secondsToMilliseconds(getRandomInteger(maxDelay, minDelay)))
+      await sleep(secondsToMilliseconds(randomInt(minDelay, maxDelay)))
       await chargingStation.reset(OCPP16StopTransactionReason.REBOOT)
     }
   }
index 38f218ee35b46850154516c1c53572d4724f7a4d..8a42bf67a7b05f361374a1d04bf996ab5d6b304f 100644 (file)
@@ -1,3 +1,4 @@
+import { randomInt } from 'node:crypto'
 import { readFileSync } from 'node:fs'
 import { dirname, join } from 'node:path'
 import { fileURLToPath } from 'node:url'
@@ -53,7 +54,6 @@ import {
   DCElectricUtils,
   getRandomFloatFluctuatedRounded,
   getRandomFloatRounded,
-  getRandomInteger,
   handleFileException,
   isNotEmptyArray,
   isNotEmptyString,
@@ -284,7 +284,7 @@ export const buildMeterValue = (
             parseInt(socSampledValueTemplate.value),
             socSampledValueTemplate.fluctuationPercent ?? Constants.DEFAULT_FLUCTUATION_PERCENT
           )
-          : getRandomInteger(socMaximumValue, socMinimumValue)
+          : randomInt(socMinimumValue, socMaximumValue)
         meterValue.sampledValue.push(
           buildSampledValue(socSampledValueTemplate, socSampledValueTemplateValue)
         )
index ea0ff8fca7dece1e9f88092664e698006724ae7a..a5e46f60673e3078afd9386c4b3995c0800477b5 100644 (file)
@@ -85,7 +85,7 @@ export class Constants {
     | RequestCommand
     | IncomingRequestCommand
 
-  static readonly MAX_RANDOM_INTEGER = 281474976710654
+  static readonly MAX_RANDOM_INTEGER = 281474976710655
 
   static readonly STOP_CHARGING_STATIONS_TIMEOUT = 60000 // Ms
 
index bc9a8f436a8c1e7c8b60457f817e9467a6c96933..7ff24ac8a423b7ece4ab779dd87c3972f9dcf2d4 100644 (file)
@@ -1,4 +1,4 @@
-import { getRandomValues, randomBytes, randomInt, randomUUID } from 'node:crypto'
+import { getRandomValues, randomBytes, randomUUID } from 'node:crypto'
 import { env, nextTick } from 'node:process'
 
 import {
@@ -19,7 +19,6 @@ import {
   type TimestampedData,
   WebSocketCloseEventStatusString
 } from '../types/index.js'
-import { Constants } from './Constants.js'
 
 export const logPrefix = (prefixString = ''): string => {
   return `${new Date().toLocaleString()}${prefixString}`
@@ -159,15 +158,6 @@ export const getRandomFloat = (max = Number.MAX_VALUE, min = 0): number => {
   return (randomBytes(4).readUInt32LE() / 0xffffffff) * (max - min) + min
 }
 
-export const getRandomInteger = (max = Constants.MAX_RANDOM_INTEGER, min = 0): number => {
-  max = Math.floor(max)
-  if (min !== 0) {
-    min = Math.ceil(min)
-    return Math.floor(randomInt(min, max + 1))
-  }
-  return Math.floor(randomInt(max + 1))
-}
-
 /**
  * Rounds the given number to the given scale.
  * The rounding is done using the "round half away from zero" method.
index 549b83470e47073f845f821f28b7812daadd90fa..a09ae0a53719337c6511df19882c74e842e5d782 100644 (file)
@@ -41,7 +41,6 @@ export {
   generateUUID,
   getRandomFloatFluctuatedRounded,
   getRandomFloatRounded,
-  getRandomInteger,
   getWebSocketCloseEventStatusString,
   isArraySorted,
   isAsyncFunction,
index a86765293d72e64371b9da02cbf8308ee2c5bad1..5672b032187e336ba48e6a85c73a0d5b5f981a02 100644 (file)
@@ -1,3 +1,4 @@
+import { randomInt } from 'node:crypto'
 import { version } from 'node:process'
 import { describe, it } from 'node:test'
 
@@ -17,7 +18,6 @@ import {
   formatDurationSeconds,
   generateUUID,
   getRandomFloat,
-  getRandomInteger,
   hasOwnProp,
   isArraySorted,
   isAsyncFunction,
@@ -95,7 +95,7 @@ await describe('Utils test suite', async () => {
     expect(convertToInt(undefined)).toBe(0)
     expect(convertToInt(null)).toBe(0)
     expect(convertToInt(0)).toBe(0)
-    const randomInteger = getRandomInteger()
+    const randomInteger = randomInt(Constants.MAX_RANDOM_INTEGER)
     expect(convertToInt(randomInteger)).toEqual(randomInteger)
     expect(convertToInt('-1')).toBe(-1)
     expect(convertToInt('1')).toBe(1)
@@ -157,36 +157,6 @@ await describe('Utils test suite', async () => {
     expect(random).toBeLessThan(1)
   })
 
-  await it('Verify getRandomInteger()', () => {
-    let randomInteger = getRandomInteger()
-    expect(Number.isSafeInteger(randomInteger)).toBe(true)
-    expect(randomInteger).toBeGreaterThanOrEqual(0)
-    expect(randomInteger).toBeLessThanOrEqual(Constants.MAX_RANDOM_INTEGER)
-    expect(randomInteger).not.toEqual(getRandomInteger())
-    randomInteger = getRandomInteger(0, -Constants.MAX_RANDOM_INTEGER)
-    expect(randomInteger).toBeGreaterThanOrEqual(-Constants.MAX_RANDOM_INTEGER)
-    expect(randomInteger).toBeLessThanOrEqual(0)
-    expect(() => getRandomInteger(0, 1)).toThrow(
-      'The value of "max" is out of range. It must be greater than the value of "min" (1). Received 1'
-    )
-    expect(() => getRandomInteger(-1)).toThrow(
-      'The value of "max" is out of range. It must be greater than the value of "min" (0). Received 0'
-    )
-    expect(() => getRandomInteger(Constants.MAX_RANDOM_INTEGER + 1)).toThrow(
-      `The value of "max" is out of range. It must be <= ${
-        Constants.MAX_RANDOM_INTEGER + 1
-      }. Received 281_474_976_710_656`
-    )
-    randomInteger = getRandomInteger(2, 1)
-    expect(randomInteger).toBeGreaterThanOrEqual(1)
-    expect(randomInteger).toBeLessThanOrEqual(2)
-    const maximum = 2.2
-    const minimum = 1.1
-    randomInteger = getRandomInteger(maximum, minimum)
-    expect(randomInteger).toBeLessThanOrEqual(Math.floor(maximum))
-    expect(randomInteger).toBeGreaterThanOrEqual(Math.ceil(minimum))
-  })
-
   await it('Verify roundTo()', () => {
     expect(roundTo(0, 2)).toBe(0)
     expect(roundTo(0.5, 0)).toBe(1)