From 65ea75eeab63f231268d0d1a2c66900c50a4cabd Mon Sep 17 00:00:00 2001 From: Thomas BOUSSELIN Date: Thu, 23 Jan 2025 15:53:54 +0100 Subject: [PATCH] feat: test for postDistributedInformation --- .../DistributedEntityProvisionService.kt | 6 +- .../DistributedEntityProvisionServiceTests.kt | 120 ++++++++++++++++++ .../egm/stellio/shared/model/ApiExceptions.kt | 2 +- 3 files changed, 124 insertions(+), 4 deletions(-) create mode 100644 search-service/src/test/kotlin/com/egm/stellio/search/csr/service/DistributedEntityProvisionServiceTests.kt diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/csr/service/DistributedEntityProvisionService.kt b/search-service/src/main/kotlin/com/egm/stellio/search/csr/service/DistributedEntityProvisionService.kt index e6ecacc40..96264a05c 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/csr/service/DistributedEntityProvisionService.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/csr/service/DistributedEntityProvisionService.kt @@ -122,7 +122,7 @@ class DistributedEntityProvisionService( } else responses to entity } - private suspend fun postDistributedInformation( + internal suspend fun postDistributedInformation( httpHeaders: HttpHeaders, entity: CompactedEntity, csr: ContextSourceRegistration, @@ -163,7 +163,7 @@ class DistributedEntityProvisionService( } else if (response == null) { val message = "No error message received from CSR ${csr.id} at $uri" logger.warn(message) - GatewayTimeoutException(message).left() + BadGatewayException(message).left() } else { logger.warn("Error creating an entity for CSR at $uri: $response") ContextSourceException.fromResponse(response).left() @@ -173,7 +173,7 @@ class DistributedEntityProvisionService( onFailure = { e -> logger.warn("Error contacting CSR at $uri: ${e.message}") logger.warn(e.stackTraceToString()) - BadGatewayException( + GatewayTimeoutException( "Error connecting to CSR at $uri: \"${e.cause}:${e.message}\"" ).left() } diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/csr/service/DistributedEntityProvisionServiceTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/csr/service/DistributedEntityProvisionServiceTests.kt new file mode 100644 index 000000000..e0db85c6a --- /dev/null +++ b/search-service/src/test/kotlin/com/egm/stellio/search/csr/service/DistributedEntityProvisionServiceTests.kt @@ -0,0 +1,120 @@ +package com.egm.stellio.search.csr.service + +import com.egm.stellio.search.csr.CsrUtils.gimmeRawCSR +import com.egm.stellio.search.support.WithKafkaContainer +import com.egm.stellio.search.support.WithTimescaleContainer +import com.egm.stellio.shared.model.ContextSourceException +import com.egm.stellio.shared.model.ErrorType +import com.egm.stellio.shared.model.GatewayTimeoutException +import com.egm.stellio.shared.util.APIC_COMPOUND_CONTEXT +import com.egm.stellio.shared.util.JsonLdUtils.compactEntity +import com.egm.stellio.shared.util.expandJsonLdEntity +import com.egm.stellio.shared.util.toUri +import com.github.tomakehurst.wiremock.client.WireMock.badRequest +import com.github.tomakehurst.wiremock.client.WireMock.post +import com.github.tomakehurst.wiremock.client.WireMock.stubFor +import com.github.tomakehurst.wiremock.client.WireMock.urlMatching +import com.github.tomakehurst.wiremock.junit5.WireMockTest +import com.ninjasquad.springmockk.SpykBean +import kotlinx.coroutines.test.runTest +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertInstanceOf +import org.junit.jupiter.api.Assertions.assertTrue +import org.junit.jupiter.api.Test +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.http.HttpHeaders +import org.springframework.http.HttpStatus +import org.springframework.test.context.ActiveProfiles + +@SpringBootTest +@WireMockTest(httpPort = 8089) +@ActiveProfiles("test") +class DistributedEntityProvisionServiceTests : WithTimescaleContainer, WithKafkaContainer() { + + @SpykBean + private lateinit var distributedEntityProvisionService: DistributedEntityProvisionService + +// @Autowired +// private lateinit var applicationProperties: ApplicationProperties +// +// @MockkBean +// private lateinit var contextSourceRegistrationService: ContextSourceRegistrationService + + private val apiaryId = "urn:ngsi-ld:Apiary:TEST" + + private val entity = + """ + { + "id":"$apiaryId", + "type":"Apiary", + "name": { + "type":"Property", + "value":"ApiarySophia" + }, + "@context":[ "$APIC_COMPOUND_CONTEXT" ] + } + """.trimIndent() + + private val validErrorResponse = + """ + { + "type":"${ErrorType.BAD_REQUEST_DATA.type}", + "status": ${HttpStatus.BAD_REQUEST.value()}, + "title": "A valid error", + "detail":"The detail of the valid Error" + } + """.trimIndent() + + private val responseWithBadPayload = "error message not respecting specification" + + @Test + fun `postDistributedInformation should process badly formed errors`() = runTest { + val csr = gimmeRawCSR() + val path = "/ngsi-ld/v1/entities" + + stubFor( + post(urlMatching(path)) + .willReturn(badRequest().withBody(responseWithBadPayload)) + ) + + val entity = compactEntity(expandJsonLdEntity(entity), listOf(APIC_COMPOUND_CONTEXT)) + val response = distributedEntityProvisionService.postDistributedInformation(HttpHeaders(), entity, csr, path) + + assertTrue(response.isLeft()) + assertEquals(response.leftOrNull()?.type, ErrorType.BAD_GATEWAY.type) + assertEquals(response.leftOrNull()?.status, HttpStatus.BAD_GATEWAY) + assertEquals(response.leftOrNull()?.detail, responseWithBadPayload) + } + + @Test + fun `postDistributedInformation should return the received error`() = runTest { + val csr = gimmeRawCSR() + val path = "/ngsi-ld/v1/entities" + + stubFor( + post(urlMatching(path)) + .willReturn(badRequest().withBody(validErrorResponse)) + ) + + val entity = compactEntity(expandJsonLdEntity(entity), listOf(APIC_COMPOUND_CONTEXT)) + val response = distributedEntityProvisionService.postDistributedInformation(HttpHeaders(), entity, csr, path) + + assertTrue(response.isLeft()) + assertInstanceOf(ContextSourceException::class.java, response.leftOrNull()) + assertEquals(response.leftOrNull()?.type, ErrorType.BAD_REQUEST_DATA.type) + assertEquals(response.leftOrNull()?.status, HttpStatus.BAD_REQUEST) + assertEquals(response.leftOrNull()?.detail, "The detail of the valid Error") + assertEquals(response.leftOrNull()?.message, "A valid error") + } + + @Test + fun `postDistributedInformation should return a GateWayTimeOut if it receives no answer`() = runTest { + val csr = gimmeRawCSR().copy(endpoint = "http://localhost:invalid".toUri()) + val path = "/ngsi-ld/v1/entities" + val entity = compactEntity(expandJsonLdEntity(entity), listOf(APIC_COMPOUND_CONTEXT)) + val response = distributedEntityProvisionService.postDistributedInformation(HttpHeaders(), entity, csr, path) + + assertTrue(response.isLeft()) + assertInstanceOf(GatewayTimeoutException::class.java, response.leftOrNull()) + } +} diff --git a/shared/src/main/kotlin/com/egm/stellio/shared/model/ApiExceptions.kt b/shared/src/main/kotlin/com/egm/stellio/shared/model/ApiExceptions.kt index b7f455d11..ea9ebdcbc 100644 --- a/shared/src/main/kotlin/com/egm/stellio/shared/model/ApiExceptions.kt +++ b/shared/src/main/kotlin/com/egm/stellio/shared/model/ApiExceptions.kt @@ -53,8 +53,8 @@ data class ContextSourceException( ) { companion object { fun fromResponse(response: String): ContextSourceException { - val responseMap = response.deserializeAsMap() return kotlin.runCatching { + val responseMap = response.deserializeAsMap() // mandatory val type = responseMap[TYPE_PROPERTY].toString().toUri() val title = responseMap[TITLE_PROPERTY]!!.toString()