diff --git a/src/integrationTest/kotlin/dev/dnpm/etl/processor/helpers.kt b/src/integrationTest/kotlin/dev/dnpm/etl/processor/helpers.kt new file mode 100644 index 0000000..6ca420f --- /dev/null +++ b/src/integrationTest/kotlin/dev/dnpm/etl/processor/helpers.kt @@ -0,0 +1,30 @@ +/* + * This file is part of ETL-Processor + * + * Copyright (c) 2024 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 + +import org.mockito.ArgumentMatchers + +@Suppress("UNCHECKED_CAST") +inline fun anyValueClass(): T { + val unboxedClass = T::class.java.declaredFields.first().type + return ArgumentMatchers.any(unboxedClass as Class) + ?: T::class.java.getDeclaredMethod("box-impl", unboxedClass) + .invoke(null, null) as T +} \ No newline at end of file diff --git a/src/integrationTest/kotlin/dev/dnpm/etl/processor/input/MtbFileRestControllerTest.kt b/src/integrationTest/kotlin/dev/dnpm/etl/processor/input/MtbFileRestControllerTest.kt index 521ec52..670020f 100644 --- a/src/integrationTest/kotlin/dev/dnpm/etl/processor/input/MtbFileRestControllerTest.kt +++ b/src/integrationTest/kotlin/dev/dnpm/etl/processor/input/MtbFileRestControllerTest.kt @@ -21,6 +21,7 @@ package dev.dnpm.etl.processor.input import com.fasterxml.jackson.databind.ObjectMapper import de.ukw.ccc.bwhc.dto.* +import dev.dnpm.etl.processor.anyValueClass import dev.dnpm.etl.processor.config.AppSecurityConfiguration import dev.dnpm.etl.processor.security.TokenRepository import dev.dnpm.etl.processor.security.UserRoleRepository @@ -29,7 +30,6 @@ 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.mockito.ArgumentMatchers.anyString import org.mockito.junit.jupiter.MockitoExtension import org.mockito.kotlin.any import org.mockito.kotlin.never @@ -141,7 +141,7 @@ class MtbFileRestControllerTest { status { isAccepted() } } - verify(requestProcessor, times(1)).processDeletion(anyString()) + verify(requestProcessor, times(1)).processDeletion(anyValueClass()) } @Test @@ -152,7 +152,7 @@ class MtbFileRestControllerTest { status { isUnauthorized() } } - verify(requestProcessor, never()).processDeletion(anyString()) + verify(requestProcessor, never()).processDeletion(anyValueClass()) } @Nested diff --git a/src/integrationTest/kotlin/dev/dnpm/etl/processor/monitoring/RequestRepositoryTest.kt b/src/integrationTest/kotlin/dev/dnpm/etl/processor/monitoring/RequestRepositoryTest.kt index 231fffe..bef124c 100644 --- a/src/integrationTest/kotlin/dev/dnpm/etl/processor/monitoring/RequestRepositoryTest.kt +++ b/src/integrationTest/kotlin/dev/dnpm/etl/processor/monitoring/RequestRepositoryTest.kt @@ -19,10 +19,8 @@ package dev.dnpm.etl.processor.monitoring -import dev.dnpm.etl.processor.AbstractTestcontainerTest -import dev.dnpm.etl.processor.Fingerprint +import dev.dnpm.etl.processor.* import dev.dnpm.etl.processor.output.MtbFileSender -import dev.dnpm.etl.processor.randomRequestId import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @@ -63,8 +61,8 @@ class RequestRepositoryTest : AbstractTestcontainerTest() { fun shouldSaveRequest() { val request = Request( randomRequestId(), - "TEST_12345678901", - "P1", + PatientPseudonym("TEST_12345678901"), + PatientId("P1"), Fingerprint("0123456789abcdef1"), RequestType.MTB_FILE, RequestStatus.WARNING, diff --git a/src/integrationTest/kotlin/dev/dnpm/etl/processor/services/RequestServiceIntegrationTest.kt b/src/integrationTest/kotlin/dev/dnpm/etl/processor/services/RequestServiceIntegrationTest.kt index 1aac5fd..47ac301 100644 --- a/src/integrationTest/kotlin/dev/dnpm/etl/processor/services/RequestServiceIntegrationTest.kt +++ b/src/integrationTest/kotlin/dev/dnpm/etl/processor/services/RequestServiceIntegrationTest.kt @@ -19,14 +19,12 @@ package dev.dnpm.etl.processor.services -import dev.dnpm.etl.processor.AbstractTestcontainerTest -import dev.dnpm.etl.processor.Fingerprint +import dev.dnpm.etl.processor.* import dev.dnpm.etl.processor.monitoring.Request import dev.dnpm.etl.processor.monitoring.RequestRepository import dev.dnpm.etl.processor.monitoring.RequestStatus import dev.dnpm.etl.processor.monitoring.RequestType import dev.dnpm.etl.processor.output.MtbFileSender -import dev.dnpm.etl.processor.randomRequestId import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test @@ -67,7 +65,7 @@ class RequestServiceIntegrationTest : AbstractTestcontainerTest() { @Test fun shouldResultInEmptyRequestList() { - val actual = requestService.allRequestsByPatientPseudonym("TEST_12345678901") + val actual = requestService.allRequestsByPatientPseudonym(TEST_PATIENT_PSEUDONYM) assertThat(actual).isEmpty() } @@ -78,8 +76,8 @@ class RequestServiceIntegrationTest : AbstractTestcontainerTest() { listOf( Request( randomRequestId(), - "TEST_12345678901", - "P1", + PatientPseudonym("TEST_12345678901"), + PatientId("P1"), Fingerprint("0123456789abcdef1"), RequestType.MTB_FILE, RequestStatus.SUCCESS, @@ -88,8 +86,8 @@ class RequestServiceIntegrationTest : AbstractTestcontainerTest() { // Should be ignored - wrong patient ID --> Request( randomRequestId(), - "TEST_12345678902", - "P2", + PatientPseudonym("TEST_12345678902"), + PatientId("P2"), Fingerprint("0123456789abcdef2"), RequestType.MTB_FILE, RequestStatus.WARNING, @@ -98,8 +96,8 @@ class RequestServiceIntegrationTest : AbstractTestcontainerTest() { // <-- Request( randomRequestId(), - "TEST_12345678901", - "P2", + PatientPseudonym("TEST_12345678901"), + PatientId("P2"), Fingerprint("0123456789abcdee1"), RequestType.DELETE, RequestStatus.SUCCESS, @@ -113,7 +111,7 @@ class RequestServiceIntegrationTest : AbstractTestcontainerTest() { fun shouldResultInSortedRequestList() { setupTestData() - val actual = requestService.allRequestsByPatientPseudonym("TEST_12345678901") + val actual = requestService.allRequestsByPatientPseudonym(TEST_PATIENT_PSEUDONYM) assertThat(actual).hasSize(2) assertThat(actual[0].fingerprint).isEqualTo(Fingerprint("0123456789abcdee1")) @@ -124,7 +122,7 @@ class RequestServiceIntegrationTest : AbstractTestcontainerTest() { fun shouldReturnDeleteRequestAsLastRequest() { setupTestData() - val actual = requestService.isLastRequestWithKnownStatusDeletion("TEST_12345678901") + val actual = requestService.isLastRequestWithKnownStatusDeletion(TEST_PATIENT_PSEUDONYM) assertThat(actual).isTrue() } @@ -133,10 +131,14 @@ class RequestServiceIntegrationTest : AbstractTestcontainerTest() { fun shouldReturnLastMtbFileRequest() { setupTestData() - val actual = requestService.lastMtbFileRequestForPatientPseudonym("TEST_12345678901") + val actual = requestService.lastMtbFileRequestForPatientPseudonym(TEST_PATIENT_PSEUDONYM) assertThat(actual).isNotNull assertThat(actual?.fingerprint).isEqualTo(Fingerprint("0123456789abcdef1")) } + companion object { + val TEST_PATIENT_PSEUDONYM = PatientPseudonym("TEST_12345678901") + } + } \ No newline at end of file diff --git a/src/integrationTest/kotlin/dev/dnpm/etl/processor/web/HomeControllerTest.kt b/src/integrationTest/kotlin/dev/dnpm/etl/processor/web/HomeControllerTest.kt index a5d8771..80c17d2 100644 --- a/src/integrationTest/kotlin/dev/dnpm/etl/processor/web/HomeControllerTest.kt +++ b/src/integrationTest/kotlin/dev/dnpm/etl/processor/web/HomeControllerTest.kt @@ -21,15 +21,13 @@ package dev.dnpm.etl.processor.web import com.gargoylesoftware.htmlunit.WebClient import com.gargoylesoftware.htmlunit.html.HtmlPage -import dev.dnpm.etl.processor.Fingerprint -import dev.dnpm.etl.processor.NotFoundException +import dev.dnpm.etl.processor.* import dev.dnpm.etl.processor.config.AppConfiguration import dev.dnpm.etl.processor.config.AppSecurityConfiguration import dev.dnpm.etl.processor.monitoring.Report 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.randomRequestId import dev.dnpm.etl.processor.services.RequestService import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.BeforeEach @@ -37,8 +35,6 @@ import org.junit.jupiter.api.Nested import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows import org.junit.jupiter.api.extension.ExtendWith -import org.mockito.ArgumentMatchers -import org.mockito.ArgumentMatchers.anyString import org.mockito.junit.jupiter.MockitoExtension import org.mockito.kotlin.any import org.mockito.kotlin.whenever @@ -83,13 +79,6 @@ class HomeControllerTest { private lateinit var mockMvc: MockMvc private lateinit var webClient: WebClient - inline fun anyValueClass(): T { - val unboxedClass = T::class.java.declaredFields.first().type - return ArgumentMatchers.any(unboxedClass as Class) - ?: T::class.java.getDeclaredMethod("box-impl", unboxedClass) - .invoke(null, null) as T - } - @BeforeEach fun setup( @Autowired mockMvc: MockMvc, @@ -129,8 +118,8 @@ class HomeControllerTest { Request( 2L, randomRequestId(), - "PSEUDO1", - "PATIENT1", + PatientPseudonym("PSEUDO1"), + PatientId("PATIENT1"), Fingerprint("ashdkasdh"), RequestType.MTB_FILE, RequestStatus.SUCCESS @@ -138,8 +127,8 @@ class HomeControllerTest { Request( 1L, randomRequestId(), - "PSEUDO1", - "PATIENT1", + PatientPseudonym("PSEUDO1"), + PatientId("PATIENT1"), Fingerprint("asdasdasd"), RequestType.MTB_FILE, RequestStatus.ERROR @@ -163,8 +152,8 @@ class HomeControllerTest { Request( 2L, requestId, - "PSEUDO1", - "PATIENT1", + PatientPseudonym("PSEUDO1"), + PatientId("PATIENT1"), Fingerprint("ashdkasdh"), RequestType.MTB_FILE, RequestStatus.SUCCESS, @@ -182,14 +171,14 @@ class HomeControllerTest { @Test @WithMockUser(username = "admin", roles = ["ADMIN"]) fun testShouldShowPatientDetails() { - whenever(requestService.findRequestByPatientId(anyString(), any())).thenReturn( + whenever(requestService.findRequestByPatientId(anyValueClass(), any())).thenReturn( PageImpl( listOf( Request( 2L, randomRequestId(), - "PSEUDO1", - "PATIENT1", + PatientPseudonym("PSEUDO1"), + PatientId("PATIENT1"), Fingerprint("ashdkasdh"), RequestType.MTB_FILE, RequestStatus.SUCCESS @@ -197,8 +186,8 @@ class HomeControllerTest { Request( 1L, randomRequestId(), - "PSEUDO1", - "PATIENT1", + PatientPseudonym("PSEUDO1"), + PatientId("PATIENT1"), Fingerprint("asdasdasd"), RequestType.MTB_FILE, RequestStatus.ERROR @@ -254,7 +243,7 @@ class HomeControllerTest { @Test @WithMockUser(username = "admin", roles = ["ADMIN"]) fun testShouldShowEmptyPatientDetails() { - whenever(requestService.findRequestByPatientId(anyString(), any())).thenReturn(Page.empty()) + whenever(requestService.findRequestByPatientId(anyValueClass(), any())).thenReturn(Page.empty()) val page = webClient.getPage("http://localhost/patient/PSEUDO1") assertThat(page.querySelectorAll("tbody tr")).isEmpty() diff --git a/src/integrationTest/kotlin/dev/dnpm/etl/processor/web/StatisticsRestControllerTest.kt b/src/integrationTest/kotlin/dev/dnpm/etl/processor/web/StatisticsRestControllerTest.kt index e66def7..b9a1338 100644 --- a/src/integrationTest/kotlin/dev/dnpm/etl/processor/web/StatisticsRestControllerTest.kt +++ b/src/integrationTest/kotlin/dev/dnpm/etl/processor/web/StatisticsRestControllerTest.kt @@ -20,6 +20,8 @@ package dev.dnpm.etl.processor.web import dev.dnpm.etl.processor.Fingerprint +import dev.dnpm.etl.processor.PatientId +import dev.dnpm.etl.processor.PatientPseudonym import dev.dnpm.etl.processor.config.AppConfiguration import dev.dnpm.etl.processor.config.AppSecurityConfiguration import dev.dnpm.etl.processor.monitoring.CountedState @@ -188,8 +190,8 @@ class StatisticsRestControllerTest { Request( 1, randomRequestId(), - "TEST_12345678901", - "P1", + PatientPseudonym("TEST_12345678901"), + PatientId("P1"), Fingerprint("0123456789abcdef1"), RequestType.MTB_FILE, RequestStatus.SUCCESS, @@ -198,8 +200,8 @@ class StatisticsRestControllerTest { Request( 2, randomRequestId(), - "TEST_12345678902", - "P2", + PatientPseudonym("TEST_12345678902"), + PatientId("P2"), Fingerprint("0123456789abcdef2"), RequestType.MTB_FILE, RequestStatus.WARNING, @@ -208,8 +210,8 @@ class StatisticsRestControllerTest { Request( 3, randomRequestId(), - "TEST_12345678901", - "P2", + PatientPseudonym("TEST_12345678901"), + PatientId("P2"), Fingerprint("0123456789abcdee1"), RequestType.DELETE, RequestStatus.ERROR, @@ -218,8 +220,8 @@ class StatisticsRestControllerTest { Request( 4, randomRequestId(), - "TEST_12345678902", - "P2", + PatientPseudonym("TEST_12345678902"), + PatientId("P2"), Fingerprint("0123456789abcdef2"), RequestType.MTB_FILE, RequestStatus.DUPLICATION, @@ -228,8 +230,8 @@ class StatisticsRestControllerTest { Request( 5, randomRequestId(), - "TEST_12345678902", - "P2", + PatientPseudonym("TEST_12345678902"), + PatientId("P2"), Fingerprint("0123456789abcdef2"), RequestType.DELETE, RequestStatus.UNKNOWN, diff --git a/src/main/kotlin/dev/dnpm/etl/processor/input/KafkaInputListener.kt b/src/main/kotlin/dev/dnpm/etl/processor/input/KafkaInputListener.kt index b72b1fd..2aff8cb 100644 --- a/src/main/kotlin/dev/dnpm/etl/processor/input/KafkaInputListener.kt +++ b/src/main/kotlin/dev/dnpm/etl/processor/input/KafkaInputListener.kt @@ -22,6 +22,7 @@ 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 dev.dnpm.etl.processor.PatientId import dev.dnpm.etl.processor.RequestId import dev.dnpm.etl.processor.services.RequestProcessor import org.apache.kafka.clients.consumer.ConsumerRecord @@ -36,6 +37,7 @@ class KafkaInputListener( override fun onMessage(data: ConsumerRecord) { val mtbFile = objectMapper.readValue(data.value(), MtbFile::class.java) + val patientId = PatientId(mtbFile.patient.id) val firstRequestIdHeader = data.headers().headers("requestId")?.firstOrNull() val requestId = if (null != firstRequestIdHeader) { RequestId(String(firstRequestIdHeader.value())) @@ -53,9 +55,9 @@ class KafkaInputListener( } else { logger.debug("Accepted MTB File and process deletion") if (requestId.isBlank()) { - requestProcessor.processDeletion(mtbFile.patient.id) + requestProcessor.processDeletion(patientId) } else { - requestProcessor.processDeletion(mtbFile.patient.id, requestId) + requestProcessor.processDeletion(patientId, requestId) } } } diff --git a/src/main/kotlin/dev/dnpm/etl/processor/input/MtbFileRestController.kt b/src/main/kotlin/dev/dnpm/etl/processor/input/MtbFileRestController.kt index 8259288..9e282c2 100644 --- a/src/main/kotlin/dev/dnpm/etl/processor/input/MtbFileRestController.kt +++ b/src/main/kotlin/dev/dnpm/etl/processor/input/MtbFileRestController.kt @@ -21,6 +21,7 @@ package dev.dnpm.etl.processor.input import de.ukw.ccc.bwhc.dto.Consent import de.ukw.ccc.bwhc.dto.MtbFile +import dev.dnpm.etl.processor.PatientId import dev.dnpm.etl.processor.services.RequestProcessor import org.slf4j.LoggerFactory import org.springframework.http.ResponseEntity @@ -46,7 +47,8 @@ class MtbFileRestController( requestProcessor.processMtbFile(mtbFile) } else { logger.debug("Accepted MTB File and process deletion") - requestProcessor.processDeletion(mtbFile.patient.id) + val patientId = PatientId(mtbFile.patient.id) + requestProcessor.processDeletion(patientId) } return ResponseEntity.accepted().build() } @@ -54,7 +56,7 @@ class MtbFileRestController( @DeleteMapping(path = ["{patientId}"]) fun deleteData(@PathVariable patientId: String): ResponseEntity { logger.debug("Accepted patient ID to process deletion") - requestProcessor.processDeletion(patientId) + requestProcessor.processDeletion(PatientId(patientId)) return ResponseEntity.accepted().build() } diff --git a/src/main/kotlin/dev/dnpm/etl/processor/monitoring/Request.kt b/src/main/kotlin/dev/dnpm/etl/processor/monitoring/Request.kt index 9efae4c..d26d222 100644 --- a/src/main/kotlin/dev/dnpm/etl/processor/monitoring/Request.kt +++ b/src/main/kotlin/dev/dnpm/etl/processor/monitoring/Request.kt @@ -19,9 +19,7 @@ package dev.dnpm.etl.processor.monitoring -import dev.dnpm.etl.processor.Fingerprint -import dev.dnpm.etl.processor.randomRequestId -import dev.dnpm.etl.processor.RequestId +import dev.dnpm.etl.processor.* import org.springframework.data.annotation.Id import org.springframework.data.domain.Page import org.springframework.data.domain.Pageable @@ -38,8 +36,8 @@ import java.util.* data class Request( @Id val id: Long? = null, val uuid: RequestId = randomRequestId(), - val patientId: String, - val pid: String, + val patientId: PatientPseudonym, + val pid: PatientId, @Column("fingerprint") val fingerprint: Fingerprint, val type: RequestType, @@ -49,8 +47,8 @@ data class Request( ) { constructor( uuid: RequestId, - patientId: String, - pid: String, + patientId: PatientPseudonym, + pid: PatientId, fingerprint: Fingerprint, type: RequestType, status: RequestStatus @@ -59,8 +57,8 @@ data class Request( constructor( uuid: RequestId, - patientId: String, - pid: String, + patientId: PatientPseudonym, + pid: PatientId, fingerprint: Fingerprint, type: RequestType, status: RequestStatus, @@ -83,11 +81,11 @@ data class CountedState( interface RequestRepository : CrudRepository, PagingAndSortingRepository { - fun findAllByPatientIdOrderByProcessedAtDesc(patientId: String): List + fun findAllByPatientIdOrderByProcessedAtDesc(patientId: PatientPseudonym): List fun findByUuidEquals(uuid: RequestId): Optional - fun findRequestByPatientId(patientId: String, pageable: Pageable): Page + fun findRequestByPatientId(patientId: PatientPseudonym, pageable: Pageable): Page @Query("SELECT count(*) AS count, status FROM request WHERE type = 'MTB_FILE' GROUP BY status ORDER BY status, count DESC;") fun countStates(): List diff --git a/src/main/kotlin/dev/dnpm/etl/processor/output/KafkaMtbFileSender.kt b/src/main/kotlin/dev/dnpm/etl/processor/output/KafkaMtbFileSender.kt index 7b777e8..4838689 100644 --- a/src/main/kotlin/dev/dnpm/etl/processor/output/KafkaMtbFileSender.kt +++ b/src/main/kotlin/dev/dnpm/etl/processor/output/KafkaMtbFileSender.kt @@ -63,7 +63,7 @@ class KafkaMtbFileSender( val dummyMtbFile = MtbFile.builder() .withConsent( Consent.builder() - .withPatient(request.patientId) + .withPatient(request.patientId.value) .withStatus(Consent.Status.REJECTED) .build() ) @@ -99,7 +99,7 @@ class KafkaMtbFileSender( } private fun key(request: MtbFileSender.DeleteRequest): String { - return "{\"pid\": \"${request.patientId}\"}" + return "{\"pid\": \"${request.patientId.value}\"}" } data class Data(val requestId: RequestId, val content: MtbFile) diff --git a/src/main/kotlin/dev/dnpm/etl/processor/output/MtbFileSender.kt b/src/main/kotlin/dev/dnpm/etl/processor/output/MtbFileSender.kt index 2670f2e..8d994c5 100644 --- a/src/main/kotlin/dev/dnpm/etl/processor/output/MtbFileSender.kt +++ b/src/main/kotlin/dev/dnpm/etl/processor/output/MtbFileSender.kt @@ -20,6 +20,7 @@ package dev.dnpm.etl.processor.output import de.ukw.ccc.bwhc.dto.MtbFile +import dev.dnpm.etl.processor.PatientPseudonym import dev.dnpm.etl.processor.RequestId import dev.dnpm.etl.processor.monitoring.RequestStatus import org.springframework.http.HttpStatusCode @@ -35,7 +36,7 @@ interface MtbFileSender { data class MtbFileRequest(val requestId: RequestId, val mtbFile: MtbFile) - data class DeleteRequest(val requestId: RequestId, val patientId: String) + data class DeleteRequest(val requestId: RequestId, val patientId: PatientPseudonym) } diff --git a/src/main/kotlin/dev/dnpm/etl/processor/pseudonym/PseudonymizeService.kt b/src/main/kotlin/dev/dnpm/etl/processor/pseudonym/PseudonymizeService.kt index d18cd2c..e80f6ec 100644 --- a/src/main/kotlin/dev/dnpm/etl/processor/pseudonym/PseudonymizeService.kt +++ b/src/main/kotlin/dev/dnpm/etl/processor/pseudonym/PseudonymizeService.kt @@ -19,6 +19,8 @@ package dev.dnpm.etl.processor.pseudonym +import dev.dnpm.etl.processor.PatientId +import dev.dnpm.etl.processor.PatientPseudonym import dev.dnpm.etl.processor.config.PseudonymizeConfigProperties class PseudonymizeService( @@ -26,10 +28,10 @@ class PseudonymizeService( private val configProperties: PseudonymizeConfigProperties ) { - fun patientPseudonym(patientId: String): String { + fun patientPseudonym(patientId: PatientId): PatientPseudonym { return when (generator) { - is GpasPseudonymGenerator -> generator.generate(patientId) - else -> "${configProperties.prefix}_${generator.generate(patientId)}" + is GpasPseudonymGenerator -> PatientPseudonym(generator.generate(patientId.value)) + else -> PatientPseudonym("${configProperties.prefix}_${generator.generate(patientId.value)}") } } diff --git a/src/main/kotlin/dev/dnpm/etl/processor/pseudonym/extensions.kt b/src/main/kotlin/dev/dnpm/etl/processor/pseudonym/extensions.kt index ef25787..bf645f6 100644 --- a/src/main/kotlin/dev/dnpm/etl/processor/pseudonym/extensions.kt +++ b/src/main/kotlin/dev/dnpm/etl/processor/pseudonym/extensions.kt @@ -20,6 +20,7 @@ package dev.dnpm.etl.processor.pseudonym import de.ukw.ccc.bwhc.dto.MtbFile +import dev.dnpm.etl.processor.PatientId import org.apache.commons.codec.digest.DigestUtils /** Replaces patient ID with generated patient pseudonym @@ -29,7 +30,7 @@ import org.apache.commons.codec.digest.DigestUtils * @return The MTB file containing patient pseudonymes */ infix fun MtbFile.pseudonymizeWith(pseudonymizeService: PseudonymizeService) { - val patientPseudonym = pseudonymizeService.patientPseudonym(this.patient.id) + val patientPseudonym = pseudonymizeService.patientPseudonym(PatientId(this.patient.id)).value this.episode?.patient = patientPseudonym this.carePlans?.forEach { it.patient = patientPseudonym } diff --git a/src/main/kotlin/dev/dnpm/etl/processor/services/RequestProcessor.kt b/src/main/kotlin/dev/dnpm/etl/processor/services/RequestProcessor.kt index 94598ae..2cbfd2f 100644 --- a/src/main/kotlin/dev/dnpm/etl/processor/services/RequestProcessor.kt +++ b/src/main/kotlin/dev/dnpm/etl/processor/services/RequestProcessor.kt @@ -21,9 +21,7 @@ package dev.dnpm.etl.processor.services import com.fasterxml.jackson.databind.ObjectMapper import de.ukw.ccc.bwhc.dto.MtbFile -import dev.dnpm.etl.processor.Fingerprint -import dev.dnpm.etl.processor.randomRequestId -import dev.dnpm.etl.processor.RequestId +import dev.dnpm.etl.processor.* import dev.dnpm.etl.processor.config.AppConfigProperties import dev.dnpm.etl.processor.monitoring.Report import dev.dnpm.etl.processor.monitoring.Request @@ -56,17 +54,19 @@ class RequestProcessor( } fun processMtbFile(mtbFile: MtbFile, requestId: RequestId) { - val pid = mtbFile.patient.id + val pid = PatientId(mtbFile.patient.id) mtbFile pseudonymizeWith pseudonymizeService mtbFile anonymizeContentWith pseudonymizeService val request = MtbFileSender.MtbFileRequest(requestId, transformationService.transform(mtbFile)) + val patientPseudonym = PatientPseudonym(request.mtbFile.patient.id) + requestService.save( Request( requestId, - request.mtbFile.patient.id, + patientPseudonym, pid, fingerprint(request.mtbFile), RequestType.MTB_FILE, @@ -101,20 +101,22 @@ class RequestProcessor( } private fun isDuplication(pseudonymizedMtbFile: MtbFile): Boolean { + val patientPseudonym = PatientPseudonym(pseudonymizedMtbFile.patient.id) + val lastMtbFileRequestForPatient = - requestService.lastMtbFileRequestForPatientPseudonym(pseudonymizedMtbFile.patient.id) - val isLastRequestDeletion = requestService.isLastRequestWithKnownStatusDeletion(pseudonymizedMtbFile.patient.id) + requestService.lastMtbFileRequestForPatientPseudonym(patientPseudonym) + val isLastRequestDeletion = requestService.isLastRequestWithKnownStatusDeletion(patientPseudonym) return null != lastMtbFileRequestForPatient && !isLastRequestDeletion && lastMtbFileRequestForPatient.fingerprint == fingerprint(pseudonymizedMtbFile) } - fun processDeletion(patientId: String) { + fun processDeletion(patientId: PatientId) { processDeletion(patientId, randomRequestId()) } - fun processDeletion(patientId: String, requestId: RequestId) { + fun processDeletion(patientId: PatientId, requestId: RequestId) { try { val patientPseudonym = pseudonymizeService.patientPseudonym(patientId) @@ -123,7 +125,7 @@ class RequestProcessor( requestId, patientPseudonym, patientId, - fingerprint(patientPseudonym), + fingerprint(patientPseudonym.value), RequestType.DELETE, RequestStatus.UNKNOWN ) @@ -147,7 +149,7 @@ class RequestProcessor( requestService.save( Request( uuid = requestId, - patientId = "???", + patientId = emptyPatientPseudonym(), pid = patientId, fingerprint = Fingerprint.empty(), status = RequestStatus.ERROR, diff --git a/src/main/kotlin/dev/dnpm/etl/processor/services/RequestService.kt b/src/main/kotlin/dev/dnpm/etl/processor/services/RequestService.kt index a2e8de3..826b060 100644 --- a/src/main/kotlin/dev/dnpm/etl/processor/services/RequestService.kt +++ b/src/main/kotlin/dev/dnpm/etl/processor/services/RequestService.kt @@ -19,6 +19,7 @@ package dev.dnpm.etl.processor.services +import dev.dnpm.etl.processor.PatientPseudonym import dev.dnpm.etl.processor.RequestId import dev.dnpm.etl.processor.monitoring.* import org.springframework.data.domain.Page @@ -40,15 +41,15 @@ class RequestService( fun findByUuid(uuid: RequestId): Optional = requestRepository.findByUuidEquals(uuid) - fun findRequestByPatientId(patientId: String, pageable: Pageable): Page = requestRepository.findRequestByPatientId(patientId, pageable) + fun findRequestByPatientId(patientId: PatientPseudonym, pageable: Pageable): Page = requestRepository.findRequestByPatientId(patientId, pageable) - fun allRequestsByPatientPseudonym(patientPseudonym: String) = requestRepository + fun allRequestsByPatientPseudonym(patientPseudonym: PatientPseudonym) = requestRepository .findAllByPatientIdOrderByProcessedAtDesc(patientPseudonym) - fun lastMtbFileRequestForPatientPseudonym(patientPseudonym: String) = + fun lastMtbFileRequestForPatientPseudonym(patientPseudonym: PatientPseudonym) = Companion.lastMtbFileRequestForPatientPseudonym(allRequestsByPatientPseudonym(patientPseudonym)) - fun isLastRequestWithKnownStatusDeletion(patientPseudonym: String) = + fun isLastRequestWithKnownStatusDeletion(patientPseudonym: PatientPseudonym) = Companion.isLastRequestWithKnownStatusDeletion(allRequestsByPatientPseudonym(patientPseudonym)) fun countStates(): Iterable = requestRepository.countStates() diff --git a/src/main/kotlin/dev/dnpm/etl/processor/types.kt b/src/main/kotlin/dev/dnpm/etl/processor/types.kt index b41a550..b2f13ef 100644 --- a/src/main/kotlin/dev/dnpm/etl/processor/types.kt +++ b/src/main/kotlin/dev/dnpm/etl/processor/types.kt @@ -38,4 +38,12 @@ value class RequestId(val value: String) { } -fun randomRequestId() = RequestId(UUID.randomUUID().toString()) \ No newline at end of file +fun randomRequestId() = RequestId(UUID.randomUUID().toString()) + +@JvmInline +value class PatientId(val value: String) + +@JvmInline +value class PatientPseudonym(val value: String) + +fun emptyPatientPseudonym() = PatientPseudonym("") \ No newline at end of file diff --git a/src/main/kotlin/dev/dnpm/etl/processor/web/HomeController.kt b/src/main/kotlin/dev/dnpm/etl/processor/web/HomeController.kt index ac003d3..43f2f1d 100644 --- a/src/main/kotlin/dev/dnpm/etl/processor/web/HomeController.kt +++ b/src/main/kotlin/dev/dnpm/etl/processor/web/HomeController.kt @@ -20,6 +20,7 @@ package dev.dnpm.etl.processor.web import dev.dnpm.etl.processor.NotFoundException +import dev.dnpm.etl.processor.PatientPseudonym import dev.dnpm.etl.processor.RequestId import dev.dnpm.etl.processor.monitoring.ReportService import dev.dnpm.etl.processor.services.RequestService @@ -56,7 +57,7 @@ class HomeController( @PageableDefault(page = 0, size = 20, sort = ["processedAt"], direction = Sort.Direction.DESC) pageable: Pageable, model: Model ): String { - val requests = requestService.findRequestByPatientId(patientId, pageable) + val requests = requestService.findRequestByPatientId(PatientPseudonym(patientId), pageable) model.addAttribute("patientId", patientId) model.addAttribute("requests", requests) 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 58c78e4..7753dbc 100644 --- a/src/test/kotlin/dev/dnpm/etl/processor/input/KafkaInputListenerTest.kt +++ b/src/test/kotlin/dev/dnpm/etl/processor/input/KafkaInputListenerTest.kt @@ -32,7 +32,6 @@ import org.apache.kafka.common.record.TimestampType import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith -import org.mockito.ArgumentMatchers.anyString import org.mockito.Mock import org.mockito.junit.jupiter.MockitoExtension import org.mockito.kotlin.any @@ -78,7 +77,7 @@ class KafkaInputListenerTest { kafkaInputListener.onMessage(ConsumerRecord("testtopic", 0, 0, "", this.objectMapper.writeValueAsString(mtbFile))) - verify(requestProcessor, times(1)).processDeletion(anyString()) + verify(requestProcessor, times(1)).processDeletion(anyValueClass()) } @Test @@ -107,7 +106,7 @@ class KafkaInputListenerTest { kafkaInputListener.onMessage( ConsumerRecord("testtopic", 0, 0, -1L, TimestampType.NO_TIMESTAMP_TYPE, -1, -1, "", this.objectMapper.writeValueAsString(mtbFile), headers, Optional.empty()) ) - verify(requestProcessor, times(1)).processDeletion(anyString(), anyValueClass()) + verify(requestProcessor, times(1)).processDeletion(anyValueClass(), anyValueClass()) } } \ No newline at end of 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 0b076a1..f9fe3f3 100644 --- a/src/test/kotlin/dev/dnpm/etl/processor/input/MtbFileRestControllerTest.kt +++ b/src/test/kotlin/dev/dnpm/etl/processor/input/MtbFileRestControllerTest.kt @@ -21,8 +21,8 @@ package dev.dnpm.etl.processor.input import com.fasterxml.jackson.databind.ObjectMapper import de.ukw.ccc.bwhc.dto.* +import dev.dnpm.etl.processor.anyValueClass import dev.dnpm.etl.processor.services.RequestProcessor -import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @@ -31,7 +31,6 @@ 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.argumentCaptor import org.springframework.http.MediaType import org.springframework.test.web.servlet.MockMvc import org.springframework.test.web.servlet.delete @@ -129,9 +128,7 @@ class MtbFileRestControllerTest { } } - val captor = argumentCaptor() - verify(requestProcessor, times(1)).processDeletion(captor.capture()) - assertThat(captor.firstValue).isEqualTo("TEST_12345678") + verify(requestProcessor, times(1)).processDeletion(anyValueClass()) } @Test @@ -142,9 +139,7 @@ class MtbFileRestControllerTest { } } - val captor = argumentCaptor() - verify(requestProcessor, times(1)).processDeletion(captor.capture()) - assertThat(captor.firstValue).isEqualTo("TEST_12345678") + verify(requestProcessor, times(1)).processDeletion(anyValueClass()) } } \ No newline at end of file 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 b943f5f..655e29e 100644 --- a/src/test/kotlin/dev/dnpm/etl/processor/output/KafkaMtbFileSenderTest.kt +++ b/src/test/kotlin/dev/dnpm/etl/processor/output/KafkaMtbFileSenderTest.kt @@ -21,6 +21,7 @@ package dev.dnpm.etl.processor.output import com.fasterxml.jackson.databind.ObjectMapper import de.ukw.ccc.bwhc.dto.* +import dev.dnpm.etl.processor.PatientPseudonym import dev.dnpm.etl.processor.RequestId import dev.dnpm.etl.processor.config.KafkaProperties import dev.dnpm.etl.processor.monitoring.RequestStatus @@ -87,7 +88,7 @@ class KafkaMtbFileSenderTest { completedFuture(SendResult(null, null)) }.whenever(kafkaTemplate).send(anyString(), anyString(), anyString()) - val response = kafkaMtbFileSender.send(MtbFileSender.DeleteRequest(TEST_REQUEST_ID, "PID")) + val response = kafkaMtbFileSender.send(MtbFileSender.DeleteRequest(TEST_REQUEST_ID, TEST_PATIENT_PSEUDONYM)) assertThat(response.status).isEqualTo(testData.requestStatus) } @@ -113,7 +114,7 @@ class KafkaMtbFileSenderTest { completedFuture(SendResult(null, null)) }.whenever(kafkaTemplate).send(anyString(), anyString(), anyString()) - kafkaMtbFileSender.send(MtbFileSender.DeleteRequest(TEST_REQUEST_ID, "PID")) + kafkaMtbFileSender.send(MtbFileSender.DeleteRequest(TEST_REQUEST_ID, TEST_PATIENT_PSEUDONYM)) val captor = argumentCaptor() verify(kafkaTemplate, times(1)).send(anyString(), captor.capture(), captor.capture()) @@ -163,7 +164,7 @@ class KafkaMtbFileSenderTest { completedFuture(SendResult(null, null)) }.whenever(kafkaTemplate).send(anyString(), anyString(), anyString()) - kafkaMtbFileSender.send(MtbFileSender.DeleteRequest(TEST_REQUEST_ID, "PID")) + kafkaMtbFileSender.send(MtbFileSender.DeleteRequest(TEST_REQUEST_ID, TEST_PATIENT_PSEUDONYM)) val expectedCount = when (testData.exception) { // OK - No Retry @@ -177,6 +178,7 @@ class KafkaMtbFileSenderTest { companion object { val TEST_REQUEST_ID = RequestId("TestId") + val TEST_PATIENT_PSEUDONYM = PatientPseudonym("PID") fun mtbFile(consentStatus: Consent.Status): MtbFile { return if (consentStatus == Consent.Status.ACTIVE) { diff --git a/src/test/kotlin/dev/dnpm/etl/processor/output/RestMtbFileSenderTest.kt b/src/test/kotlin/dev/dnpm/etl/processor/output/RestMtbFileSenderTest.kt index 4f0eca8..9cc1437 100644 --- a/src/test/kotlin/dev/dnpm/etl/processor/output/RestMtbFileSenderTest.kt +++ b/src/test/kotlin/dev/dnpm/etl/processor/output/RestMtbFileSenderTest.kt @@ -20,6 +20,7 @@ package dev.dnpm.etl.processor.output 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.RequestStatus @@ -65,7 +66,7 @@ class RestMtbFileSenderTest { withStatus(requestWithResponse.httpStatus).body(requestWithResponse.body).createResponse(it) } - val response = restMtbFileSender.send(MtbFileSender.DeleteRequest(TEST_REQUEST_ID, "PID")) + val response = restMtbFileSender.send(MtbFileSender.DeleteRequest(TEST_REQUEST_ID, TEST_PATIENT_PSEUDONYM)) assertThat(response.status).isEqualTo(requestWithResponse.response.status) assertThat(response.body).isEqualTo(requestWithResponse.response.body) } @@ -138,7 +139,7 @@ class RestMtbFileSenderTest { withStatus(requestWithResponse.httpStatus).body(requestWithResponse.body).createResponse(it) } - val response = restMtbFileSender.send(MtbFileSender.DeleteRequest(TEST_REQUEST_ID, "PID")) + val response = restMtbFileSender.send(MtbFileSender.DeleteRequest(TEST_REQUEST_ID, TEST_PATIENT_PSEUDONYM)) assertThat(response.status).isEqualTo(requestWithResponse.response.status) assertThat(response.body).isEqualTo(requestWithResponse.response.body) } @@ -151,6 +152,7 @@ class RestMtbFileSenderTest { ) val TEST_REQUEST_ID = RequestId("TestId") + val TEST_PATIENT_PSEUDONYM = PatientPseudonym("PID") private val warningBody = """ { 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 d8c7813..fbc26ae 100644 --- a/src/test/kotlin/dev/dnpm/etl/processor/pseudonym/ExtensionsTest.kt +++ b/src/test/kotlin/dev/dnpm/etl/processor/pseudonym/ExtensionsTest.kt @@ -21,11 +21,11 @@ package dev.dnpm.etl.processor.pseudonym import com.fasterxml.jackson.databind.ObjectMapper import de.ukw.ccc.bwhc.dto.* +import dev.dnpm.etl.processor.anyValueClass import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows import org.junit.jupiter.api.extension.ExtendWith -import org.mockito.ArgumentMatchers import org.mockito.Mock import org.mockito.junit.jupiter.MockitoExtension import org.mockito.kotlin.doAnswer @@ -52,7 +52,7 @@ class ExtensionsTest { doAnswer { it.arguments[0] "PSEUDO-ID" - }.whenever(pseudonymizeService).patientPseudonym(ArgumentMatchers.anyString()) + }.whenever(pseudonymizeService).patientPseudonym(anyValueClass()) val mtbFile = fakeMtbFile() @@ -67,7 +67,7 @@ class ExtensionsTest { doAnswer { it.arguments[0] "PSEUDO-ID" - }.whenever(pseudonymizeService).patientPseudonym(ArgumentMatchers.anyString()) + }.whenever(pseudonymizeService).patientPseudonym(anyValueClass()) doAnswer { "TESTDOMAIN" @@ -95,7 +95,7 @@ class ExtensionsTest { doAnswer { it.arguments[0] "PSEUDO-ID" - }.whenever(pseudonymizeService).patientPseudonym(ArgumentMatchers.anyString()) + }.whenever(pseudonymizeService).patientPseudonym(anyValueClass()) doAnswer { "TESTDOMAIN" @@ -139,7 +139,7 @@ class ExtensionsTest { doAnswer { it.arguments[0] "PSEUDO-ID" - }.whenever(pseudonymizeService).patientPseudonym(ArgumentMatchers.anyString()) + }.whenever(pseudonymizeService).patientPseudonym(anyValueClass()) doAnswer { "TESTDOMAIN" 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 d7354be..1c58d5d 100644 --- a/src/test/kotlin/dev/dnpm/etl/processor/services/RequestProcessorTest.kt +++ b/src/test/kotlin/dev/dnpm/etl/processor/services/RequestProcessorTest.kt @@ -21,8 +21,7 @@ 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.randomRequestId +import dev.dnpm.etl.processor.* import dev.dnpm.etl.processor.config.AppConfigProperties import dev.dnpm.etl.processor.monitoring.Request import dev.dnpm.etl.processor.monitoring.RequestStatus @@ -34,7 +33,6 @@ import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith -import org.mockito.ArgumentMatchers.anyString import org.mockito.Mock import org.mockito.Mockito.* import org.mockito.junit.jupiter.MockitoExtension @@ -91,22 +89,22 @@ class RequestProcessorTest { Request( 1L, randomRequestId(), - "TEST_12345678901", - "P1", + PatientPseudonym("TEST_12345678901"), + PatientId("P1"), Fingerprint("zdlzv5s5ydmd4ktw2v5piohegc4jcyrm6j66bq6tv2uxuerndmga"), RequestType.MTB_FILE, RequestStatus.SUCCESS, Instant.parse("2023-08-08T02:00:00Z") ) - }.whenever(requestService).lastMtbFileRequestForPatientPseudonym(anyString()) + }.whenever(requestService).lastMtbFileRequestForPatientPseudonym(anyValueClass()) doAnswer { false - }.whenever(requestService).isLastRequestWithKnownStatusDeletion(anyString()) + }.whenever(requestService).isLastRequestWithKnownStatusDeletion(anyValueClass()) doAnswer { it.arguments[0] as String - }.whenever(pseudonymizeService).patientPseudonym(any()) + }.whenever(pseudonymizeService).patientPseudonym(anyValueClass()) doAnswer { it.arguments[0] @@ -150,22 +148,22 @@ class RequestProcessorTest { Request( 1L, randomRequestId(), - "TEST_12345678901", - "P1", + PatientPseudonym("TEST_12345678901"), + PatientId("P1"), Fingerprint("zdlzv5s5ydmd4ktw2v5piohegc4jcyrm6j66bq6tv2uxuerndmga"), RequestType.MTB_FILE, RequestStatus.SUCCESS, Instant.parse("2023-08-08T02:00:00Z") ) - }.whenever(requestService).lastMtbFileRequestForPatientPseudonym(anyString()) + }.whenever(requestService).lastMtbFileRequestForPatientPseudonym(anyValueClass()) doAnswer { false - }.whenever(requestService).isLastRequestWithKnownStatusDeletion(anyString()) + }.whenever(requestService).isLastRequestWithKnownStatusDeletion(anyValueClass()) doAnswer { it.arguments[0] as String - }.whenever(pseudonymizeService).patientPseudonym(any()) + }.whenever(pseudonymizeService).patientPseudonym(anyValueClass()) doAnswer { it.arguments[0] @@ -209,18 +207,18 @@ class RequestProcessorTest { Request( 1L, randomRequestId(), - "TEST_12345678901", - "P1", + PatientPseudonym("TEST_12345678901"), + PatientId("P1"), Fingerprint("different"), RequestType.MTB_FILE, RequestStatus.SUCCESS, Instant.parse("2023-08-08T02:00:00Z") ) - }.whenever(requestService).lastMtbFileRequestForPatientPseudonym(anyString()) + }.whenever(requestService).lastMtbFileRequestForPatientPseudonym(anyValueClass()) doAnswer { false - }.whenever(requestService).isLastRequestWithKnownStatusDeletion(anyString()) + }.whenever(requestService).isLastRequestWithKnownStatusDeletion(anyValueClass()) doAnswer { MtbFileSender.Response(status = RequestStatus.SUCCESS) @@ -228,7 +226,7 @@ class RequestProcessorTest { doAnswer { it.arguments[0] as String - }.whenever(pseudonymizeService).patientPseudonym(any()) + }.whenever(pseudonymizeService).patientPseudonym(anyValueClass()) doAnswer { it.arguments[0] @@ -272,18 +270,18 @@ class RequestProcessorTest { Request( 1L, randomRequestId(), - "TEST_12345678901", - "P1", + PatientPseudonym("TEST_12345678901"), + PatientId("P1"), Fingerprint("different"), RequestType.MTB_FILE, RequestStatus.SUCCESS, Instant.parse("2023-08-08T02:00:00Z") ) - }.whenever(requestService).lastMtbFileRequestForPatientPseudonym(anyString()) + }.whenever(requestService).lastMtbFileRequestForPatientPseudonym(anyValueClass()) doAnswer { false - }.whenever(requestService).isLastRequestWithKnownStatusDeletion(anyString()) + }.whenever(requestService).isLastRequestWithKnownStatusDeletion(anyValueClass()) doAnswer { MtbFileSender.Response(status = RequestStatus.ERROR) @@ -291,7 +289,7 @@ class RequestProcessorTest { doAnswer { it.arguments[0] as String - }.whenever(pseudonymizeService).patientPseudonym(any()) + }.whenever(pseudonymizeService).patientPseudonym(anyValueClass()) doAnswer { it.arguments[0] @@ -333,13 +331,13 @@ class RequestProcessorTest { fun testShouldSendDeleteRequestAndSaveUnknownRequestStatusAtFirst() { doAnswer { "PSEUDONYM" - }.whenever(pseudonymizeService).patientPseudonym(anyString()) + }.whenever(pseudonymizeService).patientPseudonym(anyValueClass()) doAnswer { MtbFileSender.Response(status = RequestStatus.UNKNOWN) }.whenever(sender).send(any()) - this.requestProcessor.processDeletion("TEST_12345678901") + this.requestProcessor.processDeletion(TEST_PATIENT_ID) val requestCaptor = argumentCaptor() verify(requestService, times(1)).save(requestCaptor.capture()) @@ -351,13 +349,13 @@ class RequestProcessorTest { fun testShouldSendDeleteRequestAndSendSuccessEvent() { doAnswer { "PSEUDONYM" - }.whenever(pseudonymizeService).patientPseudonym(anyString()) + }.whenever(pseudonymizeService).patientPseudonym(anyValueClass()) doAnswer { MtbFileSender.Response(status = RequestStatus.SUCCESS) }.whenever(sender).send(any()) - this.requestProcessor.processDeletion("TEST_12345678901") + this.requestProcessor.processDeletion(TEST_PATIENT_ID) val eventCaptor = argumentCaptor() verify(applicationEventPublisher, times(1)).publishEvent(eventCaptor.capture()) @@ -369,13 +367,13 @@ class RequestProcessorTest { fun testShouldSendDeleteRequestAndSendErrorEvent() { doAnswer { "PSEUDONYM" - }.whenever(pseudonymizeService).patientPseudonym(anyString()) + }.whenever(pseudonymizeService).patientPseudonym(anyValueClass()) doAnswer { MtbFileSender.Response(status = RequestStatus.ERROR) }.whenever(sender).send(any()) - this.requestProcessor.processDeletion("TEST_12345678901") + this.requestProcessor.processDeletion(TEST_PATIENT_ID) val eventCaptor = argumentCaptor() verify(applicationEventPublisher, times(1)).publishEvent(eventCaptor.capture()) @@ -385,9 +383,9 @@ class RequestProcessorTest { @Test fun testShouldSendDeleteRequestWithPseudonymErrorAndSaveErrorRequestStatus() { - doThrow(RuntimeException()).whenever(pseudonymizeService).patientPseudonym(anyString()) + doThrow(RuntimeException()).whenever(pseudonymizeService).patientPseudonym(anyValueClass()) - this.requestProcessor.processDeletion("TEST_12345678901") + this.requestProcessor.processDeletion(TEST_PATIENT_ID) val requestCaptor = argumentCaptor() verify(requestService, times(1)).save(requestCaptor.capture()) @@ -401,7 +399,7 @@ class RequestProcessorTest { doAnswer { it.arguments[0] as String - }.whenever(pseudonymizeService).patientPseudonym(any()) + }.whenever(pseudonymizeService).patientPseudonym(anyValueClass()) doAnswer { it.arguments[0] @@ -443,4 +441,8 @@ class RequestProcessorTest { assertThat(eventCaptor.firstValue.status).isEqualTo(RequestStatus.SUCCESS) } + companion object { + val TEST_PATIENT_ID = PatientId("TEST_12345678901") + } + } \ No newline at end of file diff --git a/src/test/kotlin/dev/dnpm/etl/processor/services/RequestServiceTest.kt b/src/test/kotlin/dev/dnpm/etl/processor/services/RequestServiceTest.kt index 93090ed..470c048 100644 --- a/src/test/kotlin/dev/dnpm/etl/processor/services/RequestServiceTest.kt +++ b/src/test/kotlin/dev/dnpm/etl/processor/services/RequestServiceTest.kt @@ -19,8 +19,7 @@ package dev.dnpm.etl.processor.services -import dev.dnpm.etl.processor.Fingerprint -import dev.dnpm.etl.processor.randomRequestId +import dev.dnpm.etl.processor.* import dev.dnpm.etl.processor.monitoring.Request import dev.dnpm.etl.processor.monitoring.RequestRepository import dev.dnpm.etl.processor.monitoring.RequestStatus @@ -45,8 +44,8 @@ class RequestServiceTest { private fun anyRequest() = any(Request::class.java) ?: Request( 0L, randomRequestId(), - "TEST_dummy", - "PX", + PatientPseudonym("TEST_dummy"), + PatientId("PX"), Fingerprint("dummy"), RequestType.MTB_FILE, RequestStatus.SUCCESS, @@ -67,8 +66,8 @@ class RequestServiceTest { Request( 1L, randomRequestId(), - "TEST_12345678901", - "P1", + PatientPseudonym("TEST_12345678901"), + PatientId("P1"), Fingerprint("0123456789abcdef1"), RequestType.MTB_FILE, RequestStatus.WARNING, @@ -77,8 +76,8 @@ class RequestServiceTest { Request( 2L, randomRequestId(), - "TEST_12345678901", - "P1", + PatientPseudonym("TEST_12345678901"), + PatientId("P1"), Fingerprint("0123456789abcdefd"), RequestType.DELETE, RequestStatus.WARNING, @@ -87,8 +86,8 @@ class RequestServiceTest { Request( 3L, randomRequestId(), - "TEST_12345678901", - "P1", + PatientPseudonym("TEST_12345678901"), + PatientId("P1"), Fingerprint("0123456789abcdef1"), RequestType.MTB_FILE, RequestStatus.UNKNOWN, @@ -107,8 +106,8 @@ class RequestServiceTest { Request( 1L, randomRequestId(), - "TEST_12345678901", - "P1", + PatientPseudonym("TEST_12345678901"), + PatientId("P1"), Fingerprint("0123456789abcdef1"), RequestType.MTB_FILE, RequestStatus.WARNING, @@ -117,8 +116,8 @@ class RequestServiceTest { Request( 2L, randomRequestId(), - "TEST_12345678901", - "P1", + PatientPseudonym("TEST_12345678901"), + PatientId("P1"), Fingerprint("0123456789abcdef1"), RequestType.MTB_FILE, RequestStatus.WARNING, @@ -127,8 +126,8 @@ class RequestServiceTest { Request( 3L, randomRequestId(), - "TEST_12345678901", - "P1", + PatientPseudonym("TEST_12345678901"), + PatientId("P1"), Fingerprint("0123456789abcdef1"), RequestType.MTB_FILE, RequestStatus.UNKNOWN, @@ -147,8 +146,8 @@ class RequestServiceTest { Request( 1L, randomRequestId(), - "TEST_12345678901", - "P1", + PatientPseudonym("TEST_12345678901"), + PatientId("P1"), Fingerprint("0123456789abcdef1"), RequestType.DELETE, RequestStatus.SUCCESS, @@ -157,8 +156,8 @@ class RequestServiceTest { Request( 1L, randomRequestId(), - "TEST_12345678902", - "P2", + PatientPseudonym("TEST_12345678902"), + PatientId("P2"), Fingerprint("0123456789abcdef2"), RequestType.MTB_FILE, RequestStatus.WARNING, @@ -190,8 +189,8 @@ class RequestServiceTest { val request = Request( randomRequestId(), - "TEST_12345678901", - "P1", + PatientPseudonym("TEST_12345678901"), + PatientId("P1"), Fingerprint("0123456789abcdef1"), RequestType.DELETE, RequestStatus.SUCCESS, @@ -205,23 +204,23 @@ class RequestServiceTest { @Test fun allRequestsByPatientPseudonymShouldRequestAllRequestsForPatientPseudonym() { - requestService.allRequestsByPatientPseudonym("TEST_12345678901") + requestService.allRequestsByPatientPseudonym(PatientPseudonym("TEST_12345678901")) - verify(requestRepository, times(1)).findAllByPatientIdOrderByProcessedAtDesc(anyString()) + verify(requestRepository, times(1)).findAllByPatientIdOrderByProcessedAtDesc(anyValueClass()) } @Test fun lastMtbFileRequestForPatientPseudonymShouldRequestAllRequestsForPatientPseudonym() { - requestService.lastMtbFileRequestForPatientPseudonym("TEST_12345678901") + requestService.lastMtbFileRequestForPatientPseudonym(PatientPseudonym("TEST_12345678901")) - verify(requestRepository, times(1)).findAllByPatientIdOrderByProcessedAtDesc(anyString()) + verify(requestRepository, times(1)).findAllByPatientIdOrderByProcessedAtDesc(anyValueClass()) } @Test fun isLastRequestDeletionShouldRequestAllRequestsForPatientPseudonym() { - requestService.isLastRequestWithKnownStatusDeletion("TEST_12345678901") + requestService.isLastRequestWithKnownStatusDeletion(PatientPseudonym("TEST_12345678901")) - verify(requestRepository, times(1)).findAllByPatientIdOrderByProcessedAtDesc(anyString()) + verify(requestRepository, times(1)).findAllByPatientIdOrderByProcessedAtDesc(anyValueClass()) } } \ No newline at end of file diff --git a/src/test/kotlin/dev/dnpm/etl/processor/services/ResponseProcessorTest.kt b/src/test/kotlin/dev/dnpm/etl/processor/services/ResponseProcessorTest.kt index 7204d7c..465d8b8 100644 --- a/src/test/kotlin/dev/dnpm/etl/processor/services/ResponseProcessorTest.kt +++ b/src/test/kotlin/dev/dnpm/etl/processor/services/ResponseProcessorTest.kt @@ -19,9 +19,7 @@ package dev.dnpm.etl.processor.services -import dev.dnpm.etl.processor.Fingerprint -import dev.dnpm.etl.processor.RequestId -import dev.dnpm.etl.processor.anyValueClass +import dev.dnpm.etl.processor.* import dev.dnpm.etl.processor.monitoring.Request import dev.dnpm.etl.processor.monitoring.RequestStatus import dev.dnpm.etl.processor.monitoring.RequestType @@ -49,8 +47,8 @@ class ResponseProcessorTest { private val testRequest = Request( 1L, RequestId("TestID1234"), - "PSEUDONYM-A", - "1", + PatientPseudonym("PSEUDONYM-A"), + PatientId("1"), Fingerprint("dummyfingerprint"), RequestType.MTB_FILE, RequestStatus.UNKNOWN