]> Piment Noir Git Repositories - e-mobility-charging-stations-simulator.git/commitdiff
refactor(auth): replace adapter Map with single adapter per station
authorJérôme Benoit <jerome.benoit@sap.com>
Sat, 21 Mar 2026 18:01:48 +0000 (19:01 +0100)
committerJérôme Benoit <jerome.benoit@sap.com>
Sat, 21 Mar 2026 18:01:48 +0000 (19:01 +0100)
Each charging station has exactly one OCPP version, making the
Map<OCPPVersion, OCPPAuthAdapter> unnecessary indirection. Simplify
to a single adapter field across the auth module.

- AuthComponentFactory: createAdapter() returns single OCPPAuthAdapter
- RemoteAuthStrategy: setAdapter()/clearAdapter() replace map ops
- CertificateAuthStrategy: readonly adapter field, no map
- OCPPAuthServiceImpl: single adapter, initializeAdapter() singular
- Tests updated to match new single-adapter API

src/charging-station/ocpp/auth/factories/AuthComponentFactory.ts
src/charging-station/ocpp/auth/services/OCPPAuthServiceImpl.ts
src/charging-station/ocpp/auth/strategies/CertificateAuthStrategy.ts
src/charging-station/ocpp/auth/strategies/RemoteAuthStrategy.ts
tests/charging-station/ocpp/auth/factories/AuthComponentFactory.test.ts
tests/charging-station/ocpp/auth/strategies/CertificateAuthStrategy.test.ts
tests/charging-station/ocpp/auth/strategies/RemoteAuthStrategy.test.ts

index d70d3685f7e979c5fb3cc0a7e69bd43cdde5c657..8bb4dcebdff357f8055f3dfca05a5904db8b69b5 100644 (file)
@@ -1,10 +1,9 @@
 import type { ChargingStation } from '../../../ChargingStation.js'
-import type { OCPP16AuthAdapter } from '../adapters/OCPP16AuthAdapter.js'
-import type { OCPP20AuthAdapter } from '../adapters/OCPP20AuthAdapter.js'
 import type {
   AuthCache,
   AuthStrategy,
   LocalAuthListManager,
+  OCPPAuthAdapter,
 } from '../interfaces/OCPPAuthService.js'
 import type { AuthConfiguration } from '../types/AuthTypes.js'
 
