diff options
Diffstat (limited to 'src')
3 files changed, 172 insertions, 9 deletions
diff --git a/src/integrationTest/kotlin/dev/dnpm/etl/processor/output/RestDipMtbFileSenderTest.kt b/src/integrationTest/kotlin/dev/dnpm/etl/processor/output/RestDipMtbFileSenderTest.kt new file mode 100644 index 0000000..f6f6a08 --- /dev/null +++ b/src/integrationTest/kotlin/dev/dnpm/etl/processor/output/RestDipMtbFileSenderTest.kt @@ -0,0 +1,146 @@ +/* + * This file is part of ETL-Processor + * + * Copyright (c) 2023 Comprehensive Cancer Center Mainfranken + * Copyright (c) 2023-2025 Paul-Christian Volkmer, Datenintegrationszentrum Philipps-Universität Marburg and Contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +package dev.dnpm.etl.processor.output + +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.module.kotlin.KotlinModule +import dev.dnpm.etl.processor.RequestId +import dev.dnpm.etl.processor.config.AppConfiguration +import dev.dnpm.etl.processor.config.AppRestConfiguration +import dev.dnpm.etl.processor.config.AppSecurityConfiguration +import dev.dnpm.etl.processor.config.RestTargetProperties +import dev.dnpm.etl.processor.consent.ConsentEvaluator +import dev.dnpm.etl.processor.monitoring.ReportService +import dev.dnpm.etl.processor.monitoring.RequestStatus +import dev.pcvolkmer.mv64e.mtb.* +import org.assertj.core.api.Assertions.assertThat +import org.hamcrest.CoreMatchers.not +import org.hamcrest.Matchers.containsString +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Nested +import org.junit.jupiter.api.Test +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.http.HttpMethod +import org.springframework.http.HttpStatus +import org.springframework.http.MediaType +import org.springframework.retry.policy.SimpleRetryPolicy +import org.springframework.retry.support.RetryTemplateBuilder +import org.springframework.test.context.ContextConfiguration +import org.springframework.test.context.TestPropertySource +import org.springframework.test.context.bean.override.mockito.MockitoBean +import org.springframework.test.web.client.MockRestServiceServer +import org.springframework.test.web.client.match.MockRestRequestMatchers.* +import org.springframework.test.web.client.response.MockRestResponseCreators.withStatus +import org.springframework.web.client.RestTemplate +import java.time.Instant +import java.util.* + +@SpringBootTest +@MockitoBean(types = [ReportService::class]) +@ContextConfiguration( + classes = + [ + AppConfiguration::class, + AppSecurityConfiguration::class, + AppRestConfiguration::class, + ConsentEvaluator::class, + ], +) +@TestPropertySource( + properties = ["app.rest.uri=http://localhost:9000", "app.max-retry-attempts=5"], +) +class RestDipMtbFileSenderTest { + + @Nested + inner class DnpmV2ContentRequest { + + private lateinit var mockRestServiceServer: MockRestServiceServer + + private lateinit var restMtbFileSender: RestMtbFileSender + + private var reportService = + ReportService(ObjectMapper().registerModule(KotlinModule.Builder().build())) + + @BeforeEach + fun setup( + @Autowired restTemplate: RestTemplate + ) { + val restTemplate = restTemplate + val restTargetProperties = RestTargetProperties("http://localhost:9000/api", null, null) + val retryTemplate = RetryTemplateBuilder().customPolicy(SimpleRetryPolicy(1)).build() + + this.mockRestServiceServer = MockRestServiceServer.createServer(restTemplate) + + this.restMtbFileSender = + RestDipMtbFileSender(restTemplate, restTargetProperties, retryTemplate, reportService) + } + + @Test + fun shouldNotSendJsonNullValues() { + this.mockRestServiceServer + .expect(method(HttpMethod.POST)) + .andExpect(requestTo("http://localhost:9000/api/mtb/etl/patient-record")) + .andExpect( + content().string(not(containsString("null"))) + ) + .andRespond { + withStatus(HttpStatus.OK) + .contentType(MediaType.APPLICATION_JSON) + .body( + """ + { + "patient": "PID", + "issues": [ + { "severity": "info", "message": "Info Message" } + ] + } + """ + ) + .createResponse(it) + } + + val response = restMtbFileSender.send(DnpmV2MtbFileRequest(RequestId("TEST1234"), dnpmV2MtbFile())) + assertThat(response.status).isEqualTo(RequestStatus.SUCCESS) + } + } + + companion object { + fun dnpmV2MtbFile(): Mtb { + return Mtb().apply { + this.patient = + Patient().apply { + this.id = "PID" + this.birthDate = Date.from(Instant.now()) + this.gender = GenderCoding().apply { this.code = GenderCodingCode.MALE } + } + this.episodesOfCare = + listOf( + MtbEpisodeOfCare().apply { + this.id = "1" + this.patient = Reference().apply { this.id = "PID" } + this.period = PeriodDate().apply { this.start = Date.from(Instant.now()) } + } + ) + } + } + } +} diff --git a/src/main/kotlin/dev/dnpm/etl/processor/config/AppConfiguration.kt b/src/main/kotlin/dev/dnpm/etl/processor/config/AppConfiguration.kt index 35585cb..f21c09b 100644 --- a/src/main/kotlin/dev/dnpm/etl/processor/config/AppConfiguration.kt +++ b/src/main/kotlin/dev/dnpm/etl/processor/config/AppConfiguration.kt @@ -1,7 +1,8 @@ /* * This file is part of ETL-Processor * - * Copyright (c) 2025 Comprehensive Cancer Center Mainfranken, Datenintegrationszentrum Philipps-Universität Marburg and Contributors + * Copyright (c) 2023 Comprehensive Cancer Center Mainfranken + * Copyright (c) 2023-2025 Paul-Christian Volkmer, Datenintegrationszentrum Philipps-Universität Marburg and Contributors * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published @@ -31,21 +32,20 @@ import dev.dnpm.etl.processor.security.TokenService import dev.dnpm.etl.processor.services.ConsentProcessor import dev.dnpm.etl.processor.services.Transformation import dev.dnpm.etl.processor.services.TransformationService -import kotlin.time.Duration.Companion.seconds -import kotlin.time.toJavaDuration import org.apache.cxf.jaxws.JaxWsProxyFactoryBean import org.slf4j.LoggerFactory -import org.springframework.boot.autoconfigure.condition.AllNestedConditions import org.springframework.boot.autoconfigure.condition.AnyNestedCondition import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty import org.springframework.boot.context.properties.EnableConfigurationProperties +import org.springframework.boot.web.client.RestTemplateBuilder import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Conditional import org.springframework.context.annotation.Configuration import org.springframework.context.annotation.ConfigurationCondition import org.springframework.data.jdbc.repository.config.AbstractJdbcConfiguration -import org.springframework.data.relational.core.sql.NestedCondition +import org.springframework.http.converter.StringHttpMessageConverter +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter import org.springframework.retry.RetryCallback import org.springframework.retry.RetryContext import org.springframework.retry.RetryListener @@ -58,6 +58,8 @@ import org.springframework.security.provisioning.InMemoryUserDetailsManager import org.springframework.web.client.HttpClientErrorException import org.springframework.web.client.RestTemplate import reactor.core.publisher.Sinks +import kotlin.time.Duration.Companion.seconds +import kotlin.time.toJavaDuration @Configuration @EnableConfigurationProperties( @@ -75,9 +77,22 @@ class AppConfiguration { private val logger = LoggerFactory.getLogger(AppConfiguration::class.java) + fun stringHttpMessageConverter(): StringHttpMessageConverter { + return StringHttpMessageConverter() + } + + @Bean + fun mappingJacksonHttpMessageConverter(objectMapper: ObjectMapper): MappingJackson2HttpMessageConverter { + val converter = MappingJackson2HttpMessageConverter() + converter.setObjectMapper(objectMapper) + return converter + } + @Bean - fun restTemplate(): RestTemplate { - return RestTemplate() + fun restTemplate(objectMapper: ObjectMapper): RestTemplate { + return RestTemplateBuilder() + .messageConverters(stringHttpMessageConverter(), mappingJacksonHttpMessageConverter(objectMapper)) + .build() } @Bean diff --git a/src/main/kotlin/dev/dnpm/etl/processor/output/RestMtbFileSender.kt b/src/main/kotlin/dev/dnpm/etl/processor/output/RestMtbFileSender.kt index 4120d4a..9c22ec0 100644 --- a/src/main/kotlin/dev/dnpm/etl/processor/output/RestMtbFileSender.kt +++ b/src/main/kotlin/dev/dnpm/etl/processor/output/RestMtbFileSender.kt @@ -1,7 +1,8 @@ /* * This file is part of ETL-Processor * - * Copyright (c) 2025 Comprehensive Cancer Center Mainfranken, Datenintegrationszentrum Philipps-Universität Marburg and Contributors + * Copyright (c) 2023 Comprehensive Cancer Center Mainfranken + * Copyright (c) 2023-2025 Paul-Christian Volkmer, Datenintegrationszentrum Philipps-Universität Marburg and Contributors * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published @@ -28,6 +29,7 @@ import dev.dnpm.etl.processor.monitoring.asRequestStatus import org.slf4j.LoggerFactory import org.springframework.http.HttpEntity import org.springframework.http.HttpHeaders +import org.springframework.http.HttpMethod import org.springframework.http.MediaType import org.springframework.retry.support.RetryTemplate import org.springframework.web.client.RestClientException @@ -51,7 +53,7 @@ abstract class RestMtbFileSender( return retryTemplate.execute<MtbFileSender.Response, Exception> { val headers = getHttpHeaders(request) val entityReq = HttpEntity(request.content, headers) - val response = restTemplate.postForEntity(sendUrl(), entityReq, String::class.java) + val response = restTemplate.exchange(sendUrl(), HttpMethod.POST, entityReq, String::class.java) if (!response.statusCode.is2xxSuccessful) { logger.warn("Error sending to remote system: {}", response.body) return@execute MtbFileSender.Response( |
