]> Piment Noir Git Repositories - e-mobility-charging-stations-simulator.git/commitdiff
test(ocpp): add OCPPServiceUtils authorization wrapper tests
authorJérôme Benoit <jerome.benoit@sap.com>
Tue, 3 Mar 2026 19:50:04 +0000 (20:50 +0100)
committerJérôme Benoit <jerome.benoit@sap.com>
Tue, 3 Mar 2026 19:50:04 +0000 (20:50 +0100)
Add tests for isIdTagAuthorized and isIdTagAuthorizedUnified functions
covering local auth list, remote authorization, OCPP 2.0 unified auth
dispatch, and error fallback paths.

tests/charging-station/ocpp/OCPPServiceUtils-authorization.test.ts [new file with mode: 0644]

diff --git a/tests/charging-station/ocpp/OCPPServiceUtils-authorization.test.ts b/tests/charging-station/ocpp/OCPPServiceUtils-authorization.test.ts
new file mode 100644 (file)
index 0000000..7c9e9ed
--- /dev/null
@@ -0,0 +1,161 @@
+/**
+ * @file Tests for OCPPServiceUtils authorization wrapper functions
+ * @description Verifies isIdTagAuthorized and isIdTagAuthorizedUnified functions
+ *
+ * Covers:
+ * - isIdTagAuthorized — OCPP 1.6 legacy authorization (local auth list + remote authorization)
+ * - isIdTagAuthorizedUnified — OCPP 2.0+ unified auth system with fallback
+ *
+ * Note: The unified auth subsystem (OCPPAuthService, strategies, adapters) has its own
+ * dedicated test suite in tests/charging-station/ocpp/auth/. These tests verify the
+ * wrapper/dispatch layer only — no overlap.
+ */
+
+import { expect } from '@std/expect'
+import { afterEach, describe, it } from 'node:test'
+
+import { getIdTagsFile } from '../../../src/charging-station/Helpers.js'
+import {
+  isIdTagAuthorized,
+  isIdTagAuthorizedUnified,
+} from '../../../src/charging-station/ocpp/OCPPServiceUtils.js'
+import { AuthorizationStatus, OCPPVersion } from '../../../src/types/index.js'
+import { standardCleanup } from '../../helpers/TestLifecycleHelpers.js'
+import { createMockChargingStation } from '../ChargingStationTestUtils.js'
+
+interface StationLocalAuthOverrides {
+  getLocalAuthListEnabled: () => boolean
+  hasIdTags: () => boolean
+}
+
+/**
+ *
+ * @param station
+ * @param mocks
+ * @param tags
+ */
+function setupLocalAuth (
+  station: ReturnType<typeof createMockChargingStation>['station'],
+  mocks: ReturnType<typeof createMockChargingStation>['mocks'],
+  tags: string[]
+): void {
+  const stationOverrides = station as unknown as StationLocalAuthOverrides
+  stationOverrides.getLocalAuthListEnabled = () => true
+  stationOverrides.hasIdTags = () => true
+  const stationInfo = station.stationInfo
+  if (stationInfo != null) {
+    const resolvedPath = getIdTagsFile(stationInfo)
+    if (resolvedPath != null) {
+      mocks.idTagsCache.setIdTags(resolvedPath, tags)
+    }
+  }
+}
+
+await describe('OCPPServiceUtils — authorization wrappers', async () => {
+  afterEach(() => {
+    standardCleanup()
+  })
+
+  await describe('isIdTagAuthorized (OCPP 1.6 legacy)', async () => {
+    await it('should return false when local and remote auth are both disabled', async () => {
+      const { station } = createMockChargingStation({
+        stationInfo: { remoteAuthorization: false },
+      })
+      const result = await isIdTagAuthorized(station, 1, 'TAG-001')
+      expect(result).toBe(false)
+    })
+
+    await it('should authorize locally when tag is in local auth list', async () => {
+      const { mocks, station } = createMockChargingStation({
+        stationInfo: { idTagsFile: 'test-idtags.json' },
+      })
+      setupLocalAuth(station, mocks, ['TAG-001', 'TAG-002'])
+
+      const result = await isIdTagAuthorized(station, 1, 'TAG-001')
+      expect(result).toBe(true)
+    })
+
+    await it('should set localAuthorizeIdTag and idTagLocalAuthorized on local auth success', async () => {
+      const { mocks, station } = createMockChargingStation({
+        stationInfo: { idTagsFile: 'test-idtags.json' },
+      })
+      setupLocalAuth(station, mocks, ['TAG-001'])
+
+      await isIdTagAuthorized(station, 1, 'TAG-001')
+
+      const connectorStatus = station.getConnectorStatus(1)
+      expect(connectorStatus?.localAuthorizeIdTag).toBe('TAG-001')
+      expect(connectorStatus?.idTagLocalAuthorized).toBe(true)
+    })
+
+    await it('should authorize remotely when local auth is disabled and remote returns accepted', async () => {
+      const { station } = createMockChargingStation({
+        ocppRequestService: {
+          requestHandler: () =>
+            Promise.resolve({
+              idTagInfo: { status: AuthorizationStatus.ACCEPTED },
+            }),
+        },
+        stationInfo: { remoteAuthorization: true },
+      })
+
+      const result = await isIdTagAuthorized(station, 1, 'TAG-001')
+      expect(result).toBe(true)
+    })
+
+    await it('should return false when remote authorization rejects the tag', async () => {
+      const { station } = createMockChargingStation({
+        ocppRequestService: {
+          requestHandler: () =>
+            Promise.resolve({
+              idTagInfo: { status: AuthorizationStatus.BLOCKED },
+            }),
+        },
+        stationInfo: { remoteAuthorization: true },
+      })
+
+      const result = await isIdTagAuthorized(station, 1, 'TAG-999')
+      expect(result).toBe(false)
+    })
+
+    await it('should return false for non-existent connector even with local auth enabled', async () => {
+      const { mocks, station } = createMockChargingStation({
+        stationInfo: { idTagsFile: 'test-idtags.json', remoteAuthorization: false },
+      })
+      setupLocalAuth(station, mocks, ['TAG-001'])
+
+      const result = await isIdTagAuthorized(station, 99, 'TAG-001')
+      expect(result).toBe(false)
+    })
+  })
+
+  await describe('isIdTagAuthorizedUnified', async () => {
+    await it('should fall back to legacy auth for OCPP 1.6 station', async () => {
+      const { mocks, station } = createMockChargingStation({
+        stationInfo: { idTagsFile: 'test-idtags.json' },
+      })
+      setupLocalAuth(station, mocks, ['TAG-001'])
+
+      const result = await isIdTagAuthorizedUnified(station, 1, 'TAG-001')
+      expect(result).toBe(true)
+    })
+
+    await it('should return false on auth error for OCPP 2.0 station', async () => {
+      const { station } = createMockChargingStation({
+        ocppVersion: OCPPVersion.VERSION_20,
+      })
+
+      const result = await isIdTagAuthorizedUnified(station, 1, 'TAG-001')
+      expect(result).toBe(false)
+    })
+
+    await it('should attempt unified auth service for OCPP 2.0.1 station', async () => {
+      const { station } = createMockChargingStation({
+        ocppVersion: OCPPVersion.VERSION_201,
+      })
+
+      const result = await isIdTagAuthorizedUnified(station, 1, 'TAG-001')
+      expect(result).toBe(false)
+    })
+  })
+})