From 2e881578937ee39bab3cacff9ee09328658341c2 Mon Sep 17 00:00:00 2001 From: Paul-Christian Volkmer Date: Tue, 12 Aug 2025 23:11:50 +0200 Subject: refactor: remove obsolete bwHC data model V1.0 (#129) --- .../etl/processor/input/KafkaInputListenerTest.kt | 107 +++++-- .../processor/input/MtbFileRestControllerTest.kt | 234 --------------- .../etl/processor/output/KafkaMtbFileSenderTest.kt | 116 -------- .../processor/output/RestBwhcMtbFileSenderTest.kt | 313 --------------------- .../processor/output/RestDipMtbFileSenderTest.kt | 106 +------ .../dnpm/etl/processor/pseudonym/ExtensionsTest.kt | 170 +---------- .../processor/pseudonym/PseudonymizeServiceTest.kt | 35 +-- .../etl/processor/services/ConsentProcessorTest.kt | 4 +- .../etl/processor/services/RequestProcessorTest.kt | 191 ++++++------- .../services/TransformationServiceTest.kt | 73 ++--- 10 files changed, 214 insertions(+), 1135 deletions(-) delete mode 100644 src/test/kotlin/dev/dnpm/etl/processor/output/RestBwhcMtbFileSenderTest.kt (limited to 'src/test/kotlin') diff --git a/src/test/kotlin/dev/dnpm/etl/processor/input/KafkaInputListenerTest.kt b/src/test/kotlin/dev/dnpm/etl/processor/input/KafkaInputListenerTest.kt index fbcfb3f..1239cdf 100644 --- a/src/test/kotlin/dev/dnpm/etl/processor/input/KafkaInputListenerTest.kt +++ b/src/test/kotlin/dev/dnpm/etl/processor/input/KafkaInputListenerTest.kt @@ -20,12 +20,10 @@ package dev.dnpm.etl.processor.input import com.fasterxml.jackson.databind.ObjectMapper -import de.ukw.ccc.bwhc.dto.Consent -import de.ukw.ccc.bwhc.dto.MtbFile -import de.ukw.ccc.bwhc.dto.Patient import dev.dnpm.etl.processor.consent.TtpConsentStatus import dev.dnpm.etl.processor.CustomMediaType import dev.dnpm.etl.processor.services.RequestProcessor +import dev.pcvolkmer.mv64e.mtb.* import org.apache.kafka.clients.consumer.ConsumerRecord import org.apache.kafka.common.header.internals.RecordHeader import org.apache.kafka.common.header.internals.RecordHeaders @@ -57,9 +55,20 @@ class KafkaInputListenerTest { @Test fun shouldProcessMtbFileRequest() { - val mtbFile = MtbFile.builder() - .withPatient(Patient.builder().withId("DUMMY_12345678").build()) - .withConsent(Consent.builder().withStatus(Consent.Status.ACTIVE).build()) + val mtbFile = Mtb.builder() + .patient(Patient.builder().id("DUMMY_12345678").build()) + .metadata( + MvhMetadata + .builder() + .modelProjectConsent( + ModelProjectConsent + .builder() + .provisions( + listOf(Provision.builder().type(ConsentProvision.PERMIT).purpose(ModelProjectConsentPurpose.SEQUENCING).build()) + ).build() + ) + .build() + ) .build() kafkaInputListener.onMessage( @@ -72,14 +81,25 @@ class KafkaInputListenerTest { ) ) - verify(requestProcessor, times(1)).processMtbFile(any()) + verify(requestProcessor, times(1)).processMtbFile(any()) } @Test fun shouldProcessDeleteRequest() { - val mtbFile = MtbFile.builder() - .withPatient(Patient.builder().withId("DUMMY_12345678").build()) - .withConsent(Consent.builder().withStatus(Consent.Status.REJECTED).build()) + val mtbFile = Mtb.builder() + .patient(Patient.builder().id("DUMMY_12345678").build()) + .metadata( + MvhMetadata + .builder() + .modelProjectConsent( + ModelProjectConsent + .builder() + .provisions( + listOf(Provision.builder().type(ConsentProvision.DENY).purpose(ModelProjectConsentPurpose.SEQUENCING).build()) + ).build() + ) + .build() + ) .build() kafkaInputListener.onMessage( @@ -100,9 +120,20 @@ class KafkaInputListenerTest { @Test fun shouldProcessMtbFileRequestWithExistingRequestId() { - val mtbFile = MtbFile.builder() - .withPatient(Patient.builder().withId("DUMMY_12345678").build()) - .withConsent(Consent.builder().withStatus(Consent.Status.ACTIVE).build()) + val mtbFile = Mtb.builder() + .patient(Patient.builder().id("DUMMY_12345678").build()) + .metadata( + MvhMetadata + .builder() + .modelProjectConsent( + ModelProjectConsent + .builder() + .provisions( + listOf(Provision.builder().type(ConsentProvision.PERMIT).purpose(ModelProjectConsentPurpose.SEQUENCING).build()) + ).build() + ) + .build() + ) .build() val headers = RecordHeaders(listOf(RecordHeader("requestId", UUID.randomUUID().toString().toByteArray()))) @@ -122,14 +153,25 @@ class KafkaInputListenerTest { ) ) - verify(requestProcessor, times(1)).processMtbFile(any(), anyValueClass()) + verify(requestProcessor, times(1)).processMtbFile(any(), anyValueClass()) } @Test fun shouldProcessDeleteRequestWithExistingRequestId() { - val mtbFile = MtbFile.builder() - .withPatient(Patient.builder().withId("DUMMY_12345678").build()) - .withConsent(Consent.builder().withStatus(Consent.Status.REJECTED).build()) + val mtbFile = Mtb.builder() + .patient(Patient.builder().id("DUMMY_12345678").build()) + .metadata( + MvhMetadata + .builder() + .modelProjectConsent( + ModelProjectConsent + .builder() + .provisions( + listOf(Provision.builder().type(ConsentProvision.DENY).purpose(ModelProjectConsentPurpose.SEQUENCING).build()) + ).build() + ) + .build() + ) .build() val headers = RecordHeaders(listOf(RecordHeader("requestId", UUID.randomUUID().toString().toByteArray()))) @@ -148,15 +190,29 @@ class KafkaInputListenerTest { Optional.empty() ) ) - verify(requestProcessor, times(1)).processDeletion(anyValueClass(), anyValueClass(), eq( - TtpConsentStatus.UNKNOWN_CHECK_FILE)) + verify(requestProcessor, times(1)).processDeletion( + anyValueClass(), anyValueClass(), eq( + TtpConsentStatus.UNKNOWN_CHECK_FILE + ) + ) } @Test fun shouldNotProcessDnpmV2Request() { - val mtbFile = MtbFile.builder() - .withPatient(Patient.builder().withId("DUMMY_12345678").build()) - .withConsent(Consent.builder().withStatus(Consent.Status.REJECTED).build()) + val mtbFile = Mtb.builder() + .patient(Patient.builder().id("DUMMY_12345678").build()) + .metadata( + MvhMetadata + .builder() + .modelProjectConsent( + ModelProjectConsent + .builder() + .provisions( + listOf(Provision.builder().type(ConsentProvision.DENY).purpose(ModelProjectConsentPurpose.SEQUENCING).build()) + ).build() + ) + .build() + ) .build() val headers = RecordHeaders( @@ -180,8 +236,11 @@ class KafkaInputListenerTest { Optional.empty() ) ) - verify(requestProcessor, times(0)).processDeletion(anyValueClass(), anyValueClass(), eq( - TtpConsentStatus.UNKNOWN_CHECK_FILE)) + verify(requestProcessor, times(0)).processDeletion( + anyValueClass(), anyValueClass(), eq( + TtpConsentStatus.UNKNOWN_CHECK_FILE + ) + ) } } diff --git a/src/test/kotlin/dev/dnpm/etl/processor/input/MtbFileRestControllerTest.kt b/src/test/kotlin/dev/dnpm/etl/processor/input/MtbFileRestControllerTest.kt index 7a91ed1..845f325 100644 --- a/src/test/kotlin/dev/dnpm/etl/processor/input/MtbFileRestControllerTest.kt +++ b/src/test/kotlin/dev/dnpm/etl/processor/input/MtbFileRestControllerTest.kt @@ -20,31 +20,21 @@ package dev.dnpm.etl.processor.input import com.fasterxml.jackson.databind.ObjectMapper -import de.ukw.ccc.bwhc.dto.* -import de.ukw.ccc.bwhc.dto.Consent.Status import dev.dnpm.etl.processor.CustomMediaType -import dev.dnpm.etl.processor.consent.ConsentByMtbFile import dev.dnpm.etl.processor.consent.GicsConsentService -import dev.dnpm.etl.processor.consent.TtpConsentStatus import dev.dnpm.etl.processor.services.RequestProcessor import dev.pcvolkmer.mv64e.mtb.Mtb import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Nested import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith -import org.junit.jupiter.params.ParameterizedTest -import org.junit.jupiter.params.provider.ValueSource import org.mockito.Mock import org.mockito.Mockito.times import org.mockito.Mockito.verify import org.mockito.junit.jupiter.MockitoExtension import org.mockito.kotlin.any -import org.mockito.kotlin.anyValueClass -import org.mockito.kotlin.whenever import org.springframework.core.io.ClassPathResource -import org.springframework.http.MediaType import org.springframework.test.web.servlet.MockMvc -import org.springframework.test.web.servlet.delete import org.springframework.test.web.servlet.post import org.springframework.test.web.servlet.setup.MockMvcBuilders @@ -53,219 +43,6 @@ class MtbFileRestControllerTest { private val objectMapper = ObjectMapper() - @Nested - inner class BwhcRequests { - - private lateinit var mockMvc: MockMvc - - private lateinit var requestProcessor: RequestProcessor - - - @BeforeEach - fun setup( - @Mock requestProcessor: RequestProcessor - ) { - this.requestProcessor = requestProcessor - val controller = MtbFileRestController( - requestProcessor, - ConsentByMtbFile() - ) - this.mockMvc = MockMvcBuilders.standaloneSetup(controller).build() - } - - @Test - fun shouldProcessPostRequest() { - mockMvc.post("/mtbfile") { - content = objectMapper.writeValueAsString(bwhcMtbFileContent(Status.ACTIVE)) - contentType = MediaType.APPLICATION_JSON - }.andExpect { - status { - isAccepted() - } - } - - verify(requestProcessor, times(1)).processMtbFile(any()) - } - - @Test - fun shouldProcessPostRequestWithRejectedConsent() { - mockMvc.post("/mtbfile") { - content = objectMapper.writeValueAsString(bwhcMtbFileContent(Status.REJECTED)) - contentType = MediaType.APPLICATION_JSON - }.andExpect { - status { - isAccepted() - } - } - - verify(requestProcessor, times(1)).processDeletion( - anyValueClass(), - org.mockito.kotlin.eq(TtpConsentStatus.BROAD_CONSENT_MISSING_OR_REJECTED) - ) - } - - @Test - fun shouldProcessDeleteRequest() { - mockMvc.delete("/mtbfile/TEST_12345678").andExpect { - status { - isAccepted() - } - } - - verify(requestProcessor, times(1)).processDeletion( - anyValueClass(), - org.mockito.kotlin.eq(TtpConsentStatus.UNKNOWN_CHECK_FILE) - ) - } - } - - @Nested - inner class BwhcRequestsCheckConsentViaTtp { - - private lateinit var mockMvc: MockMvc - - private lateinit var requestProcessor: RequestProcessor - - private lateinit var gicsConsentService: GicsConsentService - - @BeforeEach - fun setup( - @Mock requestProcessor: RequestProcessor, - @Mock gicsConsentService: GicsConsentService - ) { - this.requestProcessor = requestProcessor - val controller = MtbFileRestController(requestProcessor, gicsConsentService) - this.mockMvc = MockMvcBuilders.standaloneSetup(controller).build() - this.gicsConsentService = gicsConsentService - } - - @ParameterizedTest - @ValueSource(strings = ["ACTIVE", "REJECTED"]) - fun shouldProcessPostRequest(status: String) { - - whenever(gicsConsentService.getTtpBroadConsentStatus(any())).thenReturn(TtpConsentStatus.BROAD_CONSENT_GIVEN) - - mockMvc.post("/mtbfile") { - content = objectMapper.writeValueAsString(bwhcMtbFileContent(Status.valueOf(status))) - contentType = MediaType.APPLICATION_JSON - }.andExpect { - status { - isAccepted() - } - } - - verify(requestProcessor, times(1)).processMtbFile(any()) - } - - - @ParameterizedTest - @ValueSource(strings = ["ACTIVE", "REJECTED"]) - fun shouldProcessPostRequestWithRejectedConsent(status: String) { - - whenever(gicsConsentService.getTtpBroadConsentStatus(any())).thenReturn(TtpConsentStatus.BROAD_CONSENT_MISSING_OR_REJECTED) - - mockMvc.post("/mtbfile") { - content = objectMapper.writeValueAsString(bwhcMtbFileContent(Status.valueOf(status))) - contentType = MediaType.APPLICATION_JSON - }.andExpect { - status { - isAccepted() - } - } - - // consent status from ttp should override file consent value - verify(requestProcessor, times(1)).processDeletion( - anyValueClass(), - org.mockito.kotlin.eq(TtpConsentStatus.BROAD_CONSENT_MISSING_OR_REJECTED) - ) - } - - @Test - fun shouldProcessDeleteRequest() { - - mockMvc.delete("/mtbfile/TEST_12345678").andExpect { - status { - isAccepted() - } - } - - verify(requestProcessor, times(1)).processDeletion( - anyValueClass(), - org.mockito.kotlin.eq(TtpConsentStatus.UNKNOWN_CHECK_FILE) - ) - verify(gicsConsentService, times(0)).getTtpBroadConsentStatus(any()) - - } - } - - - @Nested - inner class BwhcRequestsWithAlias { - - private lateinit var mockMvc: MockMvc - - private lateinit var requestProcessor: RequestProcessor - - @BeforeEach - fun setup( - @Mock requestProcessor: RequestProcessor - ) { - this.requestProcessor = requestProcessor - val controller = MtbFileRestController( - requestProcessor, - ConsentByMtbFile() - ) - this.mockMvc = MockMvcBuilders.standaloneSetup(controller).build() - } - - @Test - fun shouldProcessPostRequest() { - mockMvc.post("/mtb") { - content = objectMapper.writeValueAsString(bwhcMtbFileContent(Status.ACTIVE)) - contentType = MediaType.APPLICATION_JSON - }.andExpect { - status { - isAccepted() - } - } - - verify(requestProcessor, times(1)).processMtbFile(any()) - } - - @Test - fun shouldProcessPostRequestWithRejectedConsent() { - mockMvc.post("/mtb") { - content = objectMapper.writeValueAsString(bwhcMtbFileContent(Status.REJECTED)) - contentType = MediaType.APPLICATION_JSON - }.andExpect { - status { - isAccepted() - } - } - - verify(requestProcessor, times(1)).processDeletion( - anyValueClass(), org.mockito.kotlin.eq( - TtpConsentStatus.BROAD_CONSENT_MISSING_OR_REJECTED - ) - ) - } - - @Test - fun shouldProcessDeleteRequest() { - mockMvc.delete("/mtb/TEST_12345678").andExpect { - status { - isAccepted() - } - } - - verify(requestProcessor, times(1)).processDeletion( - anyValueClass(), org.mockito.kotlin.eq( - TtpConsentStatus.UNKNOWN_CHECK_FILE - ) - ) - } - } - @Nested inner class RequestsForDnpmDataModel21 { @@ -304,15 +81,4 @@ class MtbFileRestControllerTest { } } - - companion object { - fun bwhcMtbFileContent(consentStatus: Status) = MtbFile.builder().withPatient( - Patient.builder().withId("TEST_12345678").withBirthDate("2000-08-08").withGender(Patient.Gender.MALE) - .build() - ).withConsent( - Consent.builder().withId("1").withStatus(consentStatus).withPatient("TEST_12345678").build() - ).withEpisode( - Episode.builder().withId("1").withPatient("TEST_12345678").withPeriod(PeriodStart("2023-08-08")).build() - ).build() - } } diff --git a/src/test/kotlin/dev/dnpm/etl/processor/output/KafkaMtbFileSenderTest.kt b/src/test/kotlin/dev/dnpm/etl/processor/output/KafkaMtbFileSenderTest.kt index f1185ef..1e9c853 100644 --- a/src/test/kotlin/dev/dnpm/etl/processor/output/KafkaMtbFileSenderTest.kt +++ b/src/test/kotlin/dev/dnpm/etl/processor/output/KafkaMtbFileSenderTest.kt @@ -20,8 +20,6 @@ package dev.dnpm.etl.processor.output import com.fasterxml.jackson.databind.ObjectMapper -import de.ukw.ccc.bwhc.dto.* -import de.ukw.ccc.bwhc.dto.Patient import dev.dnpm.etl.processor.CustomMediaType import dev.dnpm.etl.processor.PatientPseudonym import dev.dnpm.etl.processor.RequestId @@ -39,7 +37,6 @@ import org.junit.jupiter.params.provider.MethodSource import org.mockito.Mock import org.mockito.junit.jupiter.MockitoExtension import org.mockito.kotlin.* -import org.springframework.http.MediaType import org.springframework.kafka.core.KafkaTemplate import org.springframework.kafka.support.SendResult import org.springframework.retry.policy.SimpleRetryPolicy @@ -74,20 +71,6 @@ class KafkaMtbFileSenderTest { this.kafkaMtbFileSender = KafkaMtbFileSender(kafkaTemplate, kafkaProperties, retryTemplate, objectMapper) } - @ParameterizedTest - @MethodSource("dev.dnpm.etl.processor.output.KafkaMtbFileSenderTest#requestWithResponseSource") - fun shouldSendMtbFileRequestAndReturnExpectedState(testData: TestData) { - doAnswer { - if (null != testData.exception) { - throw testData.exception - } - completedFuture(SendResult(null, null)) - }.whenever(kafkaTemplate).send(any>()) - - val response = kafkaMtbFileSender.send(BwhcV1MtbFileRequest(TEST_REQUEST_ID, bwhcV1MtbFile(Consent.Status.ACTIVE))) - assertThat(response.status).isEqualTo(testData.requestStatus) - } - @ParameterizedTest @MethodSource("dev.dnpm.etl.processor.output.KafkaMtbFileSenderTest#requestWithResponseSource") fun shouldSendDeleteRequestAndReturnExpectedState(testData: TestData) { @@ -102,66 +85,6 @@ class KafkaMtbFileSenderTest { assertThat(response.status).isEqualTo(testData.requestStatus) } - @Test - fun shouldSendMtbFileRequestWithCorrectKeyAndHeaderAndBody() { - doAnswer { - completedFuture(SendResult(null, null)) - }.whenever(kafkaTemplate).send(any>()) - - kafkaMtbFileSender.send(BwhcV1MtbFileRequest(TEST_REQUEST_ID, bwhcV1MtbFile(Consent.Status.ACTIVE))) - - val captor = argumentCaptor>() - verify(kafkaTemplate, times(1)).send(captor.capture()) - assertThat(captor.firstValue.key()).isNotNull - assertThat(captor.firstValue.key()).isEqualTo("{\"pid\": \"PID\"}") - assertThat(captor.firstValue.headers().headers("contentType")).isNotNull - assertThat(captor.firstValue.headers().headers("contentType")?.firstOrNull()?.value()).isEqualTo(MediaType.APPLICATION_JSON_VALUE.toByteArray()) - assertThat(captor.firstValue.value()).isNotNull - assertThat(captor.firstValue.value()).isEqualTo(objectMapper.writeValueAsString(bwhcV1kafkaRecordData(TEST_REQUEST_ID, Consent.Status.ACTIVE))) - } - - @Test - fun shouldSendDeleteRequestWithCorrectKeyAndBody() { - doAnswer { - completedFuture(SendResult(null, null)) - }.whenever(kafkaTemplate).send(any>()) - - kafkaMtbFileSender.send(DeleteRequest(TEST_REQUEST_ID, TEST_PATIENT_PSEUDONYM)) - - val captor = argumentCaptor>() - verify(kafkaTemplate, times(1)).send(captor.capture()) - assertThat(captor.firstValue.key()).isNotNull - assertThat(captor.firstValue.key()).isEqualTo("{\"pid\": \"PID\"}") - assertThat(captor.firstValue.value()).isNotNull - assertThat(captor.firstValue.value()).isEqualTo(objectMapper.writeValueAsString(bwhcV1kafkaRecordData(TEST_REQUEST_ID, Consent.Status.REJECTED))) - } - - @ParameterizedTest - @MethodSource("dev.dnpm.etl.processor.output.KafkaMtbFileSenderTest#requestWithResponseSource") - fun shouldRetryOnMtbFileKafkaSendError(testData: TestData) { - val kafkaProperties = KafkaProperties("testtopic") - val retryTemplate = RetryTemplateBuilder().customPolicy(SimpleRetryPolicy(3)).build() - this.kafkaMtbFileSender = KafkaMtbFileSender(this.kafkaTemplate, kafkaProperties, retryTemplate, this.objectMapper) - - doAnswer { - if (null != testData.exception) { - throw testData.exception - } - completedFuture(SendResult(null, null)) - }.whenever(kafkaTemplate).send(any>()) - - kafkaMtbFileSender.send(BwhcV1MtbFileRequest(TEST_REQUEST_ID, bwhcV1MtbFile(Consent.Status.ACTIVE))) - - val expectedCount = when (testData.exception) { - // OK - No Retry - null -> times(1) - // Request failed - Retry max 3 times - else -> times(3) - } - - verify(kafkaTemplate, expectedCount).send(any>()) - } - @ParameterizedTest @MethodSource("dev.dnpm.etl.processor.output.KafkaMtbFileSenderTest#requestWithResponseSource") fun shouldRetryOnDeleteKafkaSendError(testData: TestData) { @@ -276,41 +199,6 @@ class KafkaMtbFileSenderTest { val TEST_REQUEST_ID = RequestId("TestId") val TEST_PATIENT_PSEUDONYM = PatientPseudonym("PID") - fun bwhcV1MtbFile(consentStatus: Consent.Status): MtbFile { - return if (consentStatus == Consent.Status.ACTIVE) { - MtbFile.builder() - .withPatient( - Patient.builder() - .withId("PID") - .withBirthDate("2000-08-08") - .withGender(Patient.Gender.MALE) - .build() - ) - .withConsent( - Consent.builder() - .withId("1") - .withStatus(consentStatus) - .withPatient("PID") - .build() - ) - .withEpisode( - Episode.builder() - .withId("1") - .withPatient("PID") - .withPeriod(PeriodStart("2023-08-08")) - .build() - ) - } else { - MtbFile.builder() - .withConsent( - Consent.builder() - .withStatus(consentStatus) - .withPatient("PID") - .build() - ) - }.build() - } - fun dnpmV2MtbFile(): Mtb { return Mtb().apply { this.patient = dev.pcvolkmer.mv64e.mtb.Patient().apply { @@ -334,10 +222,6 @@ class KafkaMtbFileSenderTest { } } - fun bwhcV1kafkaRecordData(requestId: RequestId, consentStatus: Consent.Status): MtbRequest { - return BwhcV1MtbFileRequest(requestId, bwhcV1MtbFile(consentStatus)) - } - fun dnmpV2kafkaRecordData(requestId: RequestId): MtbRequest { return DnpmV2MtbFileRequest(requestId, dnpmV2MtbFile()) } diff --git a/src/test/kotlin/dev/dnpm/etl/processor/output/RestBwhcMtbFileSenderTest.kt b/src/test/kotlin/dev/dnpm/etl/processor/output/RestBwhcMtbFileSenderTest.kt deleted file mode 100644 index ead2496..0000000 --- a/src/test/kotlin/dev/dnpm/etl/processor/output/RestBwhcMtbFileSenderTest.kt +++ /dev/null @@ -1,313 +0,0 @@ -/* - * This file is part of ETL-Processor - * - * Copyright (c) 2025 Comprehensive Cancer Center Mainfranken, 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 . - */ - -package dev.dnpm.etl.processor.output - -import com.fasterxml.jackson.databind.ObjectMapper -import com.fasterxml.jackson.module.kotlin.KotlinModule -import de.ukw.ccc.bwhc.dto.* -import dev.dnpm.etl.processor.PatientPseudonym -import dev.dnpm.etl.processor.RequestId -import dev.dnpm.etl.processor.config.RestTargetProperties -import dev.dnpm.etl.processor.monitoring.ReportService -import dev.dnpm.etl.processor.monitoring.RequestStatus -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.params.ParameterizedTest -import org.junit.jupiter.params.provider.MethodSource -import org.springframework.http.HttpHeaders -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.web.client.ExpectedCount -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 - -class RestBwhcMtbFileSenderTest { - - private lateinit var mockRestServiceServer: MockRestServiceServer - - private lateinit var restMtbFileSender: RestMtbFileSender - - private var reportService = ReportService(ObjectMapper().registerModule(KotlinModule.Builder().build())) - - @BeforeEach - fun setup() { - val restTemplate = RestTemplate() - val restTargetProperties = RestTargetProperties("http://localhost:9000/mtbfile", null, null) - val retryTemplate = RetryTemplateBuilder().customPolicy(SimpleRetryPolicy(1)).build() - - this.mockRestServiceServer = MockRestServiceServer.createServer(restTemplate) - - this.restMtbFileSender = - RestBwhcMtbFileSender(restTemplate, restTargetProperties, retryTemplate, reportService) - } - - @ParameterizedTest - @MethodSource("deleteRequestWithResponseSource") - fun shouldReturnExpectedResponseForDelete(requestWithResponse: RequestWithResponse) { - this.mockRestServiceServer - .expect(method(HttpMethod.DELETE)) - .andExpect(requestTo("http://localhost:9000/mtbfile/Patient/${TEST_PATIENT_PSEUDONYM.value}")) - .andRespond { - withStatus(requestWithResponse.httpStatus).body(requestWithResponse.body).createResponse(it) - } - - val response = restMtbFileSender.send(DeleteRequest(TEST_REQUEST_ID, TEST_PATIENT_PSEUDONYM)) - assertThat(response.status).isEqualTo(requestWithResponse.response.status) - assertThat(response.body).isEqualTo(requestWithResponse.response.body) - } - - @ParameterizedTest - @MethodSource("mtbFileRequestWithResponseSource") - fun shouldReturnExpectedResponseForMtbFilePost(requestWithResponse: RequestWithResponse) { - this.mockRestServiceServer - .expect(method(HttpMethod.POST)) - .andExpect(requestTo("http://localhost:9000/mtbfile/MTBFile")) - .andExpect(header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)) - .andRespond { - withStatus(requestWithResponse.httpStatus).body(requestWithResponse.body).createResponse(it) - } - - val response = restMtbFileSender.send(BwhcV1MtbFileRequest(TEST_REQUEST_ID, mtbFile)) - assertThat(response.status).isEqualTo(requestWithResponse.response.status) - assertThat(response.body).isEqualTo(requestWithResponse.response.body) - } - - @ParameterizedTest - @MethodSource("mtbFileRequestWithResponseSource") - fun shouldRetryOnMtbFileHttpRequestError(requestWithResponse: RequestWithResponse) { - val restTemplate = RestTemplate() - val restTargetProperties = RestTargetProperties("http://localhost:9000/mtbfile", null, null) - val retryTemplate = RetryTemplateBuilder().customPolicy(SimpleRetryPolicy(3)).build() - - this.mockRestServiceServer = MockRestServiceServer.createServer(restTemplate) - this.restMtbFileSender = - RestBwhcMtbFileSender(restTemplate, restTargetProperties, retryTemplate, reportService) - - val expectedCount = when (requestWithResponse.httpStatus) { - // OK - No Retry - HttpStatus.OK, HttpStatus.CREATED -> ExpectedCount.max(1) - // Request failed - Retry max 3 times - else -> ExpectedCount.max(3) - } - - this.mockRestServiceServer - .expect(expectedCount, method(HttpMethod.POST)) - .andExpect(requestTo("http://localhost:9000/mtbfile/MTBFile")) - .andRespond { - withStatus(requestWithResponse.httpStatus).body(requestWithResponse.body).createResponse(it) - } - - val response = restMtbFileSender.send(BwhcV1MtbFileRequest(TEST_REQUEST_ID, mtbFile)) - assertThat(response.status).isEqualTo(requestWithResponse.response.status) - assertThat(response.body).isEqualTo(requestWithResponse.response.body) - } - - @ParameterizedTest - @MethodSource("deleteRequestWithResponseSource") - fun shouldRetryOnDeleteHttpRequestError(requestWithResponse: RequestWithResponse) { - val restTemplate = RestTemplate() - val restTargetProperties = RestTargetProperties("http://localhost:9000/mtbfile", null, null) - val retryTemplate = RetryTemplateBuilder().customPolicy(SimpleRetryPolicy(3)).build() - - this.mockRestServiceServer = MockRestServiceServer.createServer(restTemplate) - this.restMtbFileSender = - RestBwhcMtbFileSender(restTemplate, restTargetProperties, retryTemplate, reportService) - - val expectedCount = when (requestWithResponse.httpStatus) { - // OK - No Retry - HttpStatus.OK, HttpStatus.CREATED -> ExpectedCount.max(1) - // Request failed - Retry max 3 times - else -> ExpectedCount.max(3) - } - - this.mockRestServiceServer - .expect(expectedCount, method(HttpMethod.DELETE)) - .andExpect(requestTo("http://localhost:9000/mtbfile/Patient/${TEST_PATIENT_PSEUDONYM.value}")) - .andRespond { - withStatus(requestWithResponse.httpStatus).body(requestWithResponse.body).createResponse(it) - } - - val response = restMtbFileSender.send(DeleteRequest(TEST_REQUEST_ID, TEST_PATIENT_PSEUDONYM)) - assertThat(response.status).isEqualTo(requestWithResponse.response.status) - assertThat(response.body).isEqualTo(requestWithResponse.response.body) - } - - companion object { - data class RequestWithResponse( - val httpStatus: HttpStatus, - val body: String, - val response: MtbFileSender.Response - ) - - val TEST_REQUEST_ID = RequestId("TestId") - val TEST_PATIENT_PSEUDONYM = PatientPseudonym("PID") - - val mtbFile: MtbFile = MtbFile.builder() - .withPatient( - Patient.builder() - .withId("PID") - .withBirthDate("2000-08-08") - .withGender(Patient.Gender.MALE) - .build() - ) - .withConsent( - Consent.builder() - .withId("1") - .withStatus(Consent.Status.ACTIVE) - .withPatient("PID") - .build() - ) - .withEpisode( - Episode.builder() - .withId("1") - .withPatient("PID") - .withPeriod(PeriodStart("2023-08-08")) - .build() - ) - .build() - - private const val ERROR_RESPONSE_BODY = "Sonstiger Fehler bei der Übertragung" - - /** - * Synthetic http responses with related request status - * Also see: https://ibmi-intra.cs.uni-tuebingen.de/display/ZPM/bwHC+REST+API - */ - @JvmStatic - fun mtbFileRequestWithResponseSource(): Set { - return setOf( - RequestWithResponse( - HttpStatus.OK, - responseBodyWithMaxSeverity(ReportService.Severity.INFO), - MtbFileSender.Response( - RequestStatus.SUCCESS, - responseBodyWithMaxSeverity(ReportService.Severity.INFO) - ) - ), - RequestWithResponse( - HttpStatus.CREATED, - responseBodyWithMaxSeverity(ReportService.Severity.WARNING), - MtbFileSender.Response( - RequestStatus.WARNING, - responseBodyWithMaxSeverity(ReportService.Severity.WARNING) - ) - ), - RequestWithResponse( - HttpStatus.BAD_REQUEST, - responseBodyWithMaxSeverity(ReportService.Severity.ERROR), - MtbFileSender.Response(RequestStatus.ERROR, responseBodyWithMaxSeverity(ReportService.Severity.ERROR)) - ), - RequestWithResponse( - HttpStatus.UNPROCESSABLE_ENTITY, - responseBodyWithMaxSeverity(ReportService.Severity.FATAL), - MtbFileSender.Response( - RequestStatus.ERROR, - responseBodyWithMaxSeverity(ReportService.Severity.FATAL) - ) - ), - // Some more errors not mentioned in documentation - RequestWithResponse( - HttpStatus.NOT_FOUND, - ERROR_RESPONSE_BODY, - MtbFileSender.Response(RequestStatus.ERROR, ERROR_RESPONSE_BODY) - ), - RequestWithResponse( - HttpStatus.INTERNAL_SERVER_ERROR, - ERROR_RESPONSE_BODY, - MtbFileSender.Response(RequestStatus.ERROR, ERROR_RESPONSE_BODY) - ) - ) - } - - /** - * Synthetic http responses with related request status - * Also see: https://ibmi-intra.cs.uni-tuebingen.de/display/ZPM/bwHC+REST+API - */ - @JvmStatic - fun deleteRequestWithResponseSource(): Set { - return setOf( - RequestWithResponse(HttpStatus.OK, "", MtbFileSender.Response(RequestStatus.SUCCESS)), - // Some more errors not mentioned in documentation - RequestWithResponse( - HttpStatus.NOT_FOUND, - "what????", - MtbFileSender.Response(RequestStatus.ERROR, ERROR_RESPONSE_BODY) - ), - RequestWithResponse( - HttpStatus.INTERNAL_SERVER_ERROR, - "what????", - MtbFileSender.Response(RequestStatus.ERROR, ERROR_RESPONSE_BODY) - ) - ) - } - - fun responseBodyWithMaxSeverity(severity: ReportService.Severity): String { - return when (severity) { - ReportService.Severity.INFO -> """ - { - "patient": "PID", - "issues": [ - { "severity": "info", "message": "Info Message" } - ] - } - """ - - ReportService.Severity.WARNING -> """ - { - "patient": "PID", - "issues": [ - { "severity": "info", "message": "Info Message" }, - { "severity": "warning", "message": "Warning Message" } - ] - } - """ - - ReportService.Severity.ERROR -> """ - { - "patient": "PID", - "issues": [ - { "severity": "info", "message": "Info Message" }, - { "severity": "warning", "message": "Warning Message" }, - { "severity": "error", "message": "Error Message" } - ] - } - """ - - ReportService.Severity.FATAL -> """ - { - "patient": "PID", - "issues": [ - { "severity": "info", "message": "Info Message" }, - { "severity": "warning", "message": "Warning Message" }, - { "severity": "error", "message": "Error Message" }, - { "severity": "fatal", "message": "Fatal Message" } - ] - } - """ - } - } - } - - -} diff --git a/src/test/kotlin/dev/dnpm/etl/processor/output/RestDipMtbFileSenderTest.kt b/src/test/kotlin/dev/dnpm/etl/processor/output/RestDipMtbFileSenderTest.kt index 8395518..1b27a62 100644 --- a/src/test/kotlin/dev/dnpm/etl/processor/output/RestDipMtbFileSenderTest.kt +++ b/src/test/kotlin/dev/dnpm/etl/processor/output/RestDipMtbFileSenderTest.kt @@ -21,8 +21,6 @@ package dev.dnpm.etl.processor.output import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.module.kotlin.KotlinModule -import de.ukw.ccc.bwhc.dto.* -import de.ukw.ccc.bwhc.dto.Patient import dev.dnpm.etl.processor.CustomMediaType import dev.dnpm.etl.processor.PatientPseudonym import dev.dnpm.etl.processor.RequestId @@ -54,78 +52,6 @@ import java.util.* class RestDipMtbFileSenderTest { - @Nested - inner class BwhcV1ContentRequest { - - private lateinit var mockRestServiceServer: MockRestServiceServer - - private lateinit var restMtbFileSender: RestMtbFileSender - - private var reportService = ReportService(ObjectMapper().registerModule(KotlinModule.Builder().build())) - - @BeforeEach - fun setup() { - val restTemplate = RestTemplate() - val restTargetProperties = RestTargetProperties("http://localhost:9000/api", null, null, false) - val retryTemplate = RetryTemplateBuilder().customPolicy(SimpleRetryPolicy(1)).build() - - this.mockRestServiceServer = MockRestServiceServer.createServer(restTemplate) - - this.restMtbFileSender = - RestDipMtbFileSender(restTemplate, restTargetProperties, retryTemplate, reportService) - } - - @ParameterizedTest - @MethodSource("dev.dnpm.etl.processor.output.RestDipMtbFileSenderTest#mtbFileRequestWithResponseSource") - fun shouldReturnExpectedResponseForMtbFilePost(requestWithResponse: RequestWithResponse) { - this.mockRestServiceServer - .expect(method(HttpMethod.POST)) - .andExpect(requestTo("http://localhost:9000/api/mtb/etl/patient-record")) - .andExpect(header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)) - .andRespond { - withStatus(requestWithResponse.httpStatus).body(requestWithResponse.body).createResponse(it) - } - - val response = restMtbFileSender.send(BwhcV1MtbFileRequest(TEST_REQUEST_ID, bwhcV1mtbFile)) - assertThat(response.status).isEqualTo(requestWithResponse.response.status) - assertThat(response.body).isEqualTo(requestWithResponse.response.body) - } - - @ParameterizedTest - @MethodSource("dev.dnpm.etl.processor.output.RestDipMtbFileSenderTest#mtbFileRequestWithResponseSource") - fun shouldRetryOnMtbFileHttpRequestError(requestWithResponse: RequestWithResponse) { - val restTemplate = RestTemplate() - val restTargetProperties = RestTargetProperties("http://localhost:9000/api", null, null, false) - val retryTemplate = AppConfiguration().retryTemplate(AppConfigProperties("http://localhost:9000")) - retryTemplate.setBackOffPolicy(NoBackOffPolicy()) - - this.mockRestServiceServer = MockRestServiceServer.createServer(restTemplate) - this.restMtbFileSender = - RestDipMtbFileSender(restTemplate, restTargetProperties, retryTemplate, reportService) - - val expectedCount = when (requestWithResponse.httpStatus) { - // OK - No Retry - HttpStatus.OK, HttpStatus.CREATED, HttpStatus.UNPROCESSABLE_ENTITY, HttpStatus.BAD_REQUEST -> ExpectedCount.max( - 1 - ) - // Request failed - Retry max 3 times - else -> ExpectedCount.max(3) - } - - this.mockRestServiceServer - .expect(expectedCount, method(HttpMethod.POST)) - .andExpect(requestTo("http://localhost:9000/api/mtb/etl/patient-record")) - .andRespond { - withStatus(requestWithResponse.httpStatus).body(requestWithResponse.body).createResponse(it) - } - - val response = restMtbFileSender.send(BwhcV1MtbFileRequest(TEST_REQUEST_ID, bwhcV1mtbFile)) - assertThat(response.status).isEqualTo(requestWithResponse.response.status) - assertThat(response.body).isEqualTo(requestWithResponse.response.body) - } - - } - @Nested inner class DnpmV2ContentRequest { @@ -138,7 +64,7 @@ class RestDipMtbFileSenderTest { @BeforeEach fun setup() { val restTemplate = RestTemplate() - val restTargetProperties = RestTargetProperties("http://localhost:9000/api", null, null, false) + val restTargetProperties = RestTargetProperties("http://localhost:9000/api", null, null) val retryTemplate = RetryTemplateBuilder().customPolicy(SimpleRetryPolicy(1)).build() this.mockRestServiceServer = MockRestServiceServer.createServer(restTemplate) @@ -176,7 +102,7 @@ class RestDipMtbFileSenderTest { @BeforeEach fun setup() { val restTemplate = RestTemplate() - val restTargetProperties = RestTargetProperties("http://localhost:9000/api", null, null, false) + val restTargetProperties = RestTargetProperties("http://localhost:9000/api", null, null) val retryTemplate = RetryTemplateBuilder().customPolicy(SimpleRetryPolicy(1)).build() this.mockRestServiceServer = MockRestServiceServer.createServer(restTemplate) @@ -204,8 +130,8 @@ class RestDipMtbFileSenderTest { @MethodSource("dev.dnpm.etl.processor.output.RestDipMtbFileSenderTest#deleteRequestWithResponseSource") fun shouldRetryOnDeleteHttpRequestError(requestWithResponse: RequestWithResponse) { val restTemplate = RestTemplate() - val restTargetProperties = RestTargetProperties("http://localhost:9000/api", null, null, false) - val retryTemplate = AppConfiguration().retryTemplate(AppConfigProperties("http://localhost:9000")) + val restTargetProperties = RestTargetProperties("http://localhost:9000/api", null, null) + val retryTemplate = AppConfiguration().retryTemplate(AppConfigProperties()) retryTemplate.setBackOffPolicy(NoBackOffPolicy()) this.mockRestServiceServer = MockRestServiceServer.createServer(restTemplate) @@ -245,30 +171,6 @@ class RestDipMtbFileSenderTest { val TEST_REQUEST_ID = RequestId("TestId") val TEST_PATIENT_PSEUDONYM = PatientPseudonym("PID") - val bwhcV1mtbFile: MtbFile = MtbFile.builder() - .withPatient( - Patient.builder() - .withId("PID") - .withBirthDate("2000-08-08") - .withGender(Patient.Gender.MALE) - .build() - ) - .withConsent( - Consent.builder() - .withId("1") - .withStatus(Consent.Status.ACTIVE) - .withPatient("PID") - .build() - ) - .withEpisode( - Episode.builder() - .withId("1") - .withPatient("PID") - .withPeriod(PeriodStart("2023-08-08")) - .build() - ) - .build() - fun dnpmV2MtbFile(): Mtb { return Mtb().apply { this.patient = dev.pcvolkmer.mv64e.mtb.Patient().apply { diff --git a/src/test/kotlin/dev/dnpm/etl/processor/pseudonym/ExtensionsTest.kt b/src/test/kotlin/dev/dnpm/etl/processor/pseudonym/ExtensionsTest.kt index b6baec9..5955263 100644 --- a/src/test/kotlin/dev/dnpm/etl/processor/pseudonym/ExtensionsTest.kt +++ b/src/test/kotlin/dev/dnpm/etl/processor/pseudonym/ExtensionsTest.kt @@ -21,8 +21,6 @@ package dev.dnpm.etl.processor.pseudonym import ca.uhn.fhir.context.FhirContext import com.fasterxml.jackson.databind.ObjectMapper -import de.ukw.ccc.bwhc.dto.* -import de.ukw.ccc.bwhc.dto.Patient import dev.dnpm.etl.processor.config.AppConfigProperties import dev.dnpm.etl.processor.config.GIcsConfigProperties import dev.dnpm.etl.processor.config.JacksonConfig @@ -51,172 +49,6 @@ class ExtensionsTest { return JacksonConfig().objectMapper() } - @Nested - inner class UsingBwhcDatamodel { - - val FAKE_MTB_FILE_PATH = "fake_MTBFile.json" - val CLEAN_PATIENT_ID = "5dad2f0b-49c6-47d8-a952-7b9e9e0f7549" - - - private fun fakeMtbFile(): MtbFile { - val mtbFile = ClassPathResource(FAKE_MTB_FILE_PATH).inputStream - return getObjectMapper().readValue(mtbFile, MtbFile::class.java) - } - - private fun MtbFile.serialized(): String { - return getObjectMapper().writeValueAsString(this) - } - - @Test - fun shouldNotContainCleanPatientId(@Mock pseudonymizeService: PseudonymizeService) { - doAnswer { - it.arguments[0] - "PSEUDO-ID" - }.whenever(pseudonymizeService).patientPseudonym(anyValueClass()) - - val mtbFile = fakeMtbFile() - - mtbFile.pseudonymizeWith(pseudonymizeService) - - assertThat(mtbFile.patient.id).isEqualTo("PSEUDO-ID") - assertThat(mtbFile.serialized()).doesNotContain(CLEAN_PATIENT_ID) - } - - @Test - fun shouldNotContainAnyUuidAfterRehashingOfIds(@Mock pseudonymizeService: PseudonymizeService) { - doAnswer { - it.arguments[0] - "PSEUDO-ID" - }.whenever(pseudonymizeService).patientPseudonym(anyValueClass()) - - doAnswer { - "TESTDOMAIN" - }.whenever(pseudonymizeService).prefix() - - val mtbFile = fakeMtbFile() - - mtbFile.pseudonymizeWith(pseudonymizeService) - mtbFile.anonymizeContentWith(pseudonymizeService) - - val pattern = - "\"[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}\"".toRegex() - .toPattern() - val matcher = pattern.matcher(mtbFile.serialized()) - - assertThrows { - matcher.find() - matcher.group() - }.also { - assertThat(it.message).isEqualTo("No match found") - } - - } - - @Test - fun shouldRehashIdsWithPrefix(@Mock pseudonymizeService: PseudonymizeService) { - doAnswer { - it.arguments[0] - "PSEUDO-ID" - }.whenever(pseudonymizeService).patientPseudonym(anyValueClass()) - - doAnswer { - "TESTDOMAIN" - }.whenever(pseudonymizeService).prefix() - - val mtbFile = MtbFile.builder() - .withPatient( - Patient.builder() - .withId("1") - .withBirthDate("2000-08-08") - .withGender(Patient.Gender.MALE) - .build() - ) - .withConsent( - Consent.builder() - .withId("1") - .withStatus(Consent.Status.ACTIVE) - .withPatient("123") - .build() - ) - .withEpisode( - Episode.builder() - .withId("1") - .withPatient("1") - .withPeriod(PeriodStart("2023-08-08")) - .build() - ) - .build() - - mtbFile.pseudonymizeWith(pseudonymizeService) - mtbFile.anonymizeContentWith(pseudonymizeService) - - - assertThat(mtbFile.episode.id) - // TESTDOMAIN - .isEqualTo("TESTDOMAIN44e20a53bbbf9f3ae39626d05df7014dcd77d6098") - } - - @Test - fun shouldNotThrowExceptionOnNullValues(@Mock pseudonymizeService: PseudonymizeService) { - doAnswer { - it.arguments[0] - "PSEUDO-ID" - }.whenever(pseudonymizeService).patientPseudonym(anyValueClass()) - - doAnswer { - "TESTDOMAIN" - }.whenever(pseudonymizeService).prefix() - - val mtbFile = MtbFile.builder() - .withPatient( - Patient.builder() - .withId("1") - .withBirthDate("2000-08-08") - .withGender(Patient.Gender.MALE) - .build() - ) - .withConsent( - Consent.builder() - .withId("1") - .withStatus(Consent.Status.ACTIVE) - .withPatient("123") - .build() - ) - .withEpisode( - Episode.builder() - .withId("1") - .withPatient("1") - .withPeriod(PeriodStart("2023-08-08")) - .build() - ) - .withClaims(null) - .withDiagnoses(null) - .withCarePlans(null) - .withClaimResponses(null) - .withEcogStatus(null) - .withFamilyMemberDiagnoses(null) - .withGeneticCounsellingRequests(null) - .withHistologyReevaluationRequests(null) - .withHistologyReports(null) - .withLastGuidelineTherapies(null) - .withMolecularPathologyFindings(null) - .withMolecularTherapies(null) - .withNgsReports(null) - .withPreviousGuidelineTherapies(null) - .withRebiopsyRequests(null) - .withRecommendations(null) - .withResponses(null) - .withStudyInclusionRequests(null) - .withSpecimens(null) - .build() - - mtbFile.pseudonymizeWith(pseudonymizeService) - mtbFile.anonymizeContentWith(pseudonymizeService) - - assertThat(mtbFile.episode.id).isNotNull() - } - } - @Nested inner class UsingDnpmV2Datamodel { @@ -251,7 +83,7 @@ class ExtensionsTest { private fun addConsentData(mtbFile: Mtb) { val gIcsConfigProperties = GIcsConfigProperties("", "", "") - val appConfigProperties = AppConfigProperties(null, emptyList()) + val appConfigProperties = AppConfigProperties(emptyList()) val bundle = Bundle() val dummyConsent = ConsentProcessorTest.getDummyGenomDeConsent() diff --git a/src/test/kotlin/dev/dnpm/etl/processor/pseudonym/PseudonymizeServiceTest.kt b/src/test/kotlin/dev/dnpm/etl/processor/pseudonym/PseudonymizeServiceTest.kt index 819454f..8ee19bc 100644 --- a/src/test/kotlin/dev/dnpm/etl/processor/pseudonym/PseudonymizeServiceTest.kt +++ b/src/test/kotlin/dev/dnpm/etl/processor/pseudonym/PseudonymizeServiceTest.kt @@ -19,8 +19,8 @@ package dev.dnpm.etl.processor.pseudonym -import de.ukw.ccc.bwhc.dto.* import dev.dnpm.etl.processor.config.PseudonymizeConfigProperties +import dev.pcvolkmer.mv64e.mtb.* import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @@ -29,31 +29,26 @@ import org.mockito.Mock import org.mockito.junit.jupiter.MockitoExtension import org.mockito.kotlin.doAnswer import org.mockito.kotlin.whenever +import java.time.Instant +import java.util.* @ExtendWith(MockitoExtension::class) class PseudonymizeServiceTest { - private val mtbFile = MtbFile.builder() - .withPatient( + private val mtbFile = Mtb.builder() + .patient( Patient.builder() - .withId("123") - .withBirthDate("2000-08-08") - .withGender(Patient.Gender.MALE) + .id("123") .build() ) - .withConsent( - Consent.builder() - .withId("1") - .withStatus(Consent.Status.ACTIVE) - .withPatient("123") - .build() - ) - .withEpisode( - Episode.builder() - .withId("1") - .withPatient("123") - .withPeriod(PeriodStart("2023-08-08")) - .build() + .episodesOfCare( + listOf( + MtbEpisodeOfCare.builder() + .id("1") + .patient(Reference.builder().id("123").build()) + .period(PeriodDate.builder().start(Date.from(Instant.parse("2021-01-01T00:00:00.00Z"))).build()) + .build() + ) ) .build() @@ -102,4 +97,4 @@ class PseudonymizeServiceTest { assertThat(tans.add(tan)).`as`("never the same result!").isTrue } } -} \ No newline at end of file +} diff --git a/src/test/kotlin/dev/dnpm/etl/processor/services/ConsentProcessorTest.kt b/src/test/kotlin/dev/dnpm/etl/processor/services/ConsentProcessorTest.kt index 38ce0b3..af93f7b 100644 --- a/src/test/kotlin/dev/dnpm/etl/processor/services/ConsentProcessorTest.kt +++ b/src/test/kotlin/dev/dnpm/etl/processor/services/ConsentProcessorTest.kt @@ -51,7 +51,7 @@ class ConsentProcessorTest { this.objectMapper = jacksonConfig.objectMapper() this.fhirContext = JacksonConfig.fhirContext() this.gicsConsentService = gicsConsentService - this.appConfigProperties = AppConfigProperties(null, emptyList()) + this.appConfigProperties = AppConfigProperties(emptyList()) this.consentProcessor = ConsentProcessor( appConfigProperties, @@ -168,4 +168,4 @@ class ConsentProcessorTest { .parseResource(Bundle::class.java, bundle) } -} \ No newline at end of file +} diff --git a/src/test/kotlin/dev/dnpm/etl/processor/services/RequestProcessorTest.kt b/src/test/kotlin/dev/dnpm/etl/processor/services/RequestProcessorTest.kt index b36c696..0a42b9b 100644 --- a/src/test/kotlin/dev/dnpm/etl/processor/services/RequestProcessorTest.kt +++ b/src/test/kotlin/dev/dnpm/etl/processor/services/RequestProcessorTest.kt @@ -20,22 +20,21 @@ package dev.dnpm.etl.processor.services import com.fasterxml.jackson.databind.ObjectMapper -import de.ukw.ccc.bwhc.dto.* import dev.dnpm.etl.processor.Fingerprint import dev.dnpm.etl.processor.PatientId import dev.dnpm.etl.processor.PatientPseudonym import dev.dnpm.etl.processor.config.AppConfigProperties -import dev.dnpm.etl.processor.consent.GicsConsentService import dev.dnpm.etl.processor.consent.TtpConsentStatus import dev.dnpm.etl.processor.monitoring.Request import dev.dnpm.etl.processor.monitoring.RequestStatus import dev.dnpm.etl.processor.monitoring.RequestType -import dev.dnpm.etl.processor.output.BwhcV1MtbFileRequest import dev.dnpm.etl.processor.output.DeleteRequest +import dev.dnpm.etl.processor.output.DnpmV2MtbFileRequest import dev.dnpm.etl.processor.output.MtbFileSender import dev.dnpm.etl.processor.output.RestMtbFileSender import dev.dnpm.etl.processor.pseudonym.PseudonymizeService import dev.dnpm.etl.processor.randomRequestId +import dev.pcvolkmer.mv64e.mtb.* import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test @@ -49,6 +48,7 @@ import org.mockito.kotlin.argumentCaptor import org.mockito.kotlin.whenever import org.springframework.context.ApplicationEventPublisher import java.time.Instant +import java.util.* @ExtendWith(MockitoExtension::class) @@ -77,7 +77,7 @@ class RequestProcessorTest { this.sender = sender this.requestService = requestService this.applicationEventPublisher = applicationEventPublisher - this.appConfigProperties = AppConfigProperties(null) + this.appConfigProperties = AppConfigProperties() this.consentProcessor = consentProcessor val objectMapper = ObjectMapper() @@ -102,7 +102,7 @@ class RequestProcessorTest { randomRequestId(), PatientPseudonym("TEST_12345678901"), PatientId("P1"), - Fingerprint("zdlzv5s5ydmd4ktw2v5piohegc4jcyrm6j66bq6tv2uxuerndmga"), + Fingerprint("6vkiti5bk6ikwifpajpt7cygmd3dvw54d6lwfhzlynb3pqtzferq"), RequestType.MTB_FILE, RequestStatus.SUCCESS, Instant.parse("2023-08-08T02:00:00Z") @@ -119,29 +119,24 @@ class RequestProcessorTest { doAnswer { it.arguments[0] - }.whenever(transformationService).transform(any()) + }.whenever(transformationService).transform(any()) - val mtbFile = MtbFile.builder() - .withPatient( + whenever(consentProcessor.consentGatedCheckAndTryEmbedding(any())).thenReturn(true) + + val mtbFile = Mtb.builder() + .patient( Patient.builder() - .withId("1") - .withBirthDate("2000-08-08") - .withGender(Patient.Gender.MALE) + .id("123") .build() ) - .withConsent( - Consent.builder() - .withId("1") - .withStatus(Consent.Status.ACTIVE) - .withPatient("123") - .build() - ) - .withEpisode( - Episode.builder() - .withId("1") - .withPatient("1") - .withPeriod(PeriodStart("2023-08-08")) - .build() + .episodesOfCare( + listOf( + MtbEpisodeOfCare.builder() + .id("1") + .patient(Reference.builder().id("123").build()) + .period(PeriodDate.builder().start(Date.from(Instant.parse("2023-08-08T02:00:00.00Z"))).build()) + .build() + ) ) .build() @@ -161,7 +156,7 @@ class RequestProcessorTest { randomRequestId(), PatientPseudonym("TEST_12345678901"), PatientId("P1"), - Fingerprint("zdlzv5s5ydmd4ktw2v5piohegc4jcyrm6j66bq6tv2uxuerndmga"), + Fingerprint("4gcjwtjjtcczybsljxepdfpkaeusvd7g3vogfqpmphyffyzfx7dq"), RequestType.MTB_FILE, RequestStatus.SUCCESS, Instant.parse("2023-08-08T02:00:00Z") @@ -178,29 +173,24 @@ class RequestProcessorTest { doAnswer { it.arguments[0] - }.whenever(transformationService).transform(any()) + }.whenever(transformationService).transform(any()) + + whenever(consentProcessor.consentGatedCheckAndTryEmbedding(any())).thenReturn(true) - val mtbFile = MtbFile.builder() - .withPatient( + val mtbFile = Mtb.builder() + .patient( Patient.builder() - .withId("1") - .withBirthDate("2000-08-08") - .withGender(Patient.Gender.MALE) + .id("123") .build() ) - .withConsent( - Consent.builder() - .withId("1") - .withStatus(Consent.Status.ACTIVE) - .withPatient("123") - .build() - ) - .withEpisode( - Episode.builder() - .withId("1") - .withPatient("1") - .withPeriod(PeriodStart("2023-08-08")) - .build() + .episodesOfCare( + listOf( + MtbEpisodeOfCare.builder() + .id("1") + .patient(Reference.builder().id("123").build()) + .period(PeriodDate.builder().start(Date.from(Instant.parse("2021-01-01T00:00:00.00Z"))).build()) + .build() + ) ) .build() @@ -233,7 +223,7 @@ class RequestProcessorTest { doAnswer { MtbFileSender.Response(status = RequestStatus.SUCCESS) - }.whenever(sender).send(any()) + }.whenever(sender).send(any()) doAnswer { it.arguments[0] as String @@ -241,29 +231,24 @@ class RequestProcessorTest { doAnswer { it.arguments[0] - }.whenever(transformationService).transform(any()) + }.whenever(transformationService).transform(any()) + + whenever(consentProcessor.consentGatedCheckAndTryEmbedding(any())).thenReturn(true) - val mtbFile = MtbFile.builder() - .withPatient( + val mtbFile = Mtb.builder() + .patient( Patient.builder() - .withId("1") - .withBirthDate("2000-08-08") - .withGender(Patient.Gender.MALE) + .id("123") .build() ) - .withConsent( - Consent.builder() - .withId("1") - .withStatus(Consent.Status.ACTIVE) - .withPatient("123") - .build() - ) - .withEpisode( - Episode.builder() - .withId("1") - .withPatient("1") - .withPeriod(PeriodStart("2023-08-08")) - .build() + .episodesOfCare( + listOf( + MtbEpisodeOfCare.builder() + .id("1") + .patient(Reference.builder().id("123").build()) + .period(PeriodDate.builder().start(Date.from(Instant.parse("2021-01-01T00:00:00.00Z"))).build()) + .build() + ) ) .build() @@ -296,7 +281,7 @@ class RequestProcessorTest { doAnswer { MtbFileSender.Response(status = RequestStatus.ERROR) - }.whenever(sender).send(any()) + }.whenever(sender).send(any()) doAnswer { it.arguments[0] as String @@ -304,29 +289,36 @@ class RequestProcessorTest { doAnswer { it.arguments[0] - }.whenever(transformationService).transform(any()) + }.whenever(transformationService).transform(any()) - val mtbFile = MtbFile.builder() - .withPatient( + whenever(consentProcessor.consentGatedCheckAndTryEmbedding(any())).thenReturn(true) + + val mtbFile = Mtb.builder() + .patient( Patient.builder() - .withId("1") - .withBirthDate("2000-08-08") - .withGender(Patient.Gender.MALE) + .id("123") .build() ) - .withConsent( - Consent.builder() - .withId("1") - .withStatus(Consent.Status.ACTIVE) - .withPatient("123") + .metadata( + MvhMetadata + .builder() + .modelProjectConsent( + ModelProjectConsent + .builder() + .provisions( + listOf(Provision.builder().type(ConsentProvision.PERMIT).purpose(ModelProjectConsentPurpose.SEQUENCING).build()) + ).build() + ) .build() ) - .withEpisode( - Episode.builder() - .withId("1") - .withPatient("1") - .withPeriod(PeriodStart("2023-08-08")) - .build() + .episodesOfCare( + listOf( + MtbEpisodeOfCare.builder() + .id("1") + .patient(Reference.builder().id("123").build()) + .period(PeriodDate.builder().start(Date.from(Instant.parse("2021-01-01T00:00:00.00Z"))).build()) + .build() + ) ) .build() @@ -426,33 +418,28 @@ class RequestProcessorTest { doAnswer { it.arguments[0] - }.whenever(transformationService).transform(any()) + }.whenever(transformationService).transform(any()) doAnswer { MtbFileSender.Response(status = RequestStatus.SUCCESS) - }.whenever(sender).send(any()) + }.whenever(sender).send(any()) - val mtbFile = MtbFile.builder() - .withPatient( + whenever(consentProcessor.consentGatedCheckAndTryEmbedding(any())).thenReturn(true) + + val mtbFile = Mtb.builder() + .patient( Patient.builder() - .withId("1") - .withBirthDate("2000-08-08") - .withGender(Patient.Gender.MALE) - .build() - ) - .withConsent( - Consent.builder() - .withId("1") - .withStatus(Consent.Status.ACTIVE) - .withPatient("123") + .id("123") .build() ) - .withEpisode( - Episode.builder() - .withId("1") - .withPatient("1") - .withPeriod(PeriodStart("2023-08-08")) - .build() + .episodesOfCare( + listOf( + MtbEpisodeOfCare.builder() + .id("1") + .patient(Reference.builder().id("123").build()) + .period(PeriodDate.builder().start(Date.from(Instant.parse("2021-01-01T00:00:00.00Z"))).build()) + .build() + ) ) .build() diff --git a/src/test/kotlin/dev/dnpm/etl/processor/services/TransformationServiceTest.kt b/src/test/kotlin/dev/dnpm/etl/processor/services/TransformationServiceTest.kt index 113245a..4a2d2d3 100644 --- a/src/test/kotlin/dev/dnpm/etl/processor/services/TransformationServiceTest.kt +++ b/src/test/kotlin/dev/dnpm/etl/processor/services/TransformationServiceTest.kt @@ -19,20 +19,11 @@ package dev.dnpm.etl.processor.services -import de.ukw.ccc.bwhc.dto.Consent -import de.ukw.ccc.bwhc.dto.Diagnosis -import de.ukw.ccc.bwhc.dto.Icd10 -import de.ukw.ccc.bwhc.dto.MtbFile import dev.dnpm.etl.processor.config.JacksonConfig -import dev.pcvolkmer.mv64e.mtb.ConsentProvision -import dev.pcvolkmer.mv64e.mtb.ModelProjectConsent -import dev.pcvolkmer.mv64e.mtb.ModelProjectConsentPurpose +import dev.pcvolkmer.mv64e.mtb.* import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test -import dev.pcvolkmer.mv64e.mtb.Mtb -import dev.pcvolkmer.mv64e.mtb.MvhMetadata -import dev.pcvolkmer.mv64e.mtb.Provision import org.hl7.fhir.instance.model.api.IBaseResource import java.time.Instant import java.util.Date @@ -45,82 +36,59 @@ class TransformationServiceTest { fun setup() { this.service = TransformationService( JacksonConfig().objectMapper(), listOf( - Transformation.of("consent.status") from Consent.Status.ACTIVE to Consent.Status.REJECTED, - Transformation.of("diagnoses[*].icd10.version") from "2013" to "2014", + Transformation.of("diagnoses[*].code.version") from "2013" to "2014", ) ) } @Test fun shouldTransformMtbFile() { - val mtbFile = MtbFile.builder().withDiagnoses( + val mtbFile = Mtb.builder().diagnoses( listOf( - Diagnosis.builder().withId("1234").withIcd10(Icd10("F79.9").also { - it.version = "2013" - }).build() + MtbDiagnosis.builder().id("1234").code(Coding.builder().code("F79.9").version("2013").build()).build() ) ).build() val actual = this.service.transform(mtbFile) assertThat(actual).isNotNull - assertThat(actual.diagnoses[0].icd10.version).isEqualTo("2014") + assertThat(actual.diagnoses[0].code.version).isEqualTo("2014") } @Test fun shouldOnlyTransformGivenValues() { - val mtbFile = MtbFile.builder().withDiagnoses( + val mtbFile = Mtb.builder().diagnoses( listOf( - Diagnosis.builder().withId("1234").withIcd10(Icd10("F79.9").also { - it.version = "2013" - }).build(), - Diagnosis.builder().withId("5678").withIcd10(Icd10("F79.8").also { - it.version = "2019" - }).build() + MtbDiagnosis.builder().id("1234").code(Coding.builder().code("F79.9").version("2013").build()).build(), + MtbDiagnosis.builder().id("1234").code(Coding.builder().code("F79.8").version("2019").build()).build() ) ).build() val actual = this.service.transform(mtbFile) assertThat(actual).isNotNull - assertThat(actual.diagnoses[0].icd10.code).isEqualTo("F79.9") - assertThat(actual.diagnoses[0].icd10.version).isEqualTo("2014") - assertThat(actual.diagnoses[1].icd10.code).isEqualTo("F79.8") - assertThat(actual.diagnoses[1].icd10.version).isEqualTo("2019") - } - - @Test - fun shouldTransformMtbFileWithConsentEnum() { - val mtbFile = MtbFile.builder().withConsent( - Consent("123", "456", Consent.Status.ACTIVE) - ).build() - - val actual = this.service.transform(mtbFile) - - assertThat(actual.consent).isNotNull - assertThat(actual.consent.status).isEqualTo(Consent.Status.REJECTED) + assertThat(actual.diagnoses[0].code.code).isEqualTo("F79.9") + assertThat(actual.diagnoses[0].code.version).isEqualTo("2014") + assertThat(actual.diagnoses[1].code.code).isEqualTo("F79.8") + assertThat(actual.diagnoses[1].code.version).isEqualTo("2019") } @Test fun shouldTransformConsentValues() { - val mtbFile = MtbFile.builder().withDiagnoses( + val mtbFile = Mtb.builder().diagnoses( listOf( - Diagnosis.builder().withId("1234").withIcd10(Icd10("F79.9").also { - it.version = "2013" - }).build(), - Diagnosis.builder().withId("5678").withIcd10(Icd10("F79.8").also { - it.version = "2019" - }).build() + MtbDiagnosis.builder().id("1234").code(Coding.builder().code("F79.9").version("2013").build()).build(), + MtbDiagnosis.builder().id("1234").code(Coding.builder().code("F79.8").version("2019").build()).build() ) ).build() val actual = this.service.transform(mtbFile) assertThat(actual).isNotNull - assertThat(actual.diagnoses[0].icd10.code).isEqualTo("F79.9") - assertThat(actual.diagnoses[0].icd10.version).isEqualTo("2014") - assertThat(actual.diagnoses[1].icd10.code).isEqualTo("F79.8") - assertThat(actual.diagnoses[1].icd10.version).isEqualTo("2019") + assertThat(actual.diagnoses[0].code.code).isEqualTo("F79.9") + assertThat(actual.diagnoses[0].code.version).isEqualTo("2014") + assertThat(actual.diagnoses[1].code.code).isEqualTo("F79.8") + assertThat(actual.diagnoses[1].code.version).isEqualTo("2019") } @Test @@ -155,5 +123,4 @@ class TransformationServiceTest { } - -} \ No newline at end of file +} -- cgit v1.2.3