From: Jérôme Benoit Date: Fri, 20 Mar 2026 20:39:36 +0000 (+0100) Subject: fix(ocpp2.0): add proper response handlers for certificate commands + handler coverag... X-Git-Url: https://git.piment-noir.org/?a=commitdiff_plain;h=273f53994d1c816a3760db3e08dc17c4995c9363;p=e-mobility-charging-stations-simulator.git fix(ocpp2.0): add proper response handlers for certificate commands + handler coverage tests Replace emptyResponseHandler with proper logging handlers for Get15118EVCertificate, GetCertificateStatus, and SignCertificate responses. Add handler registration coverage tests for both OCPP 1.6 and 2.0: every RequestCommand must have a response handler, every IncomingRequestCommand must have an incoming request handler. --- diff --git a/src/charging-station/ocpp/2.0/OCPP20ResponseService.ts b/src/charging-station/ocpp/2.0/OCPP20ResponseService.ts index c88823e3..75a737ad 100644 --- a/src/charging-station/ocpp/2.0/OCPP20ResponseService.ts +++ b/src/charging-station/ocpp/2.0/OCPP20ResponseService.ts @@ -6,8 +6,11 @@ import { ConnectorStatusEnum, type JsonType, OCPP20AuthorizationStatusEnumType, + type OCPP20AuthorizeResponse, type OCPP20BootNotificationResponse, type OCPP20FirmwareStatusNotificationResponse, + type OCPP20Get15118EVCertificateResponse, + type OCPP20GetCertificateStatusResponse, type OCPP20HeartbeatResponse, type OCPP20IncomingRequestCommand, type OCPP20LogStatusNotificationResponse, @@ -17,6 +20,7 @@ import { OCPP20OptionalVariableName, OCPP20RequestCommand, type OCPP20SecurityEventNotificationResponse, + type OCPP20SignCertificateResponse, type OCPP20StatusNotificationResponse, OCPP20TransactionEventEnumType, type OCPP20TransactionEventRequest, @@ -93,6 +97,7 @@ export class OCPP20ResponseService extends OCPPResponseService { public constructor () { super(OCPPVersion.VERSION_201) this.responseHandlers = new Map([ + [OCPP20RequestCommand.AUTHORIZE, this.handleResponseAuthorize.bind(this) as ResponseHandler], [ OCPP20RequestCommand.BOOT_NOTIFICATION, this.handleResponseBootNotification.bind(this) as ResponseHandler, @@ -101,6 +106,14 @@ export class OCPP20ResponseService extends OCPPResponseService { OCPP20RequestCommand.FIRMWARE_STATUS_NOTIFICATION, this.handleResponseFirmwareStatusNotification.bind(this) as ResponseHandler, ], + [ + OCPP20RequestCommand.GET_15118_EV_CERTIFICATE, + this.handleResponseGet15118EVCertificate.bind(this) as ResponseHandler, + ], + [ + OCPP20RequestCommand.GET_CERTIFICATE_STATUS, + this.handleResponseGetCertificateStatus.bind(this) as ResponseHandler, + ], [OCPP20RequestCommand.HEARTBEAT, this.handleResponseHeartbeat.bind(this) as ResponseHandler], [ OCPP20RequestCommand.LOG_STATUS_NOTIFICATION, @@ -122,6 +135,10 @@ export class OCPP20ResponseService extends OCPPResponseService { OCPP20RequestCommand.SECURITY_EVENT_NOTIFICATION, this.handleResponseSecurityEventNotification.bind(this) as ResponseHandler, ], + [ + OCPP20RequestCommand.SIGN_CERTIFICATE, + this.handleResponseSignCertificate.bind(this) as ResponseHandler, + ], [ OCPP20RequestCommand.STATUS_NOTIFICATION, this.handleResponseStatusNotification.bind(this) as ResponseHandler, @@ -154,6 +171,15 @@ export class OCPP20ResponseService extends OCPPResponseService { ) } + private handleResponseAuthorize ( + chargingStation: ChargingStation, + payload: OCPP20AuthorizeResponse + ): void { + logger.debug( + `${chargingStation.logPrefix()} ${moduleName}.handleResponseAuthorize: Authorize response received, status: ${payload.idTokenInfo.status}` + ) + } + private handleResponseBootNotification ( chargingStation: ChargingStation, payload: OCPP20BootNotificationResponse @@ -213,6 +239,24 @@ export class OCPP20ResponseService extends OCPPResponseService { ) } + private handleResponseGet15118EVCertificate ( + chargingStation: ChargingStation, + payload: OCPP20Get15118EVCertificateResponse + ): void { + logger.debug( + `${chargingStation.logPrefix()} ${moduleName}.handleResponseGet15118EVCertificate: Get15118EVCertificate response received, status: ${payload.status}` + ) + } + + private handleResponseGetCertificateStatus ( + chargingStation: ChargingStation, + payload: OCPP20GetCertificateStatusResponse + ): void { + logger.debug( + `${chargingStation.logPrefix()} ${moduleName}.handleResponseGetCertificateStatus: GetCertificateStatus response received, status: ${payload.status}` + ) + } + private handleResponseHeartbeat ( chargingStation: ChargingStation, payload: OCPP20HeartbeatResponse @@ -267,6 +311,15 @@ export class OCPP20ResponseService extends OCPPResponseService { ) } + private handleResponseSignCertificate ( + chargingStation: ChargingStation, + payload: OCPP20SignCertificateResponse + ): void { + logger.debug( + `${chargingStation.logPrefix()} ${moduleName}.handleResponseSignCertificate: SignCertificate response received, status: ${payload.status}` + ) + } + private handleResponseStatusNotification ( chargingStation: ChargingStation, payload: OCPP20StatusNotificationResponse diff --git a/tests/charging-station/ocpp/1.6/OCPP16SchemaValidation.test.ts b/tests/charging-station/ocpp/1.6/OCPP16SchemaValidation.test.ts index 93aa3af7..1bbd1f74 100644 --- a/tests/charging-station/ocpp/1.6/OCPP16SchemaValidation.test.ts +++ b/tests/charging-station/ocpp/1.6/OCPP16SchemaValidation.test.ts @@ -14,6 +14,8 @@ import { join } from 'node:path' import { afterEach, describe, it } from 'node:test' import { fileURLToPath } from 'node:url' +import { OCPP16IncomingRequestService } from '../../../../src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.js' +import { OCPP16ResponseService } from '../../../../src/charging-station/ocpp/1.6/OCPP16ResponseService.js' import { OCPP16ServiceUtils } from '../../../../src/charging-station/ocpp/1.6/OCPP16ServiceUtils.js' import { OCPP16IncomingRequestCommand, OCPP16RequestCommand } from '../../../../src/types/index.js' import { standardCleanup } from '../../../helpers/TestLifecycleHelpers.js' @@ -324,5 +326,26 @@ await describe('OCPP16SchemaValidation', async () => { ) } }) + + await it('should register a response handler for every OCPP16RequestCommand', () => { + const responseService = new OCPP16ResponseService() + const handlers = (responseService as unknown as { responseHandlers: Map }) + .responseHandlers + const registered = new Set(handlers.keys()) + for (const command of Object.values(OCPP16RequestCommand)) { + assert.ok(registered.has(command), `missing response handler for: ${command}`) + } + }) + + await it('should register an incoming request handler for every OCPP16IncomingRequestCommand', () => { + const incomingService = new OCPP16IncomingRequestService() + const handlers = ( + incomingService as unknown as { incomingRequestHandlers: Map } + ).incomingRequestHandlers + const registered = new Set(handlers.keys()) + for (const command of Object.values(OCPP16IncomingRequestCommand)) { + assert.ok(registered.has(command), `missing incoming request handler for: ${command}`) + } + }) }) }) diff --git a/tests/charging-station/ocpp/2.0/OCPP20SchemaValidation.test.ts b/tests/charging-station/ocpp/2.0/OCPP20SchemaValidation.test.ts index 59fa9adc..f0ca0785 100644 --- a/tests/charging-station/ocpp/2.0/OCPP20SchemaValidation.test.ts +++ b/tests/charging-station/ocpp/2.0/OCPP20SchemaValidation.test.ts @@ -17,6 +17,8 @@ import { join } from 'node:path' import { afterEach, describe, it } from 'node:test' import { fileURLToPath } from 'node:url' +import { OCPP20IncomingRequestService } from '../../../../src/charging-station/ocpp/2.0/OCPP20IncomingRequestService.js' +import { OCPP20ResponseService } from '../../../../src/charging-station/ocpp/2.0/OCPP20ResponseService.js' import { OCPP20ServiceUtils } from '../../../../src/charging-station/ocpp/2.0/OCPP20ServiceUtils.js' import { OCPP20IncomingRequestCommand, OCPP20RequestCommand } from '../../../../src/types/index.js' import { standardCleanup } from '../../../helpers/TestLifecycleHelpers.js' @@ -254,5 +256,26 @@ await describe('OCPP 2.0 schema validation — negative tests', async () => { ) } }) + + await it('should register a response handler for every OCPP20RequestCommand', () => { + const responseService = new OCPP20ResponseService() + const handlers = (responseService as unknown as { responseHandlers: Map }) + .responseHandlers + const registered = new Set(handlers.keys()) + for (const command of Object.values(OCPP20RequestCommand)) { + assert.ok(registered.has(command), `missing response handler for: ${command}`) + } + }) + + await it('should register an incoming request handler for every OCPP20IncomingRequestCommand', () => { + const incomingService = new OCPP20IncomingRequestService() + const handlers = ( + incomingService as unknown as { incomingRequestHandlers: Map } + ).incomingRequestHandlers + const registered = new Set(handlers.keys()) + for (const command of Object.values(OCPP20IncomingRequestCommand)) { + assert.ok(registered.has(command), `missing incoming request handler for: ${command}`) + } + }) }) })