@@ -32,15 +31,12 @@ import { AuthConfigValidator } from '../utils/ConfigValidator.js'
 // eslint-disable-next-line @typescript-eslint/no-extraneous-class
 export class AuthComponentFactory {
   /**
-   * Create OCPP adapters based on charging station version
+   * Create OCPP adapter based on charging station version
    * @param chargingStation - Charging station instance used to determine OCPP version
-   * @returns Object containing version-specific adapter (OCPP 1.6 or 2.0.x)
+   * @returns Single version-specific adapter (OCPP 1.6 or 2.0.x)
    * @throws {Error} When OCPP version is not found or unsupported
    */
-  static async createAdapters (chargingStation: ChargingStation): Promise<{
-    ocpp16Adapter?: OCPP16AuthAdapter
-    ocpp20Adapter?: OCPP20AuthAdapter
-  }> {
+  static async createAdapter (chargingStation: ChargingStation): Promise<OCPPAuthAdapter> {
     const ocppVersion = chargingStation.stationInfo?.ocppVersion
 
     if (!ocppVersion) {
@@ -51,13 +47,13 @@ export class AuthComponentFactory {
       case OCPPVersion.VERSION_16: {
         // Use static import - circular dependency is acceptable here
         const { OCPP16AuthAdapter } = await import('../adapters/OCPP16AuthAdapter.js')
-        return { ocpp16Adapter: new OCPP16AuthAdapter(chargingStation) }
+        return new OCPP16AuthAdapter(chargingStation)
       }
       case OCPPVersion.VERSION_20:
       case OCPPVersion.VERSION_201: {
         // Use static import - circular dependency is acceptable here
         const { OCPP20AuthAdapter } = await import('../adapters/OCPP20AuthAdapter.js')
-        return { ocpp20Adapter: new OCPP20AuthAdapter(chargingStation) }
+        return new OCPP20AuthAdapter(chargingStation)
       }
       default:
         throw new OCPPError(
@@ -82,28 +78,18 @@ export class AuthComponentFactory {
   /**
    * Create certificate authentication strategy
    * @param chargingStation - Charging station instance for certificate validation
-   * @param adapters - Container holding OCPP version-specific adapters
-   * @param adapters.ocpp16Adapter - Optional OCPP 1.6 protocol adapter
-   * @param adapters.ocpp20Adapter - Optional OCPP 2.0.x protocol adapter
+   * @param adapter - OCPP version-specific adapter
    * @param config - Authentication configuration with certificate settings
    * @returns Initialized certificate-based authentication strategy
    */
   static async createCertificateStrategy (
     chargingStation: ChargingStation,
-    adapters: { ocpp16Adapter?: OCPP16AuthAdapter; ocpp20Adapter?: OCPP20AuthAdapter },
+    adapter: OCPPAuthAdapter,
     config: AuthConfiguration
   ): Promise<AuthStrategy> {
     // Use static import - circular dependency is acceptable here
     const { CertificateAuthStrategy } = await import('../strategies/CertificateAuthStrategy.js')
-    const adapterMap = new Map<OCPPVersion, OCPP16AuthAdapter | OCPP20AuthAdapter>()
-    if (adapters.ocpp16Adapter) {
-      adapterMap.set(OCPPVersion.VERSION_16, adapters.ocpp16Adapter)
-    }
-    if (adapters.ocpp20Adapter) {
-      adapterMap.set(OCPPVersion.VERSION_20, adapters.ocpp20Adapter)
-      adapterMap.set(OCPPVersion.VERSION_201, adapters.ocpp20Adapter)
-    }
-    const strategy = new CertificateAuthStrategy(chargingStation, adapterMap)
+    const strategy = new CertificateAuthStrategy(chargingStation, adapter)
     strategy.initialize(config)
     return strategy
   }
@@ -157,16 +143,14 @@ export class AuthComponentFactory {
 
   /**
    * Create remote authentication strategy
-   * @param adapters - Container holding OCPP version-specific adapters
-   * @param adapters.ocpp16Adapter - Optional OCPP 1.6 protocol adapter
-   * @param adapters.ocpp20Adapter - Optional OCPP 2.0.x protocol adapter
+   * @param adapter - OCPP version-specific adapter
    * @param cache - Authorization cache for storing remote auth results
    * @param config - Authentication configuration controlling remote auth behavior
    * @param localAuthListManager - Optional local auth list manager for R17 cache exclusion
    * @returns Remote strategy instance or undefined if remote auth disabled
    */
   static async createRemoteStrategy (
-    adapters: { ocpp16Adapter?: OCPP16AuthAdapter; ocpp20Adapter?: OCPP20AuthAdapter },
+    adapter: OCPPAuthAdapter,
     cache: AuthCache | undefined,
     config: AuthConfiguration,
     localAuthListManager?: LocalAuthListManager
@@ -177,15 +161,7 @@ export class AuthComponentFactory {
 
     // Use static import - circular dependency is acceptable here
     const { RemoteAuthStrategy } = await import('../strategies/RemoteAuthStrategy.js')
-    const adapterMap = new Map<OCPPVersion, OCPP16AuthAdapter | OCPP20AuthAdapter>()
-    if (adapters.ocpp16Adapter) {
-      adapterMap.set(OCPPVersion.VERSION_16, adapters.ocpp16Adapter)
-    }
-    if (adapters.ocpp20Adapter) {
-      adapterMap.set(OCPPVersion.VERSION_20, adapters.ocpp20Adapter)
-      adapterMap.set(OCPPVersion.VERSION_201, adapters.ocpp20Adapter)
-    }
-    const strategy = new RemoteAuthStrategy(adapterMap, cache, localAuthListManager)
+    const strategy = new RemoteAuthStrategy(adapter, cache, localAuthListManager)
     strategy.initialize(config)
     return strategy
   }
@@ -193,9 +169,7 @@ export class AuthComponentFactory {
   /**
    * Create all authentication strategies based on configuration
    * @param chargingStation - Charging station instance for strategy initialization
-   * @param adapters - Container holding OCPP version-specific adapters
-   * @param adapters.ocpp16Adapter - Optional OCPP 1.6 protocol adapter
-   * @param adapters.ocpp20Adapter - Optional OCPP 2.0.x protocol adapter
+   * @param adapter - OCPP version-specific adapter
    * @param manager - Local auth list manager for local strategy
    * @param cache - Authorization cache shared across strategies
    * @param config - Authentication configuration controlling strategy creation
@@ -203,7 +177,7 @@ export class AuthComponentFactory {
    */
   static async createStrategies (
     chargingStation: ChargingStation,
-    adapters: { ocpp16Adapter?: OCPP16AuthAdapter; ocpp20Adapter?: OCPP20AuthAdapter },
+    adapter: OCPPAuthAdapter,
     manager: LocalAuthListManager | undefined,
     cache: AuthCache | undefined,
     config: AuthConfiguration
@@ -217,13 +191,13 @@ export class AuthComponentFactory {
     }
 
     // Add remote strategy if enabled
-    const remoteStrategy = await this.createRemoteStrategy(adapters, cache, config, manager)
+    const remoteStrategy = await this.createRemoteStrategy(adapter, cache, config, manager)
     if (remoteStrategy) {
       strategies.push(remoteStrategy)
     }
 
     // Always add certificate strategy
-    const certStrategy = await this.createCertificateStrategy(chargingStation, adapters, config)
+    const certStrategy = await this.createCertificateStrategy(chargingStation, adapter, config)
     strategies.push(certStrategy)
 
     // Sort by priority
index 7e717a7cf95a50a1d4bbc08bce4ea062c9a1e945..f15ed43e7982f3e57c06614083d3309f4848037c 100644 (file)
@@ -1,6 +1,5 @@
 import type { OCPP20IdTokenInfoType } from '../../../../types/index.js'
-import type { OCPP16AuthAdapter } from '../adapters/OCPP16AuthAdapter.js'
-import type { OCPP20AuthAdapter } from '../adapters/OCPP20AuthAdapter.js'
+import type { OCPPAuthAdapter } from '../interfaces/OCPPAuthService.js'
 import type { LocalAuthStrategy } from '../strategies/LocalAuthStrategy.js'
 
 import { OCPPError } from '../../../../exception/index.js'
@@ -35,7 +34,7 @@ import { AuthConfigValidator } from '../utils/ConfigValidator.js'
 const moduleName = 'OCPPAuthServiceImpl'
 
 export class OCPPAuthServiceImpl implements OCPPAuthService {
-  private readonly adapters: Map<OCPPVersion, OCPP16AuthAdapter | OCPP20AuthAdapter>
+  private adapter?: OCPPAuthAdapter
   private readonly chargingStation: ChargingStation
   private config: AuthConfiguration
   private readonly metrics: {
@@ -56,7 +55,6 @@ export class OCPPAuthServiceImpl implements OCPPAuthService {
   constructor (chargingStation: ChargingStation) {
     this.chargingStation = chargingStation
     this.strategies = new Map()
-    this.adapters = new Map()
     this.strategyPriority = ['local', 'remote', 'certificate']
 
     // Initialize metrics tracking
@@ -75,7 +73,7 @@ export class OCPPAuthServiceImpl implements OCPPAuthService {
     // Initialize default configuration
     this.config = this.createDefaultConfiguration()
 
-    // Note: Adapters and strategies will be initialized async via initialize()
+    // Note: Adapter and strategies will be initialized async via initialize()
   }
 
   /**
@@ -420,7 +418,7 @@ export class OCPPAuthServiceImpl implements OCPPAuthService {
    * Must be called after construction
    */
   public async initialize (): Promise<void> {
-    await this.initializeAdapters()
+    await this.initializeAdapter()
     await this.initializeStrategies()
   }
 
@@ -515,14 +513,14 @@ export class OCPPAuthServiceImpl implements OCPPAuthService {
       return false
     }
 
-    // Check if any adapter reports remote availability
-    for (const adapter of this.adapters.values()) {
+    // Check if adapter reports remote availability
+    if (this.adapter) {
       try {
-        if (adapter.isRemoteAvailable()) {
+        if (this.adapter.isRemoteAvailable()) {
           return true
         }
       } catch {
-        // Continue checking other adapters
+        // Adapter unavailable
       }
     }
 
@@ -669,19 +667,10 @@ export class OCPPAuthServiceImpl implements OCPPAuthService {
   }
 
   /**
-   * Initialize OCPP adapters using AuthComponentFactory
+   * Initialize OCPP adapter using AuthComponentFactory
    */
-  private async initializeAdapters (): Promise<void> {
-    const adapters = await AuthComponentFactory.createAdapters(this.chargingStation)
-
-    if (adapters.ocpp16Adapter) {
-      this.adapters.set(OCPPVersion.VERSION_16, adapters.ocpp16Adapter)
-    }
-
-    if (adapters.ocpp20Adapter) {
-      this.adapters.set(OCPPVersion.VERSION_20, adapters.ocpp20Adapter)
-      this.adapters.set(OCPPVersion.VERSION_201, adapters.ocpp20Adapter)
-    }
+  private async initializeAdapter (): Promise<void> {
+    this.adapter = await AuthComponentFactory.createAdapter(this.chargingStation)
   }
 
   /**
@@ -690,9 +679,9 @@ export class OCPPAuthServiceImpl implements OCPPAuthService {
   private async initializeStrategies (): Promise<void> {
     const ocppVersion = this.chargingStation.stationInfo?.ocppVersion
 
-    // Get adapters for strategy creation with proper typing
-    const ocpp16Adapter = this.adapters.get(OCPPVersion.VERSION_16) as OCPP16AuthAdapter | undefined
-    const ocpp20Adapter = this.adapters.get(OCPPVersion.VERSION_20) as OCPP20AuthAdapter | undefined
+    if (this.adapter == null) {
+      throw new OCPPError(ErrorType.INTERNAL_ERROR, 'Adapter must be initialized before strategies')
+    }
 
     // Create auth cache for strategy injection
     const authCache = AuthComponentFactory.createAuthCache(this.config)
@@ -700,7 +689,7 @@ export class OCPPAuthServiceImpl implements OCPPAuthService {
     // Create strategies using factory
     const strategies = await AuthComponentFactory.createStrategies(
       this.chargingStation,
-      { ocpp16Adapter, ocpp20Adapter },
+      this.adapter,
       undefined, // manager - delegated to OCPPAuthServiceImpl
       authCache,
       this.config
index 118a977a6a69d2234063b9aaa004afb8fc3504ea..0059f9f44ced0fbb68bdc799758fc2f8a91eb24c 100644 (file)
@@ -28,7 +28,7 @@ export class CertificateAuthStrategy implements AuthStrategy {
   public readonly name = 'CertificateAuthStrategy'
   public readonly priority = 3
 
-  private readonly adapters: Map<OCPPVersion, OCPPAuthAdapter>
+  private readonly adapter: OCPPAuthAdapter
   private readonly chargingStation: ChargingStation
   private isInitialized = false
   private stats = {
@@ -39,9 +39,9 @@ export class CertificateAuthStrategy implements AuthStrategy {
     totalRequests: 0,
   }
 
-  constructor (chargingStation: ChargingStation, adapters: Map<OCPPVersion, OCPPAuthAdapter>) {
+  constructor (chargingStation: ChargingStation, adapter: OCPPAuthAdapter) {
     this.chargingStation = chargingStation
-    this.adapters = adapters
+    this.adapter = adapter
   }
 
   /**
@@ -73,16 +73,7 @@ export class CertificateAuthStrategy implements AuthStrategy {
         )
       }
 
-      // Get the appropriate adapter
-      const adapter = this.adapters.get(request.identifier.ocppVersion)
-      if (!adapter) {
-        return this.createFailureResult(
-          AuthorizationStatus.INVALID,
-          `No adapter available for OCPP ${request.identifier.ocppVersion}`,
-          request.identifier,
-          startTime
-        )
-      }
+      const adapter = this.adapter
 
       // For OCPP 2.0, we can use certificate-based validation
       if (request.identifier.ocppVersion === OCPPVersion.VERSION_20) {
@@ -126,16 +117,13 @@ export class CertificateAuthStrategy implements AuthStrategy {
       return false
     }
 
-    // Must have an adapter for this OCPP version
-    const hasAdapter = this.adapters.has(request.identifier.ocppVersion)
-
     // Certificate authentication must be enabled
     const certAuthEnabled = config.certificateAuthEnabled
 
     // Must have certificate data in the identifier
     const hasCertificateData = this.hasCertificateData(request.identifier)
 
-    return hasAdapter && certAuthEnabled && hasCertificateData && this.isInitialized
+    return certAuthEnabled && hasCertificateData && this.isInitialized
   }
 
   cleanup (): void {
index 82135f70401ed6f84b3e4a7720face08e1f2ac5c..d7bcb7ca3ea96d86315ef827a94b43f3b526dbcd 100644 (file)
@@ -1,4 +1,3 @@
-import type { OCPPVersion } from '../../../../types/index.js'
 import type {
   AuthCache,
   AuthStrategy,
@@ -33,7 +32,7 @@ export class RemoteAuthStrategy implements AuthStrategy {
   public readonly name = 'RemoteAuthStrategy'
   public readonly priority = 2 // After local but before certificate
 
-  private adapters = new Map<OCPPVersion, OCPPAuthAdapter>()
+  private adapter?: OCPPAuthAdapter
   private authCache?: AuthCache
   private isInitialized = false
   private localAuthListManager?: LocalAuthListManager
@@ -49,27 +48,15 @@ export class RemoteAuthStrategy implements AuthStrategy {
   }
 
   constructor (
-    adapters?: Map<OCPPVersion, OCPPAuthAdapter>,
+    adapter?: OCPPAuthAdapter,
     authCache?: AuthCache,
     localAuthListManager?: LocalAuthListManager
   ) {
-    if (adapters) {
-      this.adapters = adapters
-    }
+    this.adapter = adapter
     this.authCache = authCache
     this.localAuthListManager = localAuthListManager
   }
 
-  /**
-   * Add an OCPP adapter for a specific version
-   * @param version - OCPP protocol version the adapter handles
-   * @param adapter - OCPP authentication adapter instance for remote operations
-   */
-  public addAdapter (version: OCPPVersion, adapter: OCPPAuthAdapter): void {
-    this.adapters.set(version, adapter)
-    logger.debug(`${moduleName}: Added OCPP ${version} adapter`)
-  }
-
   /**
    * Authenticate using remote CSMS authorization
    * @param request - Authorization request with identifier and context
@@ -96,12 +83,10 @@ export class RemoteAuthStrategy implements AuthStrategy {
         `${moduleName}: Authenticating ${truncateId(request.identifier.value)} via CSMS for ${request.context}`
       )
 
-      // Get appropriate adapter for OCPP version
-      const adapter = this.adapters.get(request.identifier.ocppVersion)
+      // Get adapter
+      const adapter = this.adapter
       if (!adapter) {
-        logger.warn(
-          `${moduleName}: No adapter available for OCPP version ${request.identifier.ocppVersion}`
-        )
+        logger.warn(`${moduleName}: No adapter available`)
         return undefined
       }
 
@@ -179,11 +164,11 @@ export class RemoteAuthStrategy implements AuthStrategy {
    * Check if this strategy can handle the authentication request
    * @param request - Authorization request to evaluate
    * @param config - Authentication configuration with remote authorization settings
-   * @returns True if an adapter exists for the OCPP version and remote auth is enabled
+   * @returns True if an adapter is available and remote auth is enabled
    */
   public canHandle (request: AuthRequest, config: AuthConfiguration): boolean {
-    // Can handle if we have an adapter for the identifier's OCPP version
-    const hasAdapter = this.adapters.has(request.identifier.ocppVersion)
+    // Can handle if we have an adapter
+    const hasAdapter = this.adapter != null
 
     // Remote authorization must be enabled via configuration
     const remoteEnabled = config.remoteAuthorization !== false
@@ -213,29 +198,35 @@ export class RemoteAuthStrategy implements AuthStrategy {
     logger.info(`${moduleName}: Cleanup completed`)
   }
 
+  /**
+   * Clear the OCPP adapter
+   */
+  public clearAdapter (): void {
+    this.adapter = undefined
+    logger.debug(`${moduleName}: Cleared OCPP adapter`)
+  }
+
   /**
    * Get strategy statistics
    * @returns Strategy statistics including success rates, response times, and error counts
    */
   public async getStats (): Promise<Record<string, unknown>> {
     const cacheStats = this.authCache ? this.authCache.getStats() : null
-    const adapterStats = new Map<string, unknown>()
 
-    // Collect adapter availability status
-    for (const [version, adapter] of this.adapters) {
+    let adapterAvailable = false
+    if (this.adapter) {
       try {
-        const isAvailable = await adapter.isRemoteAvailable()
-        adapterStats.set(`ocpp${version}Available`, isAvailable)
-      } catch (error) {
-        adapterStats.set(`ocpp${version}Available`, false)
+        adapterAvailable = await this.adapter.isRemoteAvailable()
+      } catch {
+        adapterAvailable = false
       }
     }
 
     return {
       ...this.stats,
-      adapterCount: this.adapters.size,
-      adapterStats: Object.fromEntries(adapterStats),
+      adapterAvailable,
       cacheStats,
+      hasAdapter: this.adapter != null,
       hasAuthCache: !!this.authCache,
       isInitialized: this.isInitialized,
       networkErrorRate:
@@ -254,30 +245,24 @@ export class RemoteAuthStrategy implements AuthStrategy {
   }
 
   /**
-   * Initialize strategy with configuration and adapters
+   * Initialize strategy with configuration and adapter
    * @param config - Authentication configuration for adapter validation
    */
   public initialize (config: AuthConfiguration): void {
     try {
       logger.info(`${moduleName}: Initializing...`)
 
-      // Validate that we have at least one adapter
-      if (this.adapters.size === 0) {
-        logger.warn(`${moduleName}: No OCPP adapters provided`)
+      // Validate that we have an adapter
+      if (this.adapter == null) {
+        logger.warn(`${moduleName}: No OCPP adapter provided`)
       }
 
       const stationVersion = config.ocppVersion ?? 'unknown'
 
-      // Validate adapter configurations (deduplicate by instance to avoid
-      // validating the same adapter twice for VERSION_20 and VERSION_201)
-      const validatedAdapters = new Set<OCPPAuthAdapter>()
-      for (const [, adapter] of this.adapters) {
-        if (validatedAdapters.has(adapter)) {
-          continue
-        }
-        validatedAdapters.add(adapter)
+      // Validate adapter configuration
+      if (this.adapter) {
         try {
-          const isValid = adapter.validateConfiguration(config)
+          const isValid = this.adapter.validateConfiguration(config)
           if (!isValid) {
             logger.warn(`${moduleName}: Invalid configuration for OCPP ${stationVersion}`)
           } else {
@@ -309,16 +294,12 @@ export class RemoteAuthStrategy implements AuthStrategy {
   }
 
   /**
-   * Remove an OCPP adapter
-   * @param version - OCPP protocol version of the adapter to remove
-   * @returns True if the adapter was found and removed
+   * Set the OCPP adapter
+   * @param adapter - OCPP authentication adapter instance for remote operations
    */
-  public removeAdapter (version: OCPPVersion): boolean {
-    const removed = this.adapters.delete(version)
-    if (removed) {
-      logger.debug(`${moduleName}: Removed OCPP ${version} adapter`)
-    }
-    return removed
+  public setAdapter (adapter: OCPPAuthAdapter): void {
+    this.adapter = adapter
+    logger.debug(`${moduleName}: Set OCPP adapter`)
   }
 
   /**
@@ -339,26 +320,18 @@ export class RemoteAuthStrategy implements AuthStrategy {
 
   /**
    * Test connectivity to remote authorization service
-   * @returns True if at least one OCPP adapter can reach its remote service
+   * @returns True if the OCPP adapter can reach its remote service
    */
   public async testConnectivity (): Promise<boolean> {
-    if (!this.isInitialized || this.adapters.size === 0) {
+    if (!this.isInitialized || this.adapter == null) {
       return false
     }
 
-    // Test connectivity for all adapters
-    const connectivityTests = Array.from(this.adapters.values()).map(async adapter => {
-      try {
-        return await adapter.isRemoteAvailable()
-      } catch (error) {
-        return false
-      }
-    })
-
-    const results = await Promise.allSettled(connectivityTests)
-
-    // Return true if at least one adapter is available
-    return results.some(result => result.status === 'fulfilled' && result.value)
+    try {
+      return await this.adapter.isRemoteAvailable()
+    } catch {
+      return false
+    }
   }
 
   /**
index 88f71e7debc1c60ec2cca76b59507912879ad7ad..0fc91b860784c5a3af3f44c8959d26b9ef24b667 100644 (file)
@@ -19,35 +19,35 @@ await describe('AuthComponentFactory', async () => {
     standardCleanup()
   })
 
-  await describe('createAdapters', async () => {
+  await describe('createAdapter', async () => {
     await it('should create OCPP 1.6 adapter', async () => {
       const { station: chargingStation } = createMockChargingStation({
         stationInfo: { ocppVersion: OCPPVersion.VERSION_16 },
       })
-      const result = await AuthComponentFactory.createAdapters(chargingStation)
+      const adapter = await AuthComponentFactory.createAdapter(chargingStation)
 
-      assert.notStrictEqual(result.ocpp16Adapter, undefined)
-      assert.strictEqual(result.ocpp20Adapter, undefined)
+      assert.notStrictEqual(adapter, undefined)
+      assert.strictEqual(adapter.ocppVersion, OCPPVersion.VERSION_16)
     })
 
     await it('should create OCPP 2.0 adapter', async () => {
       const { station: chargingStation } = createMockChargingStation({
         stationInfo: { ocppVersion: OCPPVersion.VERSION_20 },
       })
-      const result = await AuthComponentFactory.createAdapters(chargingStation)
+      const adapter = await AuthComponentFactory.createAdapter(chargingStation)
 
-      assert.strictEqual(result.ocpp16Adapter, undefined)
-      assert.notStrictEqual(result.ocpp20Adapter, undefined)
+      assert.notStrictEqual(adapter, undefined)
+      assert.strictEqual(adapter.ocppVersion, OCPPVersion.VERSION_20)
     })
 
     await it('should create OCPP 2.0.1 adapter', async () => {
       const { station: chargingStation } = createMockChargingStation({
         stationInfo: { ocppVersion: OCPPVersion.VERSION_201 },
       })
-      const result = await AuthComponentFactory.createAdapters(chargingStation)
+      const adapter = await AuthComponentFactory.createAdapter(chargingStation)
 
-      assert.strictEqual(result.ocpp16Adapter, undefined)
-      assert.notStrictEqual(result.ocpp20Adapter, undefined)
+      assert.notStrictEqual(adapter, undefined)
+      assert.strictEqual(adapter.ocppVersion, OCPPVersion.VERSION_20)
     })
 
     await it('should throw error for unsupported version', async () => {
@@ -55,7 +55,7 @@ await describe('AuthComponentFactory', async () => {
         stationInfo: { ocppVersion: 'VERSION_15' as OCPPVersion },
       })
 
-      await assert.rejects(AuthComponentFactory.createAdapters(chargingStation), {
+      await assert.rejects(AuthComponentFactory.createAdapter(chargingStation), {
         message: /Unsupported OCPP version/,
       })
     })
@@ -64,7 +64,7 @@ await describe('AuthComponentFactory', async () => {
       const { station: chargingStation } = createMockChargingStation()
       chargingStation.stationInfo = undefined
 
-      await assert.rejects(AuthComponentFactory.createAdapters(chargingStation), {
+      await assert.rejects(AuthComponentFactory.createAdapter(chargingStation), {
         message: /OCPP version not found/,
       })
     })
@@ -153,7 +153,7 @@ await describe('AuthComponentFactory', async () => {
       const { station: chargingStation } = createMockChargingStation({
         stationInfo: { ocppVersion: OCPPVersion.VERSION_16 },
       })
-      const adapters = await AuthComponentFactory.createAdapters(chargingStation)
+      const adapter = await AuthComponentFactory.createAdapter(chargingStation)
       const config: AuthConfiguration = {
         allowOfflineTxForUnknownId: false,
         authorizationCacheEnabled: false,
@@ -165,7 +165,7 @@ await describe('AuthComponentFactory', async () => {
         remoteAuthorization: false,
       }
 
-      const result = await AuthComponentFactory.createRemoteStrategy(adapters, undefined, config)
+      const result = await AuthComponentFactory.createRemoteStrategy(adapter, undefined, config)
 
       assert.strictEqual(result, undefined)
     })
@@ -174,7 +174,7 @@ await describe('AuthComponentFactory', async () => {
       const { station: chargingStation } = createMockChargingStation({
         stationInfo: { ocppVersion: OCPPVersion.VERSION_16 },
       })
-      const adapters = await AuthComponentFactory.createAdapters(chargingStation)
+      const adapter = await AuthComponentFactory.createAdapter(chargingStation)
       const config: AuthConfiguration = {
         allowOfflineTxForUnknownId: false,
         authorizationCacheEnabled: false,
@@ -186,7 +186,7 @@ await describe('AuthComponentFactory', async () => {
         remoteAuthorization: true,
       }
 
-      const result = await AuthComponentFactory.createRemoteStrategy(adapters, undefined, config)
+      const result = await AuthComponentFactory.createRemoteStrategy(adapter, undefined, config)
 
       assert.notStrictEqual(result, undefined)
       if (result) {
@@ -200,7 +200,7 @@ await describe('AuthComponentFactory', async () => {
       const { station: chargingStation } = createMockChargingStation({
         stationInfo: { ocppVersion: OCPPVersion.VERSION_16 },
       })
-      const adapters = await AuthComponentFactory.createAdapters(chargingStation)
+      const adapter = await AuthComponentFactory.createAdapter(chargingStation)
       const config: AuthConfiguration = {
         allowOfflineTxForUnknownId: false,
         authorizationCacheEnabled: false,
@@ -213,7 +213,7 @@ await describe('AuthComponentFactory', async () => {
 
       const result = await AuthComponentFactory.createCertificateStrategy(
         chargingStation,
-        adapters,
+        adapter,
         config
       )
 
@@ -227,7 +227,7 @@ await describe('AuthComponentFactory', async () => {
       const { station: chargingStation } = createMockChargingStation({
         stationInfo: { ocppVersion: OCPPVersion.VERSION_16 },
       })
-      const adapters = await AuthComponentFactory.createAdapters(chargingStation)
+      const adapter = await AuthComponentFactory.createAdapter(chargingStation)
       const config: AuthConfiguration = {
         allowOfflineTxForUnknownId: false,
         authorizationCacheEnabled: false,
@@ -240,7 +240,7 @@ await describe('AuthComponentFactory', async () => {
 
       const result = await AuthComponentFactory.createStrategies(
         chargingStation,
-        adapters,
+        adapter,
         undefined,
         undefined,
         config
@@ -254,7 +254,7 @@ await describe('AuthComponentFactory', async () => {
       const { station: chargingStation } = createMockChargingStation({
         stationInfo: { ocppVersion: OCPPVersion.VERSION_16 },
       })
-      const adapters = await AuthComponentFactory.createAdapters(chargingStation)
+      const adapter = await AuthComponentFactory.createAdapter(chargingStation)
       const config: AuthConfiguration = {
         allowOfflineTxForUnknownId: false,
         authorizationCacheEnabled: false,
@@ -268,7 +268,7 @@ await describe('AuthComponentFactory', async () => {
 
       const result = await AuthComponentFactory.createStrategies(
         chargingStation,
-        adapters,
+        adapter,
         undefined,
         undefined,
         config
index b45da9a299494c5fbb8fa9adb474def64a0772c0..3a3f1ffbdc1b08328ff6e21292e4964b25214511 100644 (file)
@@ -54,10 +54,7 @@ await describe('CertificateAuthStrategy', async () => {
       }),
     })
 
-    const adapters = new Map<OCPPVersion, OCPPAuthAdapter>()
-    adapters.set(OCPPVersion.VERSION_20, mockOCPP20Adapter)
-
-    strategy = new CertificateAuthStrategy(mockStation, adapters)
+    strategy = new CertificateAuthStrategy(mockStation, mockOCPP20Adapter)
   })
 
   afterEach(() => {
index 58fa2cef1a53bab6d0273566e7f7839ef5df9955..2faa90aead7ebaabc08ff59c336a4eccb0352b92 100644 (file)
@@ -36,19 +36,13 @@ await describe('RemoteAuthStrategy', async () => {
   let mockAuthCache: AuthCache
   let mockLocalAuthListManager: LocalAuthListManager
   let mockOCPP16Adapter: OCPPAuthAdapter
-  let mockOCPP20Adapter: OCPPAuthAdapter
 
   beforeEach(() => {
     mockAuthCache = createMockAuthCache()
     mockLocalAuthListManager = createMockLocalAuthListManager()
     mockOCPP16Adapter = createMockOCPPAdapter(OCPPVersion.VERSION_16)
-    mockOCPP20Adapter = createMockOCPPAdapter(OCPPVersion.VERSION_20)
 
-    const adapters = new Map<OCPPVersion, OCPPAuthAdapter>()
-    adapters.set(OCPPVersion.VERSION_16, mockOCPP16Adapter)
-    adapters.set(OCPPVersion.VERSION_20, mockOCPP20Adapter)
-
-    strategy = new RemoteAuthStrategy(adapters, mockAuthCache, mockLocalAuthListManager)
+    strategy = new RemoteAuthStrategy(mockOCPP16Adapter, mockAuthCache, mockLocalAuthListManager)
   })
 
   afterEach(() => {
@@ -69,16 +63,15 @@ await describe('RemoteAuthStrategy', async () => {
   })
 
   await describe('initialize', async () => {
-    await it('should initialize successfully with adapters', () => {
+    await it('should initialize successfully with adapter', () => {
       const config = createTestAuthConfig({ authorizationCacheEnabled: true })
       assert.doesNotThrow(() => {
         strategy.initialize(config)
       })
     })
 
-    await it('should validate adapter configurations', () => {
+    await it('should validate adapter configuration', () => {
       mockOCPP16Adapter.validateConfiguration = () => true
-      mockOCPP20Adapter.validateConfiguration = () => true
       const config = createTestAuthConfig()
       assert.doesNotThrow(() => {
         strategy.initialize(config)
@@ -133,7 +126,7 @@ await describe('RemoteAuthStrategy', async () => {
       strategy.initialize(config)
     })
 
-    await it('should authenticate using OCPP 1.6 adapter', async () => {
+    await it('should authenticate using adapter', async () => {
       const config = createTestAuthConfig({ authorizationCacheEnabled: true })
       const request = createMockAuthRequest({
         identifier: createMockIdentifier(
@@ -150,23 +143,6 @@ await describe('RemoteAuthStrategy', async () => {
       assert.strictEqual(result.method, AuthenticationMethod.REMOTE_AUTHORIZATION)
     })
 
-    await it('should authenticate using OCPP 2.0 adapter', async () => {
-      const config = createTestAuthConfig({ authorizationCacheEnabled: true })
-      const request = createMockAuthRequest({
-        identifier: {
-          ocppVersion: OCPPVersion.VERSION_20,
-          type: IdentifierType.ID_TAG,
-          value: 'REMOTE_TAG_20',
-        },
-      })
-
-      const result = await strategy.authenticate(request, config)
-
-      assert.notStrictEqual(result, undefined)
-      assert.strictEqual(result?.status, AuthorizationStatus.ACCEPTED)
-      assert.strictEqual(result.method, AuthenticationMethod.REMOTE_AUTHORIZATION)
-    })
-
     await it('should cache successful authorization results', async () => {
       let cachedKey: string | undefined
       mockAuthCache.set = (key: string) => {
@@ -321,6 +297,9 @@ await describe('RemoteAuthStrategy', async () => {
     })
 
     await it('should return undefined when no adapter available', async () => {
+      const strategyNoAdapter = new RemoteAuthStrategy(undefined, mockAuthCache)
+      strategyNoAdapter.initialize(createTestAuthConfig())
+
       const config = createTestAuthConfig()
       const request = createMockAuthRequest({
         identifier: {
@@ -330,7 +309,7 @@ await describe('RemoteAuthStrategy', async () => {
         },
       })
 
-      const result = await strategy.authenticate(request, config)
+      const result = await strategyNoAdapter.authenticate(request, config)
       assert.strictEqual(result, undefined)
     })
 
@@ -417,9 +396,9 @@ await describe('RemoteAuthStrategy', async () => {
   })
 
   await describe('adapter management', async () => {
-    await it('should add adapter dynamically', () => {
+    await it('should set adapter dynamically', () => {
       const newStrategy = new RemoteAuthStrategy()
-      newStrategy.addAdapter(OCPPVersion.VERSION_16, mockOCPP16Adapter)
+      newStrategy.setAdapter(mockOCPP16Adapter)
 
       const config = createTestAuthConfig()
       const request = createMockAuthRequest({
@@ -429,8 +408,8 @@ await describe('RemoteAuthStrategy', async () => {
       assert.strictEqual(newStrategy.canHandle(request, config), true)
     })
 
-    await it('should remove adapter', () => {
-      void strategy.removeAdapter(OCPPVersion.VERSION_16)
+    await it('should clear adapter', () => {
+      strategy.clearAdapter()
 
       const config = createTestAuthConfig()
       const request = createMockAuthRequest({
@@ -454,9 +433,8 @@ await describe('RemoteAuthStrategy', async () => {
       assert.strictEqual(result, false)
     })
 
-    await it('should return false when all adapters unavailable', async () => {
+    await it('should return false when adapter unavailable', async () => {
       mockOCPP16Adapter.isRemoteAvailable = () => false
-      mockOCPP20Adapter.isRemoteAvailable = () => false
 
       strategy.initialize(createTestAuthConfig())
       const result = await strategy.testConnectivity()
@@ -467,7 +445,7 @@ await describe('RemoteAuthStrategy', async () => {
   await describe('getStats', async () => {
     await it('should return strategy statistics', async () => {
       const stats = await strategy.getStats()
-      assert.strictEqual(stats.adapterCount, 2)
+      assert.strictEqual(stats.hasAdapter, true)
       assert.strictEqual(stats.failedRemoteAuth, 0)
       assert.strictEqual(stats.hasAuthCache, true)
       assert.strictEqual(stats.isInitialized, false)
@@ -478,7 +456,7 @@ await describe('RemoteAuthStrategy', async () => {
     await it('should include adapter statistics', async () => {
       strategy.initialize(createTestAuthConfig())
       const stats = await strategy.getStats()
-      assert.notStrictEqual(stats.adapterStats, undefined)
+      assert.strictEqual(typeof stats.adapterAvailable, 'boolean')
     })
   })