Skip to content

Commit

Permalink
feat: Add validation of required endpoints
Browse files Browse the repository at this point in the history
  • Loading branch information
andacata committed Jan 9, 2024
1 parent 4faa880 commit 312ebfc
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 66 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import com.izivia.ocpi.toolkit.modules.credentials.repositories.PartnerRepositor
import com.izivia.ocpi.toolkit.modules.versions.VersionDetailsClient
import com.izivia.ocpi.toolkit.modules.versions.VersionsClient
import com.izivia.ocpi.toolkit.modules.versions.domain.Endpoint
import com.izivia.ocpi.toolkit.modules.versions.domain.InterfaceRole
import com.izivia.ocpi.toolkit.modules.versions.domain.ModuleID
import com.izivia.ocpi.toolkit.modules.versions.domain.parseVersionNumber
import com.izivia.ocpi.toolkit.modules.versions.repositories.VersionsRepository
Expand All @@ -28,14 +29,16 @@ import com.izivia.ocpi.toolkit.transport.TransportClientBuilder
* @property clientCredentialsRoleRepository client's repository to retrieve its role
* @property serverVersionsEndpointUrl the versions endpoint url of the server (for the client to retrieve endpoints)
* @property transportClientBuilder used to build a transport (will be used to create CredentialClient to make calls)
* @property requiredOtherPartEndpointsProvider the endpoints this client expects from the other part to provide
*/
class CredentialsClientService(
private val clientVersionsEndpointUrl: String,
private val clientPartnerRepository: PartnerRepository,
private val clientVersionsRepository: VersionsRepository,
private val clientCredentialsRoleRepository: CredentialsRoleRepository,
private val serverVersionsEndpointUrl: String,
private val transportClientBuilder: TransportClientBuilder
private val transportClientBuilder: TransportClientBuilder,
private val requiredOtherPartEndpointsProvider: suspend () -> Map<InterfaceRole, List<ModuleID>>
) {
suspend fun get(): Credentials = clientPartnerRepository
.getCredentialsClientToken(partnerUrl = serverVersionsEndpointUrl)
Expand Down Expand Up @@ -226,6 +229,8 @@ class CredentialsClientService(
it.data ?: throw OcpiResponseException(it.status_code, it.status_message ?: "unknown")
}

CredentialsCommon.checkRequiredEndpoints(requiredOtherPartEndpointsProvider(), versionDetails.endpoints)

// Store version & endpoint
return clientPartnerRepository.saveEndpoints(
partnerUrl = serverVersionsEndpointUrl,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.izivia.ocpi.toolkit.modules.credentials.services

import com.izivia.ocpi.toolkit.common.OcpiServerNoMatchingEndpointsException
import com.izivia.ocpi.toolkit.modules.versions.domain.Endpoint
import com.izivia.ocpi.toolkit.modules.versions.domain.InterfaceRole
import com.izivia.ocpi.toolkit.modules.versions.domain.ModuleID

class CredentialsCommon {
companion object {
fun checkRequiredEndpoints(
requiredEndpoints: Map<InterfaceRole, List<ModuleID>>,
actualEndpoints: List<Endpoint>
) {
if (requiredEndpoints.isEmpty()) {
return
}

val requiredOtherPartAsReceiverEndpoints = requiredEndpoints[InterfaceRole.RECEIVER] ?: listOf()
val requiredOtherPartAsSenderEndpoints = requiredEndpoints[InterfaceRole.SENDER] ?: listOf()

actualEndpoints
.find { it.identifier == ModuleID.credentials }
.let {
it ?: throw OcpiServerNoMatchingEndpointsException(
"${ModuleID.credentials} other part endpoint missing"
)
}

checkRequiredRoleEndpoints(actualEndpoints, requiredOtherPartAsReceiverEndpoints, InterfaceRole.RECEIVER)
checkRequiredRoleEndpoints(actualEndpoints, requiredOtherPartAsSenderEndpoints, InterfaceRole.SENDER)
}

private fun checkRequiredRoleEndpoints(
endpoints: List<Endpoint>,
requiredEndpoints: List<ModuleID>,
role: InterfaceRole
) {
for (requiredEndpoint in requiredEndpoints) {
endpoints
.find {
requiredEndpoint == ModuleID.credentials ||
(it.role == role && it.identifier == requiredEndpoint)
}
.let {
it ?: throw OcpiServerNoMatchingEndpointsException(
"${requiredEndpoint.name} as ${role.name} other part endpoint missing"
)
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class CredentialsServerService(
private val credentialsRoleRepository: CredentialsRoleRepository,
private val transportClientBuilder: TransportClientBuilder,
private val serverVersionsUrlProvider: suspend () -> String,
private val requiredClientEndpointsProvider: suspend () -> Map<String, List<ModuleID>>
private val requiredOtherPartEndpointsProvider: suspend () -> Map<InterfaceRole, List<ModuleID>>
) : CredentialsInterface {

override suspend fun get(
Expand Down Expand Up @@ -201,50 +201,11 @@ class CredentialsServerService(
)
}

checkRequiredClientEndpoints(versionDetail.endpoints)
CredentialsCommon.checkRequiredEndpoints(requiredOtherPartEndpointsProvider(), versionDetail.endpoints)

partnerRepository.saveEndpoints(partnerUrl = credentials.url, endpoints = versionDetail.endpoints)
}

private suspend fun checkRequiredClientEndpoints(endpoints: List<Endpoint>) {
val requiredClientEndpoints = requiredClientEndpointsProvider()

if (requiredClientEndpoints.isEmpty()) {
return
}

val requiredClientAsReceiverEndpoints = requiredClientEndpoints[InterfaceRole.RECEIVER.name] ?: listOf()
val requiredClientAsSenderEndpoints = requiredClientEndpoints[InterfaceRole.SENDER.name] ?: listOf()

endpoints
.find { it.identifier == ModuleID.credentials }
.let {
it ?: throw OcpiServerNoMatchingEndpointsException("${ModuleID.credentials} client endpoint missing")
}

checkRequiredRoleEndpoints(endpoints, requiredClientAsReceiverEndpoints, InterfaceRole.RECEIVER)
checkRequiredRoleEndpoints(endpoints, requiredClientAsSenderEndpoints, InterfaceRole.SENDER)
}

private suspend fun checkRequiredRoleEndpoints(
endpoints: List<Endpoint>,
requiredEndpoints: List<ModuleID>,
role: InterfaceRole
) {
for (requiredEndpoint in requiredEndpoints) {
endpoints
.find {
requiredEndpoint == ModuleID.credentials
|| (it.role == role && it.identifier == requiredEndpoint)
}
.let {
it ?: throw OcpiServerNoMatchingEndpointsException(
"${requiredEndpoint.name} as ${role.name} client endpoint missing"
)
}
}
}

private suspend fun getCredentials(serverToken: String): Credentials = Credentials(
token = serverToken,
url = serverVersionsUrlProvider(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ fun main() {
secureFilter = receiverPlatformRepository::checkToken
)

val requiredOtherPartEndpoints = mapOf(InterfaceRole.RECEIVER to listOf(ModuleID.credentials))

runBlocking {
CredentialsServer(
service = CredentialsServerService(
Expand All @@ -40,15 +42,15 @@ fun main() {
override suspend fun getCredentialsRoles(): List<CredentialRole> = listOf(
CredentialRole(
role = Role.EMSP,
business_details = BusinessDetails(name = "Receiver", website = null, logo = null),
party_id = "DEF",
country_code = "FR"
businessDetails = BusinessDetails(name = "Receiver", website = null, logo = null),
partyId = "DEF",
countryCode = "FR"
)
)
},
transportClientBuilder = Http4kTransportClientBuilder(),
serverVersionsUrlProvider = { receiverVersionsUrl },
requiredClientEndpointsProvider = { mapOf(InterfaceRole.RECEIVER.name to listOf(ModuleID.credentials)) }
requiredOtherPartEndpointsProvider = { requiredOtherPartEndpoints }
)
).registerOn(receiverServer)
VersionsServer(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import com.izivia.ocpi.toolkit.modules.credentials.services.CredentialsClientSer
import com.izivia.ocpi.toolkit.modules.locations.domain.BusinessDetails
import com.izivia.ocpi.toolkit.modules.versions.VersionDetailsServer
import com.izivia.ocpi.toolkit.modules.versions.VersionsServer
import com.izivia.ocpi.toolkit.modules.versions.domain.InterfaceRole
import com.izivia.ocpi.toolkit.modules.versions.domain.ModuleID
import com.izivia.ocpi.toolkit.modules.versions.services.VersionDetailsService
import com.izivia.ocpi.toolkit.modules.versions.services.VersionsService
import com.izivia.ocpi.toolkit.samples.common.*
Expand Down Expand Up @@ -61,7 +63,8 @@ fun main() {
)
},
serverVersionsEndpointUrl = receiverVersionsUrl,
transportClientBuilder = Http4kTransportClientBuilder()
transportClientBuilder = Http4kTransportClientBuilder(),
requiredOtherPartEndpointsProvider = { mapOf(InterfaceRole.RECEIVER to listOf(ModuleID.credentials)) }
)

runBlocking {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ class CredentialsIntegrationTests : BaseServerIntegrationTest() {

private var database: MongoDatabase? = null

private fun setupReceiver(requiredEndpoints: Map<String, List<ModuleID>> = mapOf()): ServerSetupResult {
private fun setupReceiver(requiredEndpoints: Map<InterfaceRole, List<ModuleID>> = mapOf()): ServerSetupResult {
if (database == null) database = buildDBClient().getDatabase("ocpi-2-2-1-tests")
val receiverPartnerCollection = database!!
.getCollection<Partner>("receiver-server-${UUID.randomUUID()}")
Expand All @@ -68,15 +68,15 @@ class CredentialsIntegrationTests : BaseServerIntegrationTest() {
override suspend fun getCredentialsRoles(): List<CredentialRole> = listOf(
CredentialRole(
role = Role.EMSP,
business_details = BusinessDetails(name = "Receiver", website = null, logo = null),
party_id = "DEF",
country_code = "FR"
businessDetails = BusinessDetails(name = "Receiver", website = null, logo = null),
partyId = "DEF",
countryCode = "FR"
)
)
},
transportClientBuilder = Http4kTransportClientBuilder(),
serverVersionsUrlProvider = { receiverServerVersionsUrl },
requiredClientEndpointsProvider = { requiredEndpoints }
requiredOtherPartEndpointsProvider = { requiredEndpoints }
)
).registerOn(receiverServer)
VersionsServer(
Expand Down Expand Up @@ -133,25 +133,27 @@ class CredentialsIntegrationTests : BaseServerIntegrationTest() {

private fun setupCredentialsSenderClient(
senderServerSetupResult: ServerSetupResult,
receiverServerSetupResult: ServerSetupResult
receiverServerSetupResult: ServerSetupResult,
requiredEndpoints: Map<InterfaceRole, List<ModuleID>> = mapOf()
): CredentialsClientService {
// Setup sender (client)
return CredentialsClientService(
clientVersionsEndpointUrl = senderServerSetupResult.versionsEndpoint,
clientPlatformRepository = PartnerMongoRepository(collection = senderServerSetupResult.partnerCollection),
clientPartnerRepository = PartnerMongoRepository(collection = senderServerSetupResult.partnerCollection),
clientVersionsRepository = VersionsCacheRepository(baseUrl = senderServerSetupResult.transport.baseUrl),
clientCredentialsRoleRepository = object : CredentialsRoleRepository {
override suspend fun getCredentialsRoles(): List<CredentialRole> = listOf(
CredentialRole(
role = Role.CPO,
business_details = BusinessDetails(name = "Sender", website = null, logo = null),
party_id = "ABC",
country_code = "FR"
businessDetails = BusinessDetails(name = "Sender", website = null, logo = null),
partyId = "ABC",
countryCode = "FR"
)
)
},
serverVersionsEndpointUrl = receiverServerSetupResult.versionsEndpoint,
transportClientBuilder = Http4kTransportClientBuilder()
transportClientBuilder = Http4kTransportClientBuilder(),
requiredOtherPartEndpointsProvider = { requiredEndpoints }
)
}

Expand Down Expand Up @@ -256,11 +258,11 @@ class CredentialsIntegrationTests : BaseServerIntegrationTest() {
fun `should not properly run registration process because required endpoints are missing`() {
val receiverServer = setupReceiver(
mapOf(
InterfaceRole.RECEIVER.name to listOf(
InterfaceRole.RECEIVER to listOf(
ModuleID.credentials,
ModuleID.locations
),
InterfaceRole.SENDER.name to listOf(
InterfaceRole.SENDER to listOf(
ModuleID.chargingprofiles
)
)
Expand Down Expand Up @@ -292,16 +294,18 @@ class CredentialsIntegrationTests : BaseServerIntegrationTest() {
get { statusCode }
.isEqualTo(OcpiStatus.SERVER_NO_MATCHING_ENDPOINTS.code)
}

}

@Test
fun `should properly run registration process then correct get credentials from receiver`() {
val receiverServer = setupReceiver(mapOf(
InterfaceRole.RECEIVER.name to listOf(
ModuleID.credentials,
ModuleID.locations)
))
val receiverServer = setupReceiver(
mapOf(
InterfaceRole.RECEIVER to listOf(
ModuleID.credentials,
ModuleID.locations
)
)
)
val senderServer = setupSender()

val credentialsClientService = setupCredentialsSenderClient(
Expand Down

0 comments on commit 312ebfc

Please sign in to comment